forked from kscience/visionforge
Fix editor glitches
This commit is contained in:
parent
484423a17a
commit
ca2b267fc4
@ -1,3 +1,6 @@
|
||||
import scientifik.useFx
|
||||
import scientifik.useSerialization
|
||||
|
||||
val dataforgeVersion by extra("0.1.8-dev-2")
|
||||
|
||||
plugins {
|
||||
@ -33,5 +36,5 @@ subprojects {
|
||||
apply(plugin = "scientifik.publish")
|
||||
}
|
||||
useSerialization()
|
||||
useFx(FXModule.CONTROLS, version = fxVersion)
|
||||
useFx(scientifik.FXModule.CONTROLS, version = fxVersion)
|
||||
}
|
@ -7,6 +7,7 @@ import hep.dataforge.vis.VisualGroup
|
||||
import hep.dataforge.vis.VisualObject
|
||||
import hep.dataforge.vis.bootstrap.*
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.flexColumn
|
||||
import hep.dataforge.vis.react.state
|
||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||
import hep.dataforge.vis.spatial.VisualObject3D
|
||||
@ -16,12 +17,18 @@ import hep.dataforge.vis.spatial.specifications.Canvas
|
||||
import hep.dataforge.vis.spatial.three.ThreeCanvas
|
||||
import hep.dataforge.vis.spatial.three.ThreeCanvasComponent
|
||||
import hep.dataforge.vis.spatial.three.canvasControls
|
||||
import kotlinx.css.FlexBasis
|
||||
import kotlinx.css.Overflow
|
||||
import kotlinx.css.flex
|
||||
import kotlinx.css.overflow
|
||||
import org.w3c.files.FileReader
|
||||
import org.w3c.files.get
|
||||
import react.RProps
|
||||
import react.dom.h1
|
||||
import scientifik.gdml.GDML
|
||||
import scientifik.gdml.parse
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
import kotlin.browser.window
|
||||
import kotlin.math.PI
|
||||
|
||||
@ -63,8 +70,16 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
}
|
||||
|
||||
flexColumn {
|
||||
css {
|
||||
flex(1.0, 1.0, FlexBasis.auto)
|
||||
}
|
||||
h1 { +"GDML/JSON loader demo" }
|
||||
gridRow {
|
||||
styledDiv {
|
||||
css {
|
||||
classes.add("row")
|
||||
classes.add("p-1")
|
||||
overflow = Overflow.auto
|
||||
}
|
||||
gridColumn(3) {
|
||||
card("Load data") {
|
||||
fileDrop("(drag file here)") { files ->
|
||||
@ -82,7 +97,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
}
|
||||
}
|
||||
//tree
|
||||
card("Object tree") {
|
||||
card("Object tree", "overflow-auto") {
|
||||
visual?.let {
|
||||
objectTree(it, selected, select)
|
||||
}
|
||||
@ -106,7 +121,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
}
|
||||
}
|
||||
gridColumn(3) {
|
||||
gridRow {
|
||||
container {
|
||||
//settings
|
||||
canvas?.let {
|
||||
card("Canvas configuration") {
|
||||
@ -114,10 +129,10 @@ val GDMLApp = component<GDMLAppProps> { props ->
|
||||
}
|
||||
}
|
||||
}
|
||||
gridRow {
|
||||
container {
|
||||
namecrumbs(selected, "World") { selected = it }
|
||||
}
|
||||
gridRow {
|
||||
container {
|
||||
//properties
|
||||
card("Properties") {
|
||||
selected.let { selected ->
|
||||
|
@ -8,7 +8,6 @@ import hep.dataforge.vis.spatial.gdml.GDMLTransformer
|
||||
import hep.dataforge.vis.spatial.gdml.LUnit
|
||||
import hep.dataforge.vis.spatial.gdml.toVisual
|
||||
import react.child
|
||||
import react.dom.div
|
||||
import react.dom.render
|
||||
import kotlin.browser.document
|
||||
|
||||
@ -47,7 +46,6 @@ private class GDMLDemoApp : Application {
|
||||
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
|
||||
|
||||
render(element) {
|
||||
div("h-100") {
|
||||
child(GDMLApp) {
|
||||
attrs {
|
||||
this.context = context
|
||||
@ -55,7 +53,6 @@ private class GDMLDemoApp : Application {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// (document.getElementById("file_load_button") as? HTMLInputElement)?.apply {
|
||||
// addEventListener("change", {
|
||||
// (it.target as HTMLInputElement).files?.asList()?.first()?.let { file ->
|
||||
|
@ -19,8 +19,8 @@ inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagCo
|
||||
}
|
||||
}
|
||||
|
||||
inline fun RBuilder.card(title: String, crossinline block: RBuilder.() -> Unit) {
|
||||
div("card w-100") {
|
||||
inline fun RBuilder.card(title: String, classes: String? = null, crossinline block: RBuilder.() -> Unit) {
|
||||
div("card w-100 $classes") {
|
||||
div("card-body") {
|
||||
h3(classes = "card-title") {
|
||||
+title
|
||||
@ -166,12 +166,6 @@ fun RBuilder.accordion(id: String, builder: RAccordionBuilder.() -> Unit): React
|
||||
|
||||
fun joinStyles(vararg styles: String?) = styles.joinToString(separator = " ") { it ?: "" }
|
||||
|
||||
inline fun RBuilder.flexColumn(classes: String? = null, block: RDOMBuilder<DIV>.() -> Unit) =
|
||||
div(joinStyles(classes, "d-flex flex-column"), block)
|
||||
|
||||
inline fun RBuilder.flexRow(classes: String? = null, block: RDOMBuilder<DIV>.() -> Unit) =
|
||||
div(joinStyles(classes, "d-flex flex-row"), block)
|
||||
|
||||
enum class ContainerSize(val suffix: String) {
|
||||
DEFAULT(""),
|
||||
SM("-sm"),
|
||||
|
@ -8,13 +8,17 @@ import hep.dataforge.names.plus
|
||||
import hep.dataforge.values.Value
|
||||
import hep.dataforge.vis.react.RFBuilder
|
||||
import hep.dataforge.vis.react.component
|
||||
import hep.dataforge.vis.react.flexRow
|
||||
import hep.dataforge.vis.react.state
|
||||
import kotlinx.css.*
|
||||
import kotlinx.html.classes
|
||||
import kotlinx.html.js.onClickFunction
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.events.Event
|
||||
import react.*
|
||||
import react.dom.*
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
interface ConfigEditorItemProps : RProps {
|
||||
|
||||
@ -132,9 +136,15 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
}
|
||||
}
|
||||
is MetaItem.ValueItem -> {
|
||||
div {
|
||||
div("row form-group") {
|
||||
div("col d-inline-flex") {
|
||||
flexRow {
|
||||
css {
|
||||
alignItems = Align.center
|
||||
justifyContent= JustifyContent.flexEnd
|
||||
}
|
||||
styledDiv {
|
||||
css{
|
||||
flexGrow = 1.0
|
||||
}
|
||||
span("tree-label align-self-center") {
|
||||
+token
|
||||
attrs {
|
||||
@ -144,7 +154,7 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
}
|
||||
}
|
||||
}
|
||||
div("col-6 d-inline-flex") {
|
||||
styledDiv {
|
||||
valueChooser(
|
||||
props.name,
|
||||
actualItem,
|
||||
@ -152,7 +162,10 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
valueChanged
|
||||
)
|
||||
}
|
||||
div("col-auto d-inline-flex p-1") {
|
||||
styledDiv {
|
||||
css {
|
||||
flexShrink = 1.0
|
||||
}
|
||||
button(classes = "btn btn-link align-self-center") {
|
||||
+"\u00D7"
|
||||
attrs {
|
||||
@ -168,7 +181,6 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ConfigEditorProps : RProps {
|
||||
var id: Name
|
||||
@ -176,6 +188,7 @@ interface ConfigEditorProps : RProps {
|
||||
var default: Meta?
|
||||
var descriptor: NodeDescriptor?
|
||||
}
|
||||
|
||||
val ConfigEditor = component<ConfigEditorProps> { props ->
|
||||
child(ConfigEditorItem) {
|
||||
attrs {
|
||||
@ -212,7 +225,12 @@ fun RBuilder.configEditor(config: Config, descriptor: NodeDescriptor? = null, de
|
||||
}
|
||||
}
|
||||
|
||||
fun RBuilder.configEditor(obj: Configurable, descriptor: NodeDescriptor? = obj.descriptor, default: Meta? = null, key: Any? = null) {
|
||||
fun RBuilder.configEditor(
|
||||
obj: Configurable,
|
||||
descriptor: NodeDescriptor? = obj.descriptor,
|
||||
default: Meta? = null,
|
||||
key: Any? = null
|
||||
) {
|
||||
child(ConfigEditor) {
|
||||
attrs {
|
||||
this.key = key?.toString() ?: ""
|
||||
|
@ -1,10 +1,7 @@
|
||||
package hep.dataforge.vis.bootstrap
|
||||
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.string
|
||||
import hep.dataforge.meta.value
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.values.*
|
||||
import hep.dataforge.vis.Colors
|
||||
@ -16,12 +13,8 @@ import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.HTMLSelectElement
|
||||
import org.w3c.dom.events.Event
|
||||
import org.w3c.dom.events.KeyboardEvent
|
||||
import react.*
|
||||
import react.dom.div
|
||||
import react.dom.input
|
||||
import react.dom.option
|
||||
import react.dom.select
|
||||
import react.dom.*
|
||||
|
||||
interface ValueChooserProps : RProps {
|
||||
var item: MetaItem<*>?
|
||||
@ -30,17 +23,12 @@ interface ValueChooserProps : RProps {
|
||||
}
|
||||
|
||||
interface ValueChooserState : RState {
|
||||
var value: Value?
|
||||
var rawInput: Boolean?
|
||||
}
|
||||
|
||||
class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserProps, ValueChooserState>(props) {
|
||||
private val element = createRef<HTMLElement>()
|
||||
|
||||
override fun ValueChooserState.init(props: ValueChooserProps) {
|
||||
value = props.item.value
|
||||
}
|
||||
|
||||
private fun getValue(): Value? {
|
||||
val element = element.current ?: return null//state.element ?: return null
|
||||
return when (element) {
|
||||
@ -54,24 +42,13 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
}
|
||||
}
|
||||
|
||||
private val valueChanged: (Event) -> Unit = { _ ->
|
||||
setState {
|
||||
value = getValue()
|
||||
}
|
||||
}
|
||||
|
||||
private val valueChangeAndCommit: (Event) -> Unit = { event ->
|
||||
val res = getValue()
|
||||
setState {
|
||||
value = res
|
||||
}
|
||||
props.valueChanged?.invoke(res)
|
||||
|
||||
private val commit: (Event) -> Unit = { event ->
|
||||
props.valueChanged?.invoke(getValue())
|
||||
}
|
||||
|
||||
private val keyDown: (Event) -> Unit = { event ->
|
||||
if (event is KeyboardEvent && event.key == "Enter") {
|
||||
props.valueChanged?.invoke(getValue())
|
||||
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
|
||||
commit(event)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,11 +60,11 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
override fun componentDidUpdate(prevProps: ValueChooserProps, prevState: ValueChooserState, snapshot: Any) {
|
||||
(element.current as? HTMLInputElement)?.let { element ->
|
||||
if (element.type == "checkbox") {
|
||||
element.checked = state.value?.boolean ?: false
|
||||
element.defaultChecked = props.item?.boolean ?: false
|
||||
} else {
|
||||
element.value = state.value?.string ?: ""
|
||||
element.defaultValue = props.item?.string ?: ""
|
||||
}
|
||||
element.indeterminate = state.value == null
|
||||
element.indeterminate = props.item == null
|
||||
}
|
||||
// (state.element as? HTMLSelectElement)?.let { element ->
|
||||
// state.value?.let { element.value = it.string }
|
||||
@ -96,8 +73,7 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
|
||||
private fun RBuilder.stringInput() = input(type = InputType.text) {
|
||||
attrs {
|
||||
this.value = state.value?.string ?: ""
|
||||
onChangeFunction = valueChanged
|
||||
this.defaultValue = props.item?.string ?: ""
|
||||
onKeyDownFunction = keyDown
|
||||
}
|
||||
ref = element
|
||||
@ -112,19 +88,19 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
descriptor?.widgetType == "color" -> input(type = InputType.color) {
|
||||
ref = element
|
||||
attrs {
|
||||
this.value = state.value?.let { value ->
|
||||
this.defaultValue = props.item?.value?.let { value ->
|
||||
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
||||
else value.string
|
||||
} ?: "#000000"
|
||||
onChangeFunction = valueChangeAndCommit
|
||||
onChangeFunction = commit
|
||||
}
|
||||
}
|
||||
type == ValueType.BOOLEAN -> {
|
||||
input(type = InputType.checkBox) {
|
||||
ref = element
|
||||
attrs {
|
||||
checked = state.value?.boolean ?: false
|
||||
onChangeFunction = valueChangeAndCommit
|
||||
defaultChecked = props.item?.boolean ?: false
|
||||
onChangeFunction = commit
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,8 +116,7 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
descriptor.attributes["max"].string?.let {
|
||||
max = it
|
||||
}
|
||||
this.value = state.value?.string ?: ""
|
||||
onChangeFunction = valueChanged
|
||||
defaultValue = props.item?.string ?: ""
|
||||
onKeyDownFunction = keyDown
|
||||
}
|
||||
}
|
||||
@ -153,9 +128,9 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
|
||||
}
|
||||
ref = element
|
||||
attrs {
|
||||
this.value = state.value?.string ?: ""
|
||||
this.value = props.item?.string ?: ""
|
||||
multiple = false
|
||||
onChangeFunction = valueChangeAndCommit
|
||||
onChangeFunction = commit
|
||||
}
|
||||
}
|
||||
else -> stringInput()
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*full height*/
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container-fluid { height: inherit; }
|
||||
|
||||
/* Remove default bullets */
|
||||
ul, .tree {
|
||||
list-style-type: none;
|
||||
|
29
ui/react/src/main/kotlin/hep/dataforge/vis/react/layout.kt
Normal file
29
ui/react/src/main/kotlin/hep/dataforge/vis/react/layout.kt
Normal file
@ -0,0 +1,29 @@
|
||||
package hep.dataforge.vis.react
|
||||
|
||||
import kotlinx.css.Display
|
||||
import kotlinx.css.FlexDirection
|
||||
import kotlinx.css.display
|
||||
import kotlinx.css.flexDirection
|
||||
import kotlinx.html.DIV
|
||||
import react.RBuilder
|
||||
import styled.StyledDOMBuilder
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
inline fun RBuilder.flexColumn(block: StyledDOMBuilder<DIV>.() -> Unit) =
|
||||
styledDiv {
|
||||
css {
|
||||
display = Display.flex
|
||||
flexDirection = FlexDirection.column
|
||||
}
|
||||
block()
|
||||
}
|
||||
|
||||
inline fun RBuilder.flexRow(block: StyledDOMBuilder<DIV>.() -> Unit) =
|
||||
styledDiv {
|
||||
css {
|
||||
display = Display.flex
|
||||
flexDirection = FlexDirection.row
|
||||
}
|
||||
block()
|
||||
}
|
Loading…
Reference in New Issue
Block a user