From ca2b267fc48bf9bdaf16fc514951f54dff958f5f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 16 May 2020 22:24:29 +0300 Subject: [PATCH] Fix editor glitches --- build.gradle.kts | 5 +- .../vis/spatial/gdml/demo/GDMLAppComponent.kt | 25 +++++-- .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 11 ++- .../hep/dataforge/vis/bootstrap/bootstrap.kt | 10 +-- .../dataforge/vis/bootstrap/configEditor.kt | 70 ++++++++++++------- .../dataforge/vis/bootstrap/valueChooser.kt | 59 +++++----------- ui/bootstrap/src/main/resources/css/main.css | 8 +++ .../kotlin/hep/dataforge/vis/react/layout.kt | 29 ++++++++ 8 files changed, 128 insertions(+), 89 deletions(-) create mode 100644 ui/react/src/main/kotlin/hep/dataforge/vis/react/layout.kt diff --git a/build.gradle.kts b/build.gradle.kts index 95821d28..eb3dc641 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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) } \ No newline at end of file diff --git a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLAppComponent.kt index 6f3cae91..e929ce29 100644 --- a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLAppComponent.kt @@ -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 { 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 { props -> } } //tree - card("Object tree") { + card("Object tree", "overflow-auto") { visual?.let { objectTree(it, selected, select) } @@ -106,7 +121,7 @@ val GDMLApp = component { props -> } } gridColumn(3) { - gridRow { + container { //settings canvas?.let { card("Canvas configuration") { @@ -114,10 +129,10 @@ val GDMLApp = component { props -> } } } - gridRow { + container { namecrumbs(selected, "World") { selected = it } } - gridRow { + container { //properties card("Properties") { selected.let { selected -> diff --git a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index 3c969d00..613a98ed 100644 --- a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -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,12 +46,10 @@ 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 - this.rootObject = cubes().toVisual(gdmlConfiguration) - } + child(GDMLApp) { + attrs { + this.context = context + this.rootObject = cubes().toVisual(gdmlConfiguration) } } } diff --git a/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/bootstrap.kt b/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/bootstrap.kt index 4a0d5a42..3eaa8c3e 100644 --- a/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/bootstrap.kt +++ b/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/bootstrap.kt @@ -19,8 +19,8 @@ inline fun TagConsumer.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
.() -> Unit) = - div(joinStyles(classes, "d-flex flex-column"), block) - -inline fun RBuilder.flexRow(classes: String? = null, block: RDOMBuilder
.() -> Unit) = - div(joinStyles(classes, "d-flex flex-row"), block) - enum class ContainerSize(val suffix: String) { DEFAULT(""), SM("-sm"), diff --git a/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/configEditor.kt b/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/configEditor.kt index ccbf69df..f92e4e87 100644 --- a/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/configEditor.kt +++ b/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/configEditor.kt @@ -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,35 +136,43 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) { } } is MetaItem.ValueItem -> { - div { - div("row form-group") { - div("col d-inline-flex") { - span("tree-label align-self-center") { - +token - attrs { - if (item == null) { - classes += "tree-label-inactive" - } + flexRow { + css { + alignItems = Align.center + justifyContent= JustifyContent.flexEnd + } + styledDiv { + css{ + flexGrow = 1.0 + } + span("tree-label align-self-center") { + +token + attrs { + if (item == null) { + classes += "tree-label-inactive" } } } - div("col-6 d-inline-flex") { - valueChooser( - props.name, - actualItem, - descriptorItem as? ValueDescriptor, - valueChanged - ) + } + styledDiv { + valueChooser( + props.name, + actualItem, + descriptorItem as? ValueDescriptor, + valueChanged + ) + } + styledDiv { + css { + flexShrink = 1.0 } - div("col-auto d-inline-flex p-1") { - button(classes = "btn btn-link align-self-center") { - +"\u00D7" - attrs { - if (item == null) { - disabled = true - } else { - onClickFunction = removeClick - } + button(classes = "btn btn-link align-self-center") { + +"\u00D7" + attrs { + if (item == null) { + disabled = true + } else { + onClickFunction = removeClick } } } @@ -176,6 +188,7 @@ interface ConfigEditorProps : RProps { var default: Meta? var descriptor: NodeDescriptor? } + val ConfigEditor = component { 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() ?: "" diff --git a/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/valueChooser.kt b/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/valueChooser.kt index d49cd552..1874350c 100644 --- a/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/valueChooser.kt +++ b/ui/bootstrap/src/main/kotlin/hep/dataforge/vis/bootstrap/valueChooser.kt @@ -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(props) { private val element = createRef() - 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 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 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 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 stringInput() diff --git a/ui/bootstrap/src/main/resources/css/main.css b/ui/bootstrap/src/main/resources/css/main.css index d77f3a30..ecb7ee5f 100644 --- a/ui/bootstrap/src/main/resources/css/main.css +++ b/ui/bootstrap/src/main/resources/css/main.css @@ -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; diff --git a/ui/react/src/main/kotlin/hep/dataforge/vis/react/layout.kt b/ui/react/src/main/kotlin/hep/dataforge/vis/react/layout.kt new file mode 100644 index 00000000..b911633c --- /dev/null +++ b/ui/react/src/main/kotlin/hep/dataforge/vis/react/layout.kt @@ -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
.() -> Unit) = + styledDiv { + css { + display = Display.flex + flexDirection = FlexDirection.column + } + block() + } + +inline fun RBuilder.flexRow(block: StyledDOMBuilder
.() -> Unit) = + styledDiv { + css { + display = Display.flex + flexDirection = FlexDirection.row + } + block() + } \ No newline at end of file