Design update for gdml demo

This commit is contained in:
Alexander Nozik 2020-05-17 19:00:14 +03:00
parent ca2b267fc4
commit f484d5d1ff
24 changed files with 250 additions and 440 deletions

View File

@ -31,21 +31,13 @@ kotlin {
jsMain { jsMain {
dependencies { dependencies {
api("hep.dataforge:dataforge-output-html:$dataforgeVersion") api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72")
api("org.jetbrains:kotlin-react-dom:16.13.1-pre.104-kotlin-1.3.72")
api("org.jetbrains.kotlinx:kotlinx-html:0.6.12") api("org.jetbrains.kotlinx:kotlinx-html:0.6.12")
api("org.jetbrains:kotlin-extensions:1.0.1-pre.104-kotlin-1.3.72") //api("org.jetbrains:kotlin-extensions:1.0.1-pre.105-kotlin-1.3.72")
api("org.jetbrains:kotlin-css-js:1.0.0-pre.94-kotlin-1.3.70") //api("org.jetbrains:kotlin-css-js:1.0.0-pre.105-kotlin-1.3.72")
api("org.jetbrains:kotlin-styled:1.0.0-pre.104-kotlin-1.3.72") api("org.jetbrains:kotlin-styled:1.0.0-pre.104-kotlin-1.3.72")
api(npm("core-js", "2.6.5")) api(npm("core-js", "2.6.5"))
api(npm("react", "16.13.1"))
api(npm("react-dom", "16.13.1"))
api(npm("react-is", "16.13.0"))
api(npm("inline-style-prefixer", "5.1.0")) api(npm("inline-style-prefixer", "5.1.0"))
api(npm("styled-components", "4.3.2")) api(npm("styled-components", "4.3.2"))
//api(project(":ringui-wrapper")) //api(project(":ringui-wrapper"))

View File

@ -2,9 +2,12 @@ package hep.dataforge.vis
import hep.dataforge.meta.Laminate import hep.dataforge.meta.Laminate
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.node import hep.dataforge.meta.node
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty import hep.dataforge.names.isEmpty
import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue
/** /**
* Return nearest selectable parent [Name] * Return nearest selectable parent [Name]
@ -21,7 +24,7 @@ tailrec fun Name.selectable(): Name? = when {
} }
} }
fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>?{ fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
return when (val first = filterNotNull().firstOrNull()) { return when (val first = filterNotNull().firstOrNull()) {
null -> null null -> null
is MetaItem.ValueItem -> first //fast search for first entry if it is value is MetaItem.ValueItem -> first //fast search for first entry if it is value
@ -31,4 +34,12 @@ fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>?{
MetaItem.NodeItem(laminate) MetaItem.NodeItem(laminate)
} }
} }
}
inline fun <reified E : Enum<E>> NodeDescriptor.enum(key: Name, default: E?) = value(key) {
type(ValueType.STRING)
default?.let {
default(default)
}
allowedValues = enumValues<E>().map{it.asValue()}
} }

View File

@ -69,13 +69,13 @@ class Visual3D(meta: Meta) : AbstractPlugin(meta) {
internal fun VisualObject3D.update(meta: Meta) { internal fun VisualObject3D.update(meta: Meta) {
fun Meta.toVector(default: Float = 0f) = Point3D( fun Meta.toVector(default: Float = 0f) = Point3D(
this[VisualObject3D.x].float ?: default, this[VisualObject3D.X_KEY].float ?: default,
this[VisualObject3D.y].float ?: default, this[VisualObject3D.Y_KEY].float ?: default,
this[VisualObject3D.z].float ?: default this[VisualObject3D.Z_KEY].float ?: default
) )
meta[VisualObject3D.position].node?.toVector()?.let { position = it } meta[VisualObject3D.POSITION_KEY].node?.toVector()?.let { position = it }
meta[VisualObject3D.rotation].node?.toVector()?.let { rotation = it } meta[VisualObject3D.ROTATION].node?.toVector()?.let { rotation = it }
meta[VisualObject3D.scale].node?.toVector(1f)?.let { scale = it } meta[VisualObject3D.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
meta["properties"].node?.let { configure(it) } meta["properties"].node?.let { configure(it) }
} }

View File

@ -10,6 +10,7 @@ import hep.dataforge.output.Renderer
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.vis.VisualObject import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.enum
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
@ -37,29 +38,29 @@ interface VisualObject3D : VisualObject {
val GEOMETRY_KEY = "geometry".asName() val GEOMETRY_KEY = "geometry".asName()
val x = "x".asName() val X_KEY = "x".asName()
val y = "y".asName() val Y_KEY = "y".asName()
val z = "z".asName() val Z_KEY = "z".asName()
val position = "pos".asName() val POSITION_KEY = "pos".asName()
val xPos = position + x val X_POSITION_KEY = POSITION_KEY + X_KEY
val yPos = position + y val Y_POSITION_KEY = POSITION_KEY + Y_KEY
val zPos = position + z val Z_POSITION_KEY = POSITION_KEY + Z_KEY
val rotation = "rotation".asName() val ROTATION = "rotation".asName()
val xRotation = rotation + x val X_ROTATION_KEY = ROTATION + X_KEY
val yRotation = rotation + y val Y_ROTATION_KEY = ROTATION + Y_KEY
val zRotation = rotation + z val Z_ROTATION_KEY = ROTATION + Z_KEY
val rotationOrder = rotation + "order" val ROTATION_ORDER_KEY = ROTATION + "order"
val scale = "scale".asName() val SCALE_KEY = "scale".asName()
val xScale = scale + x val X_SCALE_KEY = SCALE_KEY + X_KEY
val yScale = scale + y val Y_SCALE_KEY = SCALE_KEY + Y_KEY
val zScale = scale + z val Z_SCALE_KEY = SCALE_KEY + Z_KEY
val descriptor by lazy { val descriptor by lazy {
NodeDescriptor { NodeDescriptor {
@ -69,12 +70,14 @@ interface VisualObject3D : VisualObject {
} }
//TODO replace by descriptor merge //TODO replace by descriptor merge
value(VisualObject.STYLE_KEY){ value(VisualObject.STYLE_KEY) {
type(ValueType.STRING) type(ValueType.STRING)
multiple = true multiple = true
} }
item(Material3D.MATERIAL_KEY.toString(), Material3D.descriptor) item(Material3D.MATERIAL_KEY.toString(), Material3D.descriptor)
enum<RotationOrder>(ROTATION_ORDER_KEY,default = RotationOrder.XYZ)
} }
} }
} }
@ -107,8 +110,8 @@ enum class RotationOrder {
* Rotation order * Rotation order
*/ */
var VisualObject3D.rotationOrder: RotationOrder var VisualObject3D.rotationOrder: RotationOrder
get() = getProperty(VisualObject3D.rotationOrder).enum<RotationOrder>() ?: RotationOrder.XYZ get() = getProperty(VisualObject3D.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
set(value) = setProperty(VisualObject3D.rotationOrder, value.name.asValue()) set(value) = setProperty(VisualObject3D.ROTATION_ORDER_KEY, value.name.asValue())
/** /**
@ -141,21 +144,21 @@ var VisualObject3D.x: Number
get() = position?.x ?: 0f get() = position?.x ?: 0f
set(value) { set(value) {
position().x = value.toDouble() position().x = value.toDouble()
propertyInvalidated(VisualObject3D.xPos) propertyInvalidated(VisualObject3D.X_POSITION_KEY)
} }
var VisualObject3D.y: Number var VisualObject3D.y: Number
get() = position?.y ?: 0f get() = position?.y ?: 0f
set(value) { set(value) {
position().y = value.toDouble() position().y = value.toDouble()
propertyInvalidated(VisualObject3D.yPos) propertyInvalidated(VisualObject3D.Y_POSITION_KEY)
} }
var VisualObject3D.z: Number var VisualObject3D.z: Number
get() = position?.z ?: 0f get() = position?.z ?: 0f
set(value) { set(value) {
position().z = value.toDouble() position().z = value.toDouble()
propertyInvalidated(VisualObject3D.zPos) propertyInvalidated(VisualObject3D.Z_POSITION_KEY)
} }
private fun VisualObject3D.rotation(): Point3D = private fun VisualObject3D.rotation(): Point3D =
@ -165,21 +168,21 @@ var VisualObject3D.rotationX: Number
get() = rotation?.x ?: 0f get() = rotation?.x ?: 0f
set(value) { set(value) {
rotation().x = value.toDouble() rotation().x = value.toDouble()
propertyInvalidated(VisualObject3D.xRotation) propertyInvalidated(VisualObject3D.X_ROTATION_KEY)
} }
var VisualObject3D.rotationY: Number var VisualObject3D.rotationY: Number
get() = rotation?.y ?: 0f get() = rotation?.y ?: 0f
set(value) { set(value) {
rotation().y = value.toDouble() rotation().y = value.toDouble()
propertyInvalidated(VisualObject3D.yRotation) propertyInvalidated(VisualObject3D.Y_ROTATION_KEY)
} }
var VisualObject3D.rotationZ: Number var VisualObject3D.rotationZ: Number
get() = rotation?.z ?: 0f get() = rotation?.z ?: 0f
set(value) { set(value) {
rotation().z = value.toDouble() rotation().z = value.toDouble()
propertyInvalidated(VisualObject3D.zRotation) propertyInvalidated(VisualObject3D.Z_ROTATION_KEY)
} }
private fun VisualObject3D.scale(): Point3D = private fun VisualObject3D.scale(): Point3D =
@ -189,19 +192,19 @@ var VisualObject3D.scaleX: Number
get() = scale?.x ?: 1f get() = scale?.x ?: 1f
set(value) { set(value) {
scale().x = value.toDouble() scale().x = value.toDouble()
propertyInvalidated(VisualObject3D.xScale) propertyInvalidated(VisualObject3D.X_SCALE_KEY)
} }
var VisualObject3D.scaleY: Number var VisualObject3D.scaleY: Number
get() = scale?.y ?: 1f get() = scale?.y ?: 1f
set(value) { set(value) {
scale().y = value.toDouble() scale().y = value.toDouble()
propertyInvalidated(VisualObject3D.yScale) propertyInvalidated(VisualObject3D.Y_SCALE_KEY)
} }
var VisualObject3D.scaleZ: Number var VisualObject3D.scaleZ: Number
get() = scale?.z ?: 1f get() = scale?.z ?: 1f
set(value) { set(value) {
scale().z = value.toDouble() scale().z = value.toDouble()
propertyInvalidated(VisualObject3D.zScale) propertyInvalidated(VisualObject3D.Z_SCALE_KEY)
} }

View File

@ -21,8 +21,8 @@ operator fun Point2D.component1() = x
operator fun Point2D.component2() = y operator fun Point2D.component2() = y
fun Point2D.toMeta() = Meta { fun Point2D.toMeta() = Meta {
VisualObject3D.x put x VisualObject3D.X_KEY put x
VisualObject3D.y put y VisualObject3D.Y_KEY put y
} }
fun Meta.point2D() = Point2D(this["x"].number ?: 0, this["y"].number ?: 0) fun Meta.point2D() = Point2D(this["x"].number ?: 0, this["y"].number ?: 0)
@ -42,7 +42,7 @@ operator fun Point3D.component3() = z
fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0) fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0)
fun Point3D.toMeta() = Meta { fun Point3D.toMeta() = Meta {
VisualObject3D.x put x VisualObject3D.X_KEY put x
VisualObject3D.y put y VisualObject3D.Y_KEY put y
VisualObject3D.z put z VisualObject3D.Z_KEY put z
} }

View File

@ -7,6 +7,7 @@ import hep.dataforge.vis.useStyle
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@Suppress("UNUSED_VARIABLE")
class PropertyTest { class PropertyTest {
@Test @Test
fun testInheritedProperty() { fun testInheritedProperty() {

View File

@ -60,9 +60,9 @@ fun Object3D.updateProperty(source: VisualObject, propertyName: Name) {
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
this.material = getMaterial(source) this.material = getMaterial(source)
} else if ( } else if (
propertyName.startsWith(VisualObject3D.position) propertyName.startsWith(VisualObject3D.POSITION_KEY)
|| propertyName.startsWith(VisualObject3D.rotation) || propertyName.startsWith(VisualObject3D.ROTATION)
|| propertyName.startsWith(VisualObject3D.scale) || propertyName.startsWith(VisualObject3D.SCALE_KEY)
) { ) {
//update position of mesh using this object //update position of mesh using this object
updatePosition(source) updatePosition(source)

View File

@ -57,9 +57,9 @@ class ThreePlugin : AbstractPlugin() {
obj.onPropertyChange(this) { name, _, _ -> obj.onPropertyChange(this) { name, _, _ ->
if ( if (
name.startsWith(VisualObject3D.position) || name.startsWith(VisualObject3D.POSITION_KEY) ||
name.startsWith(VisualObject3D.rotation) || name.startsWith(VisualObject3D.ROTATION) ||
name.startsWith(VisualObject3D.scale) name.startsWith(VisualObject3D.SCALE_KEY)
) { ) {
//update position of mesh using this object //update position of mesh using this object
updatePosition(obj) updatePosition(obj)

View File

@ -19,12 +19,8 @@ import javafx.scene.transform.Rotate
import org.fxyz3d.shapes.composites.PolyLine3D import org.fxyz3d.shapes.composites.PolyLine3D
import org.fxyz3d.shapes.primitives.CuboidMesh import org.fxyz3d.shapes.primitives.CuboidMesh
import org.fxyz3d.shapes.primitives.SpheroidMesh import org.fxyz3d.shapes.primitives.SpheroidMesh
import kotlin.collections.HashMap
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
import kotlin.collections.find
import kotlin.collections.map
import kotlin.collections.mapNotNull
import kotlin.collections.set import kotlin.collections.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -91,23 +87,23 @@ class FX3DPlugin : AbstractPlugin() {
} }
} }
}.apply { }.apply {
translateXProperty().bind(binding[VisualObject3D.xPos].float(obj.x.toFloat())) translateXProperty().bind(binding[VisualObject3D.X_POSITION_KEY].float(obj.x.toFloat()))
translateYProperty().bind(binding[VisualObject3D.yPos].float(obj.y.toFloat())) translateYProperty().bind(binding[VisualObject3D.Y_POSITION_KEY].float(obj.y.toFloat()))
translateZProperty().bind(binding[VisualObject3D.zPos].float(obj.z.toFloat())) translateZProperty().bind(binding[VisualObject3D.Z_POSITION_KEY].float(obj.z.toFloat()))
scaleXProperty().bind(binding[VisualObject3D.xScale].float(obj.scaleX.toFloat())) scaleXProperty().bind(binding[VisualObject3D.X_SCALE_KEY].float(obj.scaleX.toFloat()))
scaleYProperty().bind(binding[VisualObject3D.yScale].float(obj.scaleY.toFloat())) scaleYProperty().bind(binding[VisualObject3D.Y_SCALE_KEY].float(obj.scaleY.toFloat()))
scaleZProperty().bind(binding[VisualObject3D.zScale].float(obj.scaleZ.toFloat())) scaleZProperty().bind(binding[VisualObject3D.Z_SCALE_KEY].float(obj.scaleZ.toFloat()))
val rotateX = Rotate(0.0, Rotate.X_AXIS).apply { val rotateX = Rotate(0.0, Rotate.X_AXIS).apply {
angleProperty().bind(binding[VisualObject3D.xRotation].float(obj.rotationX.toFloat()).multiply(180.0 / PI)) angleProperty().bind(binding[VisualObject3D.X_ROTATION_KEY].float(obj.rotationX.toFloat()).multiply(180.0 / PI))
} }
val rotateY = Rotate(0.0, Rotate.Y_AXIS).apply { val rotateY = Rotate(0.0, Rotate.Y_AXIS).apply {
angleProperty().bind(binding[VisualObject3D.yRotation].float(obj.rotationY.toFloat()).multiply(180.0 / PI)) angleProperty().bind(binding[VisualObject3D.Y_ROTATION_KEY].float(obj.rotationY.toFloat()).multiply(180.0 / PI))
} }
val rotateZ = Rotate(0.0, Rotate.Z_AXIS).apply { val rotateZ = Rotate(0.0, Rotate.Z_AXIS).apply {
angleProperty().bind(binding[VisualObject3D.zRotation].float(obj.rotationZ.toFloat()).multiply(180.0 / PI)) angleProperty().bind(binding[VisualObject3D.Z_ROTATION_KEY].float(obj.rotationZ.toFloat()).multiply(180.0 / PI))
} }
when (obj.rotationOrder) { when (obj.rotationOrder) {

View File

@ -1,4 +1,6 @@
import scientifik.* import scientifik.DependencyConfiguration
import scientifik.FXModule
import scientifik.useFx
plugins { plugins {
id("scientifik.mpp") id("scientifik.mpp")
@ -16,11 +18,6 @@ kotlin {
js { js {
useCommonJs() useCommonJs()
browser {
webpackTask {
//sourceMaps = false
}
}
} }
sourceSets { sourceSets {

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.configEditor
import hep.dataforge.vis.react.flexColumn 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
@ -80,7 +81,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
classes.add("p-1") classes.add("p-1")
overflow = Overflow.auto overflow = Overflow.auto
} }
gridColumn(3) { gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-2 order-xl-1") {
card("Load data") { card("Load data") {
fileDrop("(drag file here)") { files -> fileDrop("(drag file here)") { files ->
val file = files?.get(0) val file = files?.get(0)
@ -104,7 +105,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
} }
} }
gridColumn(6) { gridColumn(6, maxSize= GridMaxSize.XL, classes = "order-1 order-xl-2") {
//canvas //canvas
(visual as? VisualObject3D)?.let { visual3D -> (visual as? VisualObject3D)?.let { visual3D ->
child(ThreeCanvasComponent::class) { child(ThreeCanvasComponent::class) {
@ -120,7 +121,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
} }
} }
} }
gridColumn(3) { gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-3") {
container { container {
//settings //settings
canvas?.let { canvas?.let {

View File

@ -7,8 +7,10 @@ import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
import hep.dataforge.vis.spatial.gdml.GDMLTransformer 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 kotlinx.css.*
import react.child import react.child
import react.dom.render import react.dom.render
import styled.injectGlobal
import kotlin.browser.document import kotlin.browser.document
@ -42,6 +44,15 @@ private class GDMLDemoApp : Application {
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
injectGlobal {
body {
height = 100.pct
width = 100.pct
margin(0.px)
padding(0.px)
}
}
val context = Global.context("demo") {} val context = Global.context("demo") {}
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")

View File

@ -6,9 +6,9 @@ import hep.dataforge.names.NameToken
import hep.dataforge.names.isEmpty import hep.dataforge.names.isEmpty
import hep.dataforge.vis.VisualObject import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.bootstrap.card import hep.dataforge.vis.bootstrap.card
import hep.dataforge.vis.bootstrap.configEditor
import hep.dataforge.vis.bootstrap.objectTree import hep.dataforge.vis.bootstrap.objectTree
import hep.dataforge.vis.react.component import hep.dataforge.vis.react.component
import hep.dataforge.vis.react.configEditor
import hep.dataforge.vis.react.state import hep.dataforge.vis.react.state
import hep.dataforge.vis.spatial.specifications.Camera import hep.dataforge.vis.spatial.specifications.Camera
import hep.dataforge.vis.spatial.specifications.Canvas import hep.dataforge.vis.spatial.specifications.Canvas

View File

@ -11,6 +11,5 @@ kotlin {
} }
dependencies{ dependencies{
api(project(":dataforge-vis-common"))
api(project(":ui:react")) api(project(":ui:react"))
} }

View File

@ -5,6 +5,7 @@ import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty import hep.dataforge.names.isEmpty
import hep.dataforge.vis.VisualObject import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.react.configEditor
import org.w3c.dom.Element import org.w3c.dom.Element
import react.RBuilder import react.RBuilder
import react.dom.li import react.dom.li

View File

@ -11,12 +11,11 @@ kotlin {
} }
dependencies{ dependencies{
api(project(":dataforge-vis-common"))
api(project(":ui:react")) api(project(":ui:react"))
api("subroh0508.net.kotlinmaterialui:core:0.3.16") api("subroh0508.net.kotlinmaterialui:core:0.4.0")
api("subroh0508.net.kotlinmaterialui:lab:0.3.16") api("subroh0508.net.kotlinmaterialui:lab:0.4.0")
api(npm("@material-ui/core","4.9.13")) api(npm("@material-ui/core","4.9.14"))
api(npm("@material-ui/lab","4.0.0-alpha.52")) api(npm("@material-ui/lab","4.0.0-alpha.51"))
//api(npm("@material-ui/icons","4.9.1")) //api(npm("@material-ui/icons","4.9.1"))
} }

View File

@ -1,193 +0,0 @@
package hep.dataforge.vis.material
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.*
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.isEmpty
import hep.dataforge.names.plus
import hep.dataforge.vis.react.component
import hep.dataforge.vis.react.state
import kotlinx.css.Display
import kotlinx.css.display
import kotlinx.css.flexGrow
import kotlinx.css.flexShrink
import kotlinx.html.js.onClickFunction
import materialui.components.button.button
import materialui.components.grid.enums.GridAlignItems
import materialui.components.grid.enums.GridJustify
import materialui.components.grid.grid
import materialui.components.typography.typographyH6
import materialui.lab.components.treeItem.treeItem
import materialui.lab.components.treeView.treeView
import org.w3c.dom.Element
import org.w3c.dom.events.Event
import react.*
import react.dom.render
import react.dom.span
import styled.css
import styled.styledDiv
interface ConfigEditorProps : RProps {
/**
* Root config object - always non null
*/
var root: Config
/**
* Full path to the displayed node in [root]. Could be empty
*/
var name: Name
/**
* Root default
*/
var default: Meta?
/**
* Root descriptor
*/
var descriptor: NodeDescriptor?
}
private fun RBuilder.configEditorItem(
root: Config,
name: Name,
descriptor: NodeDescriptor?,
default: Meta?
) {
val item = root[name]
val descriptorItem: ItemDescriptor? = descriptor?.get(name)
val defaultItem = default?.get(name)
val actualItem: MetaItem<Meta>? = item ?: defaultItem ?: descriptorItem?.defaultItem()
val token = name.last()?.toString() ?: "Properties"
val removeClick: (Event) -> Unit = {
root.remove(name)
}
treeItem {
attrs {
nodeId = name.toString()
label {
row {
attrs {
alignItems = GridAlignItems.stretch
justify = GridJustify.spaceBetween
spacing(1)
}
grid {
typographyH6 {
+token
}
}
if (actualItem is MetaItem.ValueItem) {
styledDiv {
css {
display = Display.flex
flexGrow = 1.0
}
valueChooser(root, name, actualItem.value, descriptorItem as? ValueDescriptor)
}
}
if (!name.isEmpty()) {
styledDiv {
css {
display = Display.flex
flexShrink = 1.0
}
button {
+"\u00D7"
attrs {
if (item == null) {
disabled = true
} else {
onClickFunction = removeClick
}
}
}
}
}
}
}
}
if (actualItem is MetaItem.NodeItem) {
val keys = buildSet<NameToken> {
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
add(NameToken(it))
}
item?.node?.items?.keys?.let { addAll(it) }
defaultItem?.node?.items?.keys?.let { addAll(it) }
}
keys.forEach { token ->
configEditorItem(root, name + token, descriptor, default)
}
}
}
}
val ConfigEditor: FunctionalComponent<ConfigEditorProps> = component { props ->
var kostyl by state { false }
fun update() {
kostyl = !kostyl
}
useEffectWithCleanup(listOf(props.root)) {
props.root.onChange(this) { name, _, _ ->
if (name == props.name) {
update()
}
}
return@useEffectWithCleanup { props.root.removeListener(this) }
}
treeView {
attrs {
defaultCollapseIcon {
span {
+"-"
}
//child(ExpandMoreIcon::class) {}
}//{<ExpandMoreIcon />}
defaultExpandIcon {
span {
+"+"
}
//child(ChevronRightIcon::class) {}
}//{<ChevronRightIcon />}
set("disableSelection", true)
}
configEditorItem(props.root, props.name, props.descriptor, props.default)
}
}
fun RBuilder.configEditor(
config: Config,
name: Name = Name.EMPTY,
descriptor: NodeDescriptor? = null,
default: Meta? = null
) {
child(ConfigEditor) {
attrs {
this.root = config
this.name = name
this.descriptor = descriptor
this.default = default
}
}
}
fun Element.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null) {
render(this) {
configEditor(config, Name.EMPTY, descriptor, default)
}
}
fun RBuilder.configEditor(obj: Configurable, descriptor: NodeDescriptor? = obj.descriptor, default: Meta? = null) {
configEditor(obj.config, Name.EMPTY, descriptor ?: obj.descriptor, default)
}

View File

@ -8,7 +8,9 @@ import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.isEmpty import hep.dataforge.vis.isEmpty
import hep.dataforge.vis.react.component import hep.dataforge.vis.react.component
import hep.dataforge.vis.react.state import hep.dataforge.vis.react.state
import kotlinx.html.UL
import materialui.lab.components.treeItem.treeItem import materialui.lab.components.treeItem.treeItem
import materialui.lab.components.treeView.SingleSelectTreeViewElementBuilder
import materialui.lab.components.treeView.treeView import materialui.lab.components.treeView.treeView
import react.FunctionalComponent import react.FunctionalComponent
import react.RBuilder import react.RBuilder
@ -49,11 +51,11 @@ private fun RBuilder.treeBranch(name: Name, obj: VisualObject): Unit {
val ObjectTree: FunctionalComponent<ObjectTreeProps> = component { props -> val ObjectTree: FunctionalComponent<ObjectTreeProps> = component { props ->
var selected: String? by state { props.selected.toString() } var selected: String? by state { props.selected.toString() }
treeView { treeView {
this as SingleSelectTreeViewElementBuilder<UL>
attrs { attrs {
this.selected = selected this.selected = selected
this.onNodeSelect = { _, selectedItem -> this.onNodeSelect{ _, selectedItem ->
@Suppress("CAST_NEVER_SUCCEEDS") selected = selectedItem
selected = (selectedItem as? String)
val itemName = selected?.toName() val itemName = selected?.toName()
props.clickCallback(itemName) props.clickCallback(itemName)
Unit Unit

View File

@ -1,114 +0,0 @@
package hep.dataforge.vis.material
import hep.dataforge.meta.Config
import hep.dataforge.meta.descriptors.ValueDescriptor
import hep.dataforge.meta.get
import hep.dataforge.meta.number
import hep.dataforge.meta.setValue
import hep.dataforge.names.Name
import hep.dataforge.values.*
import hep.dataforge.vis.widgetType
import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onKeyDownFunction
import materialui.components.input.input
import materialui.components.select.select
import materialui.components.slider.slider
import materialui.components.switches.switch
import materialui.components.textfield.textField
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.events.Event
import org.w3c.dom.events.KeyboardEvent
import react.RBuilder
import react.dom.option
internal fun RBuilder.valueChooser(root: Config, name: Name, value: Value, descriptor: ValueDescriptor?) {
val onValueChange: (Event) -> Unit = { event ->
if (event !is KeyboardEvent || event.key == "Enter") {
val res = when (val t = event.target) {
// (it.target as HTMLInputElement).value
is HTMLInputElement -> if (t.type == "checkbox") {
if (t.checked) True else False
} else {
t.value.asValue()
}
is HTMLSelectElement -> t.value.asValue()
else -> error("Unknown event target: $t")
}
try {
root.setValue(name, res)
} catch (ex: Exception) {
console.error("Can't set config property ${name} to $res")
}
}
}
val type = descriptor?.type?.firstOrNull()
when {
descriptor?.widgetType == "slider" -> slider {
attrs {
descriptor.attributes["step"].number?.let {
step = it
}
descriptor.attributes["min"].number?.let {
min = it
}
descriptor.attributes["max"].number?.let {
max = it
}
this.defaultValue = value.number
onChangeFunction = onValueChange
}
}
descriptor?.widgetType == "color" -> input {
attrs {
fullWidth = true
this.type = InputType.color
this.value = value.string
onChangeFunction = onValueChange
}
}
type == ValueType.BOOLEAN -> switch {
attrs {
defaultChecked = value.boolean
onChangeFunction = onValueChange
}
}
type == ValueType.NUMBER -> textField {
attrs {
fullWidth = true
this.type = InputType.number
defaultValue = value.string
onChangeFunction = onValueChange
//onKeyDownFunction = onValueChange
}
}
descriptor?.allowedValues?.isNotEmpty() ?: false -> select {
descriptor!!.allowedValues.forEach {
option {
+it.string
}
}
attrs {
fullWidth = true
multiple = false
onChangeFunction = onValueChange
}
}
else -> textField {
attrs {
this.type = InputType.text
fullWidth = true
this.defaultValue = value.string
//onFocusOutFunction = onValueChange
onKeyDownFunction = onValueChange
}
}
}
}

View File

@ -10,21 +10,12 @@ kotlin {
dependencies{ dependencies{
api(project(":dataforge-vis-common"))
api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72") //api("org.jetbrains:kotlin-react:16.13.1-pre.104-kotlin-1.3.72")
api("org.jetbrains:kotlin-react-dom:16.13.1-pre.104-kotlin-1.3.72") api("org.jetbrains:kotlin-react-dom:16.13.1-pre.104-kotlin-1.3.72")
api("org.jetbrains.kotlinx:kotlinx-html:0.6.12")
api("org.jetbrains:kotlin-extensions:1.0.1-pre.104-kotlin-1.3.72")
api("org.jetbrains:kotlin-css-js:1.0.0-pre.94-kotlin-1.3.70")
api("org.jetbrains:kotlin-styled:1.0.0-pre.104-kotlin-1.3.72")
api(npm("core-js", "2.6.5"))
api(npm("react", "16.13.1")) api(npm("react", "16.13.1"))
api(npm("react-dom", "16.13.1")) api(npm("react-dom", "16.13.1"))
api(npm("react-is", "16.13.1"))
api(npm("react-is", "16.13.0"))
api(npm("inline-style-prefixer", "5.1.0"))
api(npm("styled-components", "4.3.2"))
} }

View File

@ -0,0 +1,74 @@
package hep.dataforge.vis.react
import kotlinx.css.*
import kotlinx.css.properties.deg
import kotlinx.css.properties.rotate
import styled.StyleSheet
object TreeStyles : StyleSheet("treeStyles", true) {
/**
* Remove default bullets
*/
val tree by css {
paddingLeft = 8.px
marginLeft = 0.px
listStyleType = ListStyleType.none
}
/**
* Style the caret/arrow
*/
val treeCaret by css {
cursor = Cursor.pointer
userSelect = UserSelect.none
/* Create the caret/arrow with a unicode, and style it */
before {
content = "\u25B6".quoted
color = Color.black
display = Display.inlineBlock
marginRight = 6.px
}
}
val treeItem by css {
alignItems = Align.center
paddingLeft = 10.px
borderLeftStyle = BorderStyle.dashed
borderLeftWidth = 1.px
borderLeftColor = Color.lightGray
}
val treeLeaf by css {
display = Display.flex
flexDirection = FlexDirection.row
userSelect = UserSelect.none
alignItems = Align.center
}
/**
* Rotate the caret/arrow icon when clicked on (using JavaScript)
*/
val treeCaredDown by css {
before {
content = "\u25B6".quoted
color = Color.black
display = Display.inlineBlock
marginRight = 6.px
transform.rotate(90.deg)
}
}
val treeLabel by css {
overflow = Overflow.hidden
}
val treeLabelInactive by css {
color = Color.lightGray
}
val treeLabelSelected by css {
backgroundColor = Color.lightBlue
}
}

View File

@ -1,4 +1,4 @@
package hep.dataforge.vis.bootstrap package hep.dataforge.vis.react
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.* import hep.dataforge.meta.descriptors.*
@ -6,19 +6,15 @@ import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.plus 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.component
import hep.dataforge.vis.react.flexRow
import hep.dataforge.vis.react.state
import kotlinx.css.* import kotlinx.css.*
import kotlinx.html.classes import kotlinx.css.properties.TextDecoration
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.div
import styled.css import react.dom.render
import styled.styledDiv import styled.*
interface ConfigEditorItemProps : RProps { interface ConfigEditorItemProps : RProps {
@ -91,25 +87,32 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
when (actualItem) { when (actualItem) {
is MetaItem.NodeItem -> { is MetaItem.NodeItem -> {
div { div {
span("tree-caret") { styledSpan {
attrs { css {
+TreeStyles.treeCaret
if (expanded) { if (expanded) {
classes += "tree-caret-down" +TreeStyles.treeCaredDown
} }
}
attrs {
onClickFunction = expanderClick onClickFunction = expanderClick
} }
} }
span("tree-label") { styledSpan {
+token css {
attrs { +TreeStyles.treeLabel
if (item == null) { if (item == null) {
classes += "tree-label-inactive" +TreeStyles.treeLabelInactive
} }
} }
+token
} }
} }
if (expanded) { if (expanded) {
ul("tree") { styledUl {
css {
+TreeStyles.tree
}
val keys = buildSet<NameToken> { val keys = buildSet<NameToken> {
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach { (descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
add(NameToken(it)) add(NameToken(it))
@ -119,7 +122,10 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
} }
keys.forEach { token -> keys.forEach { token ->
li("tree-item align-middle") { styledLi {
css {
+TreeStyles.treeItem
}
child(ConfigEditorItem) { child(ConfigEditorItem) {
attrs { attrs {
this.key = props.name.toString() this.key = props.name.toString()
@ -136,22 +142,23 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
} }
} }
is MetaItem.ValueItem -> { is MetaItem.ValueItem -> {
flexRow { styledDiv {
css { css {
alignItems = Align.center +TreeStyles.treeLeaf
justifyContent= JustifyContent.flexEnd justifyContent = JustifyContent.flexEnd
} }
styledDiv { styledDiv {
css{ css {
flexGrow = 1.0 flexGrow = 1.0
} }
span("tree-label align-self-center") { styledSpan {
+token css {
attrs { +TreeStyles.treeLabel
if (item == null) { if (item == null) {
classes += "tree-label-inactive" +TreeStyles.treeLabelInactive
} }
} }
+token
} }
} }
styledDiv { styledDiv {
@ -166,7 +173,23 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
css { css {
flexShrink = 1.0 flexShrink = 1.0
} }
button(classes = "btn btn-link align-self-center") { styledButton {
css {
backgroundColor = Color.white
borderStyle = BorderStyle.solid
borderRadius = 2.px
padding(1.px, 5.px)
marginLeft = 4.px
textAlign = TextAlign.center
textDecoration = TextDecoration.none
display = Display.inlineBlock
cursor = Cursor.pointer
disabled {
cursor = Cursor.auto
borderStyle = BorderStyle.dashed
color = Color.lightGray
}
}
+"\u00D7" +"\u00D7"
attrs { attrs {
if (item == null) { if (item == null) {

View File

@ -0,0 +1,9 @@
package hep.dataforge.vis.react
import styled.StyleSheet
class MainStyle: StyleSheet("main", true){
}

View File

@ -1,4 +1,4 @@
package hep.dataforge.vis.bootstrap package hep.dataforge.vis.react
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.ValueDescriptor import hep.dataforge.meta.descriptors.ValueDescriptor
@ -6,6 +6,8 @@ import hep.dataforge.names.Name
import hep.dataforge.values.* import hep.dataforge.values.*
import hep.dataforge.vis.Colors import hep.dataforge.vis.Colors
import hep.dataforge.vis.widgetType import hep.dataforge.vis.widgetType
import kotlinx.css.Align
import kotlinx.css.alignSelf
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onKeyDownFunction import kotlinx.html.js.onKeyDownFunction
@ -14,7 +16,12 @@ 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 react.* import react.*
import react.dom.* import react.dom.defaultValue
import react.dom.input
import react.dom.option
import react.dom.select
import styled.css
import styled.styledDiv
interface ValueChooserProps : RProps { interface ValueChooserProps : RProps {
var item: MetaItem<*>? var item: MetaItem<*>?
@ -66,9 +73,6 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
} }
element.indeterminate = props.item == null element.indeterminate = props.item == null
} }
// (state.element as? HTMLSelectElement)?.let { element ->
// state.value?.let { element.value = it.string }
// }
} }
private fun RBuilder.stringInput() = input(type = InputType.text) { private fun RBuilder.stringInput() = input(type = InputType.text) {
@ -80,7 +84,10 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
} }
override fun RBuilder.render() { override fun RBuilder.render() {
div("align-self-center") { styledDiv {
css {
alignSelf = Align.center
}
val descriptor = props.descriptor val descriptor = props.descriptor
val type = descriptor?.type?.firstOrNull() val type = descriptor?.type?.firstOrNull()
when { when {