Fix editor glitches

This commit is contained in:
Alexander Nozik 2020-05-16 22:24:29 +03:00
parent 484423a17a
commit ca2b267fc4
8 changed files with 128 additions and 89 deletions

View File

@ -1,3 +1,6 @@
import scientifik.useFx
import scientifik.useSerialization
val dataforgeVersion by extra("0.1.8-dev-2") val dataforgeVersion by extra("0.1.8-dev-2")
plugins { plugins {
@ -33,5 +36,5 @@ subprojects {
apply(plugin = "scientifik.publish") apply(plugin = "scientifik.publish")
} }
useSerialization() useSerialization()
useFx(FXModule.CONTROLS, version = fxVersion) useFx(scientifik.FXModule.CONTROLS, version = fxVersion)
} }

View File

@ -7,6 +7,7 @@ import hep.dataforge.vis.VisualGroup
import hep.dataforge.vis.VisualObject import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.bootstrap.* import hep.dataforge.vis.bootstrap.*
import hep.dataforge.vis.react.component import hep.dataforge.vis.react.component
import hep.dataforge.vis.react.flexColumn
import hep.dataforge.vis.react.state import hep.dataforge.vis.react.state
import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D 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.ThreeCanvas
import hep.dataforge.vis.spatial.three.ThreeCanvasComponent import hep.dataforge.vis.spatial.three.ThreeCanvasComponent
import hep.dataforge.vis.spatial.three.canvasControls 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.FileReader
import org.w3c.files.get import org.w3c.files.get
import react.RProps import react.RProps
import react.dom.h1 import react.dom.h1
import scientifik.gdml.GDML import scientifik.gdml.GDML
import scientifik.gdml.parse import scientifik.gdml.parse
import styled.css
import styled.styledDiv
import kotlin.browser.window import kotlin.browser.window
import kotlin.math.PI import kotlin.math.PI
@ -63,8 +70,16 @@ val GDMLApp = component<GDMLAppProps> { props ->
} }
flexColumn { flexColumn {
css {
flex(1.0, 1.0, FlexBasis.auto)
}
h1 { +"GDML/JSON loader demo" } h1 { +"GDML/JSON loader demo" }
gridRow { styledDiv {
css {
classes.add("row")
classes.add("p-1")
overflow = Overflow.auto
}
gridColumn(3) { gridColumn(3) {
card("Load data") { card("Load data") {
fileDrop("(drag file here)") { files -> fileDrop("(drag file here)") { files ->
@ -82,7 +97,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
} }
} }
//tree //tree
card("Object tree") { card("Object tree", "overflow-auto") {
visual?.let { visual?.let {
objectTree(it, selected, select) objectTree(it, selected, select)
} }
@ -106,7 +121,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
} }
} }
gridColumn(3) { gridColumn(3) {
gridRow { container {
//settings //settings
canvas?.let { canvas?.let {
card("Canvas configuration") { card("Canvas configuration") {
@ -114,10 +129,10 @@ val GDMLApp = component<GDMLAppProps> { props ->
} }
} }
} }
gridRow { container {
namecrumbs(selected, "World") { selected = it } namecrumbs(selected, "World") { selected = it }
} }
gridRow { container {
//properties //properties
card("Properties") { card("Properties") {
selected.let { selected -> selected.let { selected ->

View File

@ -8,7 +8,6 @@ import hep.dataforge.vis.spatial.gdml.GDMLTransformer
import hep.dataforge.vis.spatial.gdml.LUnit import hep.dataforge.vis.spatial.gdml.LUnit
import hep.dataforge.vis.spatial.gdml.toVisual import hep.dataforge.vis.spatial.gdml.toVisual
import react.child import react.child
import react.dom.div
import react.dom.render import react.dom.render
import kotlin.browser.document 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") val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
render(element) { render(element) {
div("h-100") {
child(GDMLApp) { child(GDMLApp) {
attrs { attrs {
this.context = context this.context = context
@ -55,7 +53,6 @@ private class GDMLDemoApp : Application {
} }
} }
} }
}
// (document.getElementById("file_load_button") as? HTMLInputElement)?.apply { // (document.getElementById("file_load_button") as? HTMLInputElement)?.apply {
// addEventListener("change", { // addEventListener("change", {
// (it.target as HTMLInputElement).files?.asList()?.first()?.let { file -> // (it.target as HTMLInputElement).files?.asList()?.first()?.let { file ->

View 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) { inline fun RBuilder.card(title: String, classes: String? = null, crossinline block: RBuilder.() -> Unit) {
div("card w-100") { div("card w-100 $classes") {
div("card-body") { div("card-body") {
h3(classes = "card-title") { h3(classes = "card-title") {
+title +title
@ -166,12 +166,6 @@ fun RBuilder.accordion(id: String, builder: RAccordionBuilder.() -> Unit): React
fun joinStyles(vararg styles: String?) = styles.joinToString(separator = " ") { it ?: "" } 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) { enum class ContainerSize(val suffix: String) {
DEFAULT(""), DEFAULT(""),
SM("-sm"), SM("-sm"),

View File

@ -8,13 +8,17 @@ import hep.dataforge.names.plus
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.vis.react.RFBuilder import hep.dataforge.vis.react.RFBuilder
import hep.dataforge.vis.react.component import hep.dataforge.vis.react.component
import hep.dataforge.vis.react.flexRow
import hep.dataforge.vis.react.state import hep.dataforge.vis.react.state
import kotlinx.css.*
import kotlinx.html.classes import kotlinx.html.classes
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.events.Event import org.w3c.dom.events.Event
import react.* import react.*
import react.dom.* import react.dom.*
import styled.css
import styled.styledDiv
interface ConfigEditorItemProps : RProps { interface ConfigEditorItemProps : RProps {
@ -132,9 +136,15 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
} }
} }
is MetaItem.ValueItem -> { is MetaItem.ValueItem -> {
div { flexRow {
div("row form-group") { css {
div("col d-inline-flex") { alignItems = Align.center
justifyContent= JustifyContent.flexEnd
}
styledDiv {
css{
flexGrow = 1.0
}
span("tree-label align-self-center") { span("tree-label align-self-center") {
+token +token
attrs { attrs {
@ -144,7 +154,7 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
} }
} }
} }
div("col-6 d-inline-flex") { styledDiv {
valueChooser( valueChooser(
props.name, props.name,
actualItem, actualItem,
@ -152,7 +162,10 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
valueChanged valueChanged
) )
} }
div("col-auto d-inline-flex p-1") { styledDiv {
css {
flexShrink = 1.0
}
button(classes = "btn btn-link align-self-center") { button(classes = "btn btn-link align-self-center") {
+"\u00D7" +"\u00D7"
attrs { attrs {
@ -168,7 +181,6 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
} }
} }
} }
}
interface ConfigEditorProps : RProps { interface ConfigEditorProps : RProps {
var id: Name var id: Name
@ -176,6 +188,7 @@ interface ConfigEditorProps : RProps {
var default: Meta? var default: Meta?
var descriptor: NodeDescriptor? var descriptor: NodeDescriptor?
} }
val ConfigEditor = component<ConfigEditorProps> { props -> val ConfigEditor = component<ConfigEditorProps> { props ->
child(ConfigEditorItem) { child(ConfigEditorItem) {
attrs { 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) { child(ConfigEditor) {
attrs { attrs {
this.key = key?.toString() ?: "" this.key = key?.toString() ?: ""

View File

@ -1,10 +1,7 @@
package hep.dataforge.vis.bootstrap package hep.dataforge.vis.bootstrap
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.ValueDescriptor 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.names.Name
import hep.dataforge.values.* import hep.dataforge.values.*
import hep.dataforge.vis.Colors import hep.dataforge.vis.Colors
@ -16,12 +13,8 @@ import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.events.Event import org.w3c.dom.events.Event
import org.w3c.dom.events.KeyboardEvent
import react.* import react.*
import react.dom.div import react.dom.*
import react.dom.input
import react.dom.option
import react.dom.select
interface ValueChooserProps : RProps { interface ValueChooserProps : RProps {
var item: MetaItem<*>? var item: MetaItem<*>?
@ -30,17 +23,12 @@ interface ValueChooserProps : RProps {
} }
interface ValueChooserState : RState { interface ValueChooserState : RState {
var value: Value?
var rawInput: Boolean? var rawInput: Boolean?
} }
class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserProps, ValueChooserState>(props) { class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserProps, ValueChooserState>(props) {
private val element = createRef<HTMLElement>() private val element = createRef<HTMLElement>()
override fun ValueChooserState.init(props: ValueChooserProps) {
value = props.item.value
}
private fun getValue(): Value? { private fun getValue(): Value? {
val element = element.current ?: return null//state.element ?: return null val element = element.current ?: return null//state.element ?: return null
return when (element) { return when (element) {
@ -54,24 +42,13 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
} }
} }
private val valueChanged: (Event) -> Unit = { _ -> private val commit: (Event) -> Unit = { event ->
setState { props.valueChanged?.invoke(getValue())
value = getValue()
}
}
private val valueChangeAndCommit: (Event) -> Unit = { event ->
val res = getValue()
setState {
value = res
}
props.valueChanged?.invoke(res)
} }
private val keyDown: (Event) -> Unit = { event -> private val keyDown: (Event) -> Unit = { event ->
if (event is KeyboardEvent && event.key == "Enter") { if (event.type == "keydown" && event.asDynamic().key == "Enter") {
props.valueChanged?.invoke(getValue()) commit(event)
} }
} }
@ -83,11 +60,11 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
override fun componentDidUpdate(prevProps: ValueChooserProps, prevState: ValueChooserState, snapshot: Any) { override fun componentDidUpdate(prevProps: ValueChooserProps, prevState: ValueChooserState, snapshot: Any) {
(element.current as? HTMLInputElement)?.let { element -> (element.current as? HTMLInputElement)?.let { element ->
if (element.type == "checkbox") { if (element.type == "checkbox") {
element.checked = state.value?.boolean ?: false element.defaultChecked = props.item?.boolean ?: false
} else { } 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.element as? HTMLSelectElement)?.let { element ->
// state.value?.let { element.value = it.string } // 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) { private fun RBuilder.stringInput() = input(type = InputType.text) {
attrs { attrs {
this.value = state.value?.string ?: "" this.defaultValue = props.item?.string ?: ""
onChangeFunction = valueChanged
onKeyDownFunction = keyDown onKeyDownFunction = keyDown
} }
ref = element ref = element
@ -112,19 +88,19 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
descriptor?.widgetType == "color" -> input(type = InputType.color) { descriptor?.widgetType == "color" -> input(type = InputType.color) {
ref = element ref = element
attrs { attrs {
this.value = state.value?.let { value -> this.defaultValue = props.item?.value?.let { value ->
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int) if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
else value.string else value.string
} ?: "#000000" } ?: "#000000"
onChangeFunction = valueChangeAndCommit onChangeFunction = commit
} }
} }
type == ValueType.BOOLEAN -> { type == ValueType.BOOLEAN -> {
input(type = InputType.checkBox) { input(type = InputType.checkBox) {
ref = element ref = element
attrs { attrs {
checked = state.value?.boolean ?: false defaultChecked = props.item?.boolean ?: false
onChangeFunction = valueChangeAndCommit onChangeFunction = commit
} }
} }
} }
@ -140,8 +116,7 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
descriptor.attributes["max"].string?.let { descriptor.attributes["max"].string?.let {
max = it max = it
} }
this.value = state.value?.string ?: "" defaultValue = props.item?.string ?: ""
onChangeFunction = valueChanged
onKeyDownFunction = keyDown onKeyDownFunction = keyDown
} }
} }
@ -153,9 +128,9 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
} }
ref = element ref = element
attrs { attrs {
this.value = state.value?.string ?: "" this.value = props.item?.string ?: ""
multiple = false multiple = false
onChangeFunction = valueChangeAndCommit onChangeFunction = commit
} }
} }
else -> stringInput() else -> stringInput()

View File

@ -1,3 +1,11 @@
/*full height*/
html, body {
height: 100%;
width: 100%;
}
.container-fluid { height: inherit; }
/* Remove default bullets */ /* Remove default bullets */
ul, .tree { ul, .tree {
list-style-type: none; list-style-type: none;

View 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()
}