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 {
dependencies {
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: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-extensions:1.0.1-pre.105-kotlin-1.3.72")
//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(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("styled-components", "4.3.2"))
//api(project(":ringui-wrapper"))

View File

@ -2,9 +2,12 @@ package hep.dataforge.vis
import hep.dataforge.meta.Laminate
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.node
import hep.dataforge.names.Name
import hep.dataforge.names.isEmpty
import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue
/**
* 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()) {
null -> null
is MetaItem.ValueItem -> first //fast search for first entry if it is value
@ -32,3 +35,11 @@ fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>?{
}
}
}
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) {
fun Meta.toVector(default: Float = 0f) = Point3D(
this[VisualObject3D.x].float ?: default,
this[VisualObject3D.y].float ?: default,
this[VisualObject3D.z].float ?: default
this[VisualObject3D.X_KEY].float ?: default,
this[VisualObject3D.Y_KEY].float ?: default,
this[VisualObject3D.Z_KEY].float ?: default
)
meta[VisualObject3D.position].node?.toVector()?.let { position = it }
meta[VisualObject3D.rotation].node?.toVector()?.let { rotation = it }
meta[VisualObject3D.scale].node?.toVector(1f)?.let { scale = it }
meta[VisualObject3D.POSITION_KEY].node?.toVector()?.let { position = it }
meta[VisualObject3D.ROTATION].node?.toVector()?.let { rotation = it }
meta[VisualObject3D.SCALE_KEY].node?.toVector(1f)?.let { scale = 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.asValue
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.IGNORE_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
@ -37,29 +38,29 @@ interface VisualObject3D : VisualObject {
val GEOMETRY_KEY = "geometry".asName()
val x = "x".asName()
val y = "y".asName()
val z = "z".asName()
val X_KEY = "x".asName()
val Y_KEY = "y".asName()
val Z_KEY = "z".asName()
val position = "pos".asName()
val POSITION_KEY = "pos".asName()
val xPos = position + x
val yPos = position + y
val zPos = position + z
val X_POSITION_KEY = POSITION_KEY + X_KEY
val Y_POSITION_KEY = POSITION_KEY + Y_KEY
val Z_POSITION_KEY = POSITION_KEY + Z_KEY
val rotation = "rotation".asName()
val ROTATION = "rotation".asName()
val xRotation = rotation + x
val yRotation = rotation + y
val zRotation = rotation + z
val X_ROTATION_KEY = ROTATION + X_KEY
val Y_ROTATION_KEY = ROTATION + Y_KEY
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 yScale = scale + y
val zScale = scale + z
val X_SCALE_KEY = SCALE_KEY + X_KEY
val Y_SCALE_KEY = SCALE_KEY + Y_KEY
val Z_SCALE_KEY = SCALE_KEY + Z_KEY
val descriptor by lazy {
NodeDescriptor {
@ -69,12 +70,14 @@ interface VisualObject3D : VisualObject {
}
//TODO replace by descriptor merge
value(VisualObject.STYLE_KEY){
value(VisualObject.STYLE_KEY) {
type(ValueType.STRING)
multiple = true
}
item(Material3D.MATERIAL_KEY.toString(), Material3D.descriptor)
enum<RotationOrder>(ROTATION_ORDER_KEY,default = RotationOrder.XYZ)
}
}
}
@ -107,8 +110,8 @@ enum class RotationOrder {
* Rotation order
*/
var VisualObject3D.rotationOrder: RotationOrder
get() = getProperty(VisualObject3D.rotationOrder).enum<RotationOrder>() ?: RotationOrder.XYZ
set(value) = setProperty(VisualObject3D.rotationOrder, value.name.asValue())
get() = getProperty(VisualObject3D.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
set(value) = setProperty(VisualObject3D.ROTATION_ORDER_KEY, value.name.asValue())
/**
@ -141,21 +144,21 @@ var VisualObject3D.x: Number
get() = position?.x ?: 0f
set(value) {
position().x = value.toDouble()
propertyInvalidated(VisualObject3D.xPos)
propertyInvalidated(VisualObject3D.X_POSITION_KEY)
}
var VisualObject3D.y: Number
get() = position?.y ?: 0f
set(value) {
position().y = value.toDouble()
propertyInvalidated(VisualObject3D.yPos)
propertyInvalidated(VisualObject3D.Y_POSITION_KEY)
}
var VisualObject3D.z: Number
get() = position?.z ?: 0f
set(value) {
position().z = value.toDouble()
propertyInvalidated(VisualObject3D.zPos)
propertyInvalidated(VisualObject3D.Z_POSITION_KEY)
}
private fun VisualObject3D.rotation(): Point3D =
@ -165,21 +168,21 @@ var VisualObject3D.rotationX: Number
get() = rotation?.x ?: 0f
set(value) {
rotation().x = value.toDouble()
propertyInvalidated(VisualObject3D.xRotation)
propertyInvalidated(VisualObject3D.X_ROTATION_KEY)
}
var VisualObject3D.rotationY: Number
get() = rotation?.y ?: 0f
set(value) {
rotation().y = value.toDouble()
propertyInvalidated(VisualObject3D.yRotation)
propertyInvalidated(VisualObject3D.Y_ROTATION_KEY)
}
var VisualObject3D.rotationZ: Number
get() = rotation?.z ?: 0f
set(value) {
rotation().z = value.toDouble()
propertyInvalidated(VisualObject3D.zRotation)
propertyInvalidated(VisualObject3D.Z_ROTATION_KEY)
}
private fun VisualObject3D.scale(): Point3D =
@ -189,19 +192,19 @@ var VisualObject3D.scaleX: Number
get() = scale?.x ?: 1f
set(value) {
scale().x = value.toDouble()
propertyInvalidated(VisualObject3D.xScale)
propertyInvalidated(VisualObject3D.X_SCALE_KEY)
}
var VisualObject3D.scaleY: Number
get() = scale?.y ?: 1f
set(value) {
scale().y = value.toDouble()
propertyInvalidated(VisualObject3D.yScale)
propertyInvalidated(VisualObject3D.Y_SCALE_KEY)
}
var VisualObject3D.scaleZ: Number
get() = scale?.z ?: 1f
set(value) {
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
fun Point2D.toMeta() = Meta {
VisualObject3D.x put x
VisualObject3D.y put y
VisualObject3D.X_KEY put x
VisualObject3D.Y_KEY put y
}
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 Point3D.toMeta() = Meta {
VisualObject3D.x put x
VisualObject3D.y put y
VisualObject3D.z put z
VisualObject3D.X_KEY put x
VisualObject3D.Y_KEY put y
VisualObject3D.Z_KEY put z
}

View File

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

View File

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

View File

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

View File

@ -19,12 +19,8 @@ import javafx.scene.transform.Rotate
import org.fxyz3d.shapes.composites.PolyLine3D
import org.fxyz3d.shapes.primitives.CuboidMesh
import org.fxyz3d.shapes.primitives.SpheroidMesh
import kotlin.collections.HashMap
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.find
import kotlin.collections.map
import kotlin.collections.mapNotNull
import kotlin.collections.set
import kotlin.math.PI
import kotlin.reflect.KClass
@ -91,23 +87,23 @@ class FX3DPlugin : AbstractPlugin() {
}
}
}.apply {
translateXProperty().bind(binding[VisualObject3D.xPos].float(obj.x.toFloat()))
translateYProperty().bind(binding[VisualObject3D.yPos].float(obj.y.toFloat()))
translateZProperty().bind(binding[VisualObject3D.zPos].float(obj.z.toFloat()))
scaleXProperty().bind(binding[VisualObject3D.xScale].float(obj.scaleX.toFloat()))
scaleYProperty().bind(binding[VisualObject3D.yScale].float(obj.scaleY.toFloat()))
scaleZProperty().bind(binding[VisualObject3D.zScale].float(obj.scaleZ.toFloat()))
translateXProperty().bind(binding[VisualObject3D.X_POSITION_KEY].float(obj.x.toFloat()))
translateYProperty().bind(binding[VisualObject3D.Y_POSITION_KEY].float(obj.y.toFloat()))
translateZProperty().bind(binding[VisualObject3D.Z_POSITION_KEY].float(obj.z.toFloat()))
scaleXProperty().bind(binding[VisualObject3D.X_SCALE_KEY].float(obj.scaleX.toFloat()))
scaleYProperty().bind(binding[VisualObject3D.Y_SCALE_KEY].float(obj.scaleY.toFloat()))
scaleZProperty().bind(binding[VisualObject3D.Z_SCALE_KEY].float(obj.scaleZ.toFloat()))
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 {
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 {
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) {

View File

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

View File

@ -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.configEditor
import hep.dataforge.vis.react.flexColumn
import hep.dataforge.vis.react.state
import hep.dataforge.vis.spatial.VisualGroup3D
@ -80,7 +81,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
classes.add("p-1")
overflow = Overflow.auto
}
gridColumn(3) {
gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-2 order-xl-1") {
card("Load data") {
fileDrop("(drag file here)") { files ->
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
(visual as? VisualObject3D)?.let { visual3D ->
child(ThreeCanvasComponent::class) {
@ -120,7 +121,7 @@ val GDMLApp = component<GDMLAppProps> { props ->
}
}
}
gridColumn(3) {
gridColumn(3, maxSize= GridMaxSize.XL, classes = "order-3") {
container {
//settings
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.LUnit
import hep.dataforge.vis.spatial.gdml.toVisual
import kotlinx.css.*
import react.child
import react.dom.render
import styled.injectGlobal
import kotlin.browser.document
@ -42,6 +44,15 @@ private class GDMLDemoApp : Application {
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 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.vis.VisualObject
import hep.dataforge.vis.bootstrap.card
import hep.dataforge.vis.bootstrap.configEditor
import hep.dataforge.vis.bootstrap.objectTree
import hep.dataforge.vis.react.component
import hep.dataforge.vis.react.configEditor
import hep.dataforge.vis.react.state
import hep.dataforge.vis.spatial.specifications.Camera
import hep.dataforge.vis.spatial.specifications.Canvas

View File

@ -11,6 +11,5 @@ kotlin {
}
dependencies{
api(project(":dataforge-vis-common"))
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.isEmpty
import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.react.configEditor
import org.w3c.dom.Element
import react.RBuilder
import react.dom.li

View File

@ -11,12 +11,11 @@ kotlin {
}
dependencies{
api(project(":dataforge-vis-common"))
api(project(":ui:react"))
api("subroh0508.net.kotlinmaterialui:core:0.3.16")
api("subroh0508.net.kotlinmaterialui:lab:0.3.16")
api(npm("@material-ui/core","4.9.13"))
api(npm("@material-ui/lab","4.0.0-alpha.52"))
api("subroh0508.net.kotlinmaterialui:core:0.4.0")
api("subroh0508.net.kotlinmaterialui:lab:0.4.0")
api(npm("@material-ui/core","4.9.14"))
api(npm("@material-ui/lab","4.0.0-alpha.51"))
//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.react.component
import hep.dataforge.vis.react.state
import kotlinx.html.UL
import materialui.lab.components.treeItem.treeItem
import materialui.lab.components.treeView.SingleSelectTreeViewElementBuilder
import materialui.lab.components.treeView.treeView
import react.FunctionalComponent
import react.RBuilder
@ -49,11 +51,11 @@ private fun RBuilder.treeBranch(name: Name, obj: VisualObject): Unit {
val ObjectTree: FunctionalComponent<ObjectTreeProps> = component { props ->
var selected: String? by state { props.selected.toString() }
treeView {
this as SingleSelectTreeViewElementBuilder<UL>
attrs {
this.selected = selected
this.onNodeSelect = { _, selectedItem ->
@Suppress("CAST_NEVER_SUCCEEDS")
selected = (selectedItem as? String)
this.onNodeSelect{ _, selectedItem ->
selected = selectedItem
val itemName = selected?.toName()
props.clickCallback(itemName)
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{
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.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-dom", "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"))
api(npm("react-is", "16.13.1"))
}

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.descriptors.*
@ -6,19 +6,15 @@ import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
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.css.properties.TextDecoration
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
import react.dom.div
import react.dom.render
import styled.*
interface ConfigEditorItemProps : RProps {
@ -91,25 +87,32 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
when (actualItem) {
is MetaItem.NodeItem -> {
div {
span("tree-caret") {
attrs {
styledSpan {
css {
+TreeStyles.treeCaret
if (expanded) {
classes += "tree-caret-down"
+TreeStyles.treeCaredDown
}
}
attrs {
onClickFunction = expanderClick
}
}
span("tree-label") {
+token
attrs {
styledSpan {
css {
+TreeStyles.treeLabel
if (item == null) {
classes += "tree-label-inactive"
+TreeStyles.treeLabelInactive
}
}
+token
}
}
if (expanded) {
ul("tree") {
styledUl {
css {
+TreeStyles.tree
}
val keys = buildSet<NameToken> {
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
add(NameToken(it))
@ -119,7 +122,10 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
}
keys.forEach { token ->
li("tree-item align-middle") {
styledLi {
css {
+TreeStyles.treeItem
}
child(ConfigEditorItem) {
attrs {
this.key = props.name.toString()
@ -136,22 +142,23 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
}
}
is MetaItem.ValueItem -> {
flexRow {
styledDiv {
css {
alignItems = Align.center
justifyContent= JustifyContent.flexEnd
+TreeStyles.treeLeaf
justifyContent = JustifyContent.flexEnd
}
styledDiv {
css{
css {
flexGrow = 1.0
}
span("tree-label align-self-center") {
+token
attrs {
styledSpan {
css {
+TreeStyles.treeLabel
if (item == null) {
classes += "tree-label-inactive"
+TreeStyles.treeLabelInactive
}
}
+token
}
}
styledDiv {
@ -166,7 +173,23 @@ private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) {
css {
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"
attrs {
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.descriptors.ValueDescriptor
@ -6,6 +6,8 @@ import hep.dataforge.names.Name
import hep.dataforge.values.*
import hep.dataforge.vis.Colors
import hep.dataforge.vis.widgetType
import kotlinx.css.Align
import kotlinx.css.alignSelf
import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onKeyDownFunction
@ -14,7 +16,12 @@ import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement
import org.w3c.dom.events.Event
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 {
var item: MetaItem<*>?
@ -66,9 +73,6 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
}
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) {
@ -80,7 +84,10 @@ class ValueChooserComponent(props: ValueChooserProps) : RComponent<ValueChooserP
}
override fun RBuilder.render() {
div("align-self-center") {
styledDiv {
css {
alignSelf = Align.center
}
val descriptor = props.descriptor
val type = descriptor?.type?.firstOrNull()
when {