diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt index d6803562..2fcc1bed 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/StyleSheet.kt @@ -3,8 +3,7 @@ package hep.dataforge.vis.common import hep.dataforge.io.serialization.MetaSerializer -import hep.dataforge.meta.Meta -import hep.dataforge.meta.get +import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.asName import kotlinx.serialization.Serializable @@ -37,6 +36,15 @@ class StyleSheet() { } owner?.styleChanged(key, oldStyle, style) } + + infix fun String.put(style: Meta?) { + set(this, style) + } + + operator fun set(key: String, builder: MetaBuilder.() -> Unit) { + val newStyle = get(key)?.let { buildMeta(it, builder) } ?: buildMeta(builder) + set(key, newStyle.seal()) + } } private fun VisualObject.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt index 5baa6262..11d3dcab 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt @@ -1,8 +1,5 @@ package hep.dataforge.vis.common -import hep.dataforge.meta.MetaBuilder -import hep.dataforge.meta.buildMeta -import hep.dataforge.meta.seal import hep.dataforge.names.* import hep.dataforge.provider.Provider @@ -14,7 +11,7 @@ interface VisualGroup : Provider, Iterable, VisualObject { override val defaultTarget: String get() = VisualObject.TYPE - val styleSheet: StyleSheet + val styleSheet: StyleSheet? override fun provideTop(target: String): Map = when (target) { @@ -26,7 +23,7 @@ interface VisualGroup : Provider, Iterable, VisualObject { } res.entries }.associate { it.toPair() } - STYLE_TARGET -> styleSheet.items.mapKeys { it.key.toName() } + STYLE_TARGET -> styleSheet?.items?.mapKeys { it.key.toName() } ?: emptyMap() else -> emptyMap() } @@ -47,8 +44,8 @@ interface VisualGroup : Provider, Iterable, VisualObject { /** * A fix for serialization bug that writes all proper parents inside the tree after deserialization */ - fun attachChildren(){ - styleSheet.owner = this + fun attachChildren() { + styleSheet?.owner = this this.children.values.forEach { it.parent = this (it as? VisualGroup)?.attachChildren() @@ -60,11 +57,6 @@ interface VisualGroup : Provider, Iterable, VisualObject { } } -fun VisualGroup.updateStyle(key: String, builder: MetaBuilder.() -> Unit) { - val newStyle = styleSheet[key]?.let { buildMeta(it, builder) } ?: buildMeta(builder) - styleSheet[key] = newStyle.seal() -} - data class StyleRef(val group: VisualGroup, val styleName: Name) val VisualGroup.isEmpty: Boolean get() = this.children.isEmpty() diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index 3b529780..d59d1a3f 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -40,7 +40,7 @@ class GDMLTransformer(val root: GDML) { var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> } fun VisualObject.useStyle(name: String, builder: MetaBuilder.() -> Unit) { - styleCache.getOrPut(name.toName()){ + styleCache.getOrPut(name.toName()) { buildMeta(builder) } useStyle(name) @@ -51,7 +51,7 @@ class GDMLTransformer(val root: GDML) { val styleName = "material[${material.name}]" - obj.useStyle(styleName){ + obj.useStyle(styleName) { MATERIAL_COLOR_KEY put random.nextInt(16777216) "gdml.material" put material.name } @@ -68,7 +68,9 @@ class GDMLTransformer(val root: GDML) { internal fun finalize(final: VisualGroup3D): VisualGroup3D { final.prototypes = proto styleCache.forEach { - final.styleSheet[it.key.toString()] = it.value + final.styleSheet { + this[it.key.toString()] = it.value + } } final.rotationOrder = RotationOrder.ZXY onFinish(this@GDMLTransformer) diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt index 42c3d1c6..9134989b 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/visualGDML.kt @@ -250,5 +250,7 @@ fun GDML.toVisual(block: GDMLTransformer.() -> Unit = {}): VisualGroup3D { * Append gdml node to the group */ fun VisualGroup3D.gdml(gdml: GDML, key: String = "", transformer: GDMLTransformer.() -> Unit = {}) { - set(key, gdml.toVisual(transformer)) + val visual = gdml.toVisual(transformer) + println(Visual3DPlugin.json.stringify(VisualGroup3D.serializer(),visual)) + set(key, visual) } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt index 2ea3fc31..ed6f087b 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Composite.kt @@ -47,9 +47,15 @@ inline fun VisualGroup3D.composite( it.config.update(group.config) //it.material = group.material - it.position = group.position - it.rotation = group.rotation - it.scale = group.scale + if(group.position!=null) { + it.position = group.position + } + if(group.rotation!=null) { + it.rotation = group.rotation + } + if(group.scale!=null) { + it.scale = group.scale + } set(name, it) } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index b3b04cd0..95da3d1a 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -46,8 +46,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua return if (inherit) { properties?.get(name) ?: mergedStyles[name] - ?: prototype.getProperty(name, false) - ?: parent?.getProperty(name, inherit) + ?: prototype.getProperty(name) + ?: parent?.getProperty(name) } else { properties?.get(name) ?: mergedStyles[name] @@ -74,7 +74,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua ?: error("Prototype with name $name not found in $this") } - override var styles: List get() = super.styles + prototype.styles set(value) { @@ -119,12 +118,12 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua return if (inherit) { properties?.get(name) ?: mergedStyles[name] - ?: prototype.getProperty(name, inherit) - ?: parent?.getProperty(name, inherit) + ?: prototype.getProperty(name) + ?: parent?.getProperty(name) } else { properties?.get(name) ?: mergedStyles[name] - ?: prototype.getProperty(name, inherit) + ?: prototype.getProperty(name, false) } } @@ -135,11 +134,11 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } } -val VisualObject.prototype: VisualObject? +val VisualObject.prototype: VisualObject get() = when (this) { is Proxy -> prototype is Proxy.ProxyChild -> prototype - else -> null + else -> this } /** @@ -158,12 +157,11 @@ fun VisualGroup3D.proxy( templateName: Name, obj: VisualObject3D, name: String = "", - attachToParent: Boolean = false, block: Proxy.() -> Unit = {} ): Proxy { val existing = getPrototype(templateName) if (existing == null) { - setPrototype(templateName, obj, attachToParent) + setPrototype(templateName, obj) } else if (existing != obj) { error("Can't add different prototype on top of existing one") } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index bb76d972..4bacdd79 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -18,7 +18,6 @@ import hep.dataforge.names.asName import hep.dataforge.names.isEmpty import hep.dataforge.vis.common.AbstractVisualGroup import hep.dataforge.vis.common.StyleSheet -import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -37,7 +36,8 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { field = value } - override val styleSheet: StyleSheet = StyleSheet(this) + override var styleSheet: StyleSheet? = null + private set //FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed override var properties: Config? = null @@ -55,6 +55,14 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { attachChildren() } + /** + * Update or create stylesheet + */ + fun styleSheet(block: StyleSheet.() -> Unit) { + val res = this.styleSheet ?: StyleSheet(this).also { this.styleSheet = it } + res.block() + } + override fun removeChild(token: NameToken) { _children.remove(token) childrenChanged(token.asName(), null) @@ -90,18 +98,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } - fun getPrototype(name: Name): VisualObject3D? = - prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name) - - fun setPrototype(name: Name, obj: VisualObject3D, attachToParent: Boolean = false) { - val parent = this.parent - if (attachToParent && parent is VisualGroup3D) { - parent.setPrototype(name, obj, attachToParent) - } else { - (prototypes ?: VisualGroup3D().also { this.prototypes = it }).set(name, obj) - } - } - override fun attachChildren() { super.attachChildren() prototypes?.run { @@ -115,5 +111,28 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } } +/** + * Ger a prototype redirecting the request to the parent if prototype is not found + */ +fun VisualGroup3D.getPrototype(name: Name): VisualObject3D? = + prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name) + +/** + * Defined a prototype inside current group + */ +fun VisualGroup3D.setPrototype(name: Name, obj: VisualObject3D) { + (prototypes ?: VisualGroup3D().also { this.prototypes = it })[name] = obj +} + +/** + * Define a group with given [key], attach it to this parent and return it. + */ fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D = - VisualGroup3D().apply(action).also { set(key, it) } \ No newline at end of file + VisualGroup3D().apply(action).also { set(key, it) } + +/** + * Create or edit prototype node as a group + */ +inline fun VisualGroup3D.prototypes(builder: VisualGroup3D.() -> Unit): Unit { + (prototypes ?: VisualGroup3D().also { this.prototypes = it }).run(builder) +} \ No newline at end of file diff --git a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt index dcece5bd..fa15b905 100644 --- a/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt +++ b/dataforge-vis-spatial/src/commonTest/kotlin/hep/dataforge/vis/spatial/PropertyTest.kt @@ -3,33 +3,34 @@ package hep.dataforge.vis.spatial import hep.dataforge.meta.int import hep.dataforge.meta.set import hep.dataforge.names.asName -import hep.dataforge.vis.common.updateStyle import hep.dataforge.vis.common.useStyle import kotlin.test.Test import kotlin.test.assertEquals class PropertyTest { @Test - fun testInheritedProperty(){ + fun testInheritedProperty() { var box: Box? = null val group = VisualGroup3D().apply { config["test"] = 22 group { - box = box(100,100,100) + box = box(100, 100, 100) } } assertEquals(22, box?.getProperty("test".asName()).int) } @Test - fun testStyleProperty(){ + fun testStyleProperty() { var box: Box? = null val group = VisualGroup3D().apply { - updateStyle("testStyle"){ - "test" put 22 + styleSheet { + set("testStyle") { + "test" put 22 + } } group { - box = box(100,100,100).apply { + box = box(100, 100, 100).apply { useStyle("testStyle") } } @@ -38,18 +39,41 @@ class PropertyTest { } @Test - fun testColor(){ + fun testColor() { var box: Box? = null val group = VisualGroup3D().apply { - updateStyle("testStyle"){ - Material3D.MATERIAL_COLOR_KEY put "#555555" + styleSheet { + set("testStyle") { + Material3D.MATERIAL_COLOR_KEY put "#555555" + } } group { - box = box(100,100,100){ + box = box(100, 100, 100) { useStyle("testStyle") } } } assertEquals("#555555", box?.color) } + + @Test + fun testProxyStyleProperty() { + var box: Proxy? = null + val group = VisualGroup3D().apply { + styleSheet { + set("testStyle") { + Material3D.MATERIAL_COLOR_KEY put "#555555" + } + } + prototypes { + box(100, 100, 100, name = "box") { + styles = listOf("testStyle") + } + } + group { + box = ref("box".asName()) + } + } + assertEquals("#555555", box?.color) + } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt index 0aaaa1d9..db40d616 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/editor/propertyEditor.kt @@ -2,7 +2,10 @@ package hep.dataforge.vis.spatial.editor import hep.dataforge.io.toJson import hep.dataforge.js.jsObject -import hep.dataforge.meta.* +import hep.dataforge.meta.DynamicMeta +import hep.dataforge.meta.Meta +import hep.dataforge.meta.builder +import hep.dataforge.meta.update import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.findStyle import hep.dataforge.vis.spatial.* @@ -24,11 +27,7 @@ fun Element.propertyEditor(item: VisualObject?) { if (item != null) { append { card("Properties") { - val config: Meta = if (item is Proxy || item is Proxy.ProxyChild) { - item.prototype?.config ?: EmptyMeta - } else { - item.config - } + val config: Meta = item.prototype.config val metaToEdit = config.builder().apply { VISIBLE_KEY to (item.visible ?: true) if (item is VisualObject3D) { diff --git a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt index 7c44d47f..288174ea 100644 --- a/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt +++ b/dataforge-vis-spatial/src/jvmMain/kotlin/hep/dataforge/vis/spatial/fx/FX3DPlugin.kt @@ -3,7 +3,6 @@ package hep.dataforge.vis.spatial.fx import hep.dataforge.context.* import hep.dataforge.meta.Meta import hep.dataforge.meta.boolean -import hep.dataforge.meta.get import hep.dataforge.provider.Type import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY @@ -20,6 +19,13 @@ 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 @@ -106,11 +112,11 @@ class FX3DPlugin : AbstractPlugin() { when (obj.rotationOrder) { RotationOrder.ZYX -> transforms.addAll(rotateZ, rotateY, rotateX) - RotationOrder.XZY -> transforms.addAll(rotateY, rotateZ, rotateX) - RotationOrder.YXZ -> transforms.addAll(rotateZ, rotateX, rotateY) - RotationOrder.YZX -> transforms.addAll(rotateX, rotateZ, rotateY) - RotationOrder.ZXY -> transforms.addAll(rotateY, rotateX, rotateZ) - RotationOrder.XYZ -> transforms.addAll(rotateZ, rotateY, rotateX) + RotationOrder.XZY -> transforms.addAll(rotateX, rotateZ, rotateY) + RotationOrder.YXZ -> transforms.addAll(rotateY, rotateX, rotateZ) + RotationOrder.YZX -> transforms.addAll(rotateY, rotateZ, rotateX) + RotationOrder.ZXY -> transforms.addAll(rotateZ, rotateX, rotateY) + RotationOrder.XYZ -> transforms.addAll(rotateX, rotateY, rotateZ) } if (this is Shape3D) { diff --git a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt index 3fbaff04..1808c43f 100644 --- a/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt +++ b/spatial-demo/src/jvmMain/kotlin/hep/dataforge/vis/spatial/demo/FXDemoApp.kt @@ -17,7 +17,7 @@ class FXDemoApp : App(FXDemoGrid::class) { stage.width = 400.0 stage.height = 400.0 - //view.showcase() + view.showcase() view.demo("gdml", "gdml") { gdml(Paths.get("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml")) { lUnit = LUnit.CM