From a38d70badebf1597bf94e8255896209b2ceace99 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 10 Dec 2020 12:38:35 +0300 Subject: [PATCH] Stylesheets moved to properties --- CHANGELOG.md | 1 + build.gradle.kts | 2 +- .../vision/bootstrap/visionPropertyEditor.kt | 4 +- .../kotlin/hep/dataforge/vision/StyleSheet.kt | 105 +++++++----------- .../kotlin/hep/dataforge/vision/Vision.kt | 6 - .../kotlin/hep/dataforge/vision/VisionBase.kt | 2 +- .../hep/dataforge/vision/VisionGroup.kt | 21 ++-- .../hep/dataforge/vision/VisionGroupBase.kt | 13 --- .../editor/VisualObjectEditorFragment.kt | 4 +- .../dataforge/vision/gdml/GDMLTransformer.kt | 1 + .../hep/dataforge/vision/solid/Composite.kt | 8 +- .../hep/dataforge/vision/solid/SolidGroup.kt | 4 - .../dataforge/vision/solid/SolidReference.kt | 4 - .../dataforge/vision/solid/PropertyTest.kt | 1 + 14 files changed, 62 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a47fa13a..611e4c13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Point3D and Point2D are made separate classes instead of expect/actual (to split up different engines. - JavaFX support moved to a separate module - Threejs support moved to a separate module +- \[Breaking change!\] Stylesheets are moved into properties under `@stylesheet` key ### Deprecated diff --git a/build.gradle.kts b/build.gradle.kts index 6a5a615a..d4147448 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } val dataforgeVersion by extra("0.2.1-dev-4") -val ktorVersion by extra("1.4.2") +val ktorVersion by extra("1.4.3") val htmlVersion by extra("0.7.2") val kotlinWrappersVersion by extra("pre.129-kotlin-1.4.20") val fxVersion by extra("14") diff --git a/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/visionPropertyEditor.kt b/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/visionPropertyEditor.kt index b69c631b..5bc10577 100644 --- a/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/visionPropertyEditor.kt +++ b/ui/bootstrap/src/main/kotlin/hep/dataforge/vision/bootstrap/visionPropertyEditor.kt @@ -3,9 +3,9 @@ package hep.dataforge.vision.bootstrap import hep.dataforge.meta.Meta import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.vision.Vision +import hep.dataforge.vision.getStyle import hep.dataforge.vision.react.configEditor import hep.dataforge.vision.react.metaViewer -import hep.dataforge.vision.resolveStyle import org.w3c.dom.Element import react.RBuilder import react.dom.render @@ -24,7 +24,7 @@ public fun RBuilder.visionPropertyEditor( card("Styles") { accordion("styles") { styles.forEach { styleName -> - val style = item.resolveStyle(styleName) + val style = item.getStyle(styleName) if (style != null) { entry(styleName) { metaViewer(style) diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt index d154efbd..4d3ea1f3 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/StyleSheet.kt @@ -1,62 +1,30 @@ -@file:UseSerializers(MetaSerializer::class) - package hep.dataforge.vision import hep.dataforge.meta.* import hep.dataforge.names.Name +import hep.dataforge.names.NameToken import hep.dataforge.names.asName -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import kotlinx.serialization.UseSerializers -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder +import hep.dataforge.names.plus /** * A container for styles */ -@Serializable(StyleSheet.Companion::class) -public class StyleSheet private constructor(private val styleMap: MutableMap) { - @Transient - internal var owner: Vision? = null +public inline class StyleSheet(private val owner: VisionGroup) { - public constructor(owner: Vision) : this(LinkedHashMap()) { - this.owner = owner - } + private val styleNode get() = owner.properties?.get(STYLESHEET_KEY).node - public val items: Map get() = styleMap + public val items: Map? get() = styleNode?.items?.mapValues { it.value.node ?: Meta.EMPTY } - - private fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { - if (styles.contains(key)) { - //TODO optimize set concatenation - val tokens: Collection = - ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) - .map { it.asName() } - tokens.forEach { parent?.propertyChanged(it) } - } - if (this is VisionGroup) { - for (obj in this) { - obj.styleChanged(key, oldStyle, newStyle) - } - } - } - - public operator fun get(key: String): Meta? { - return styleMap[key] ?: owner?.parent?.styleSheet?.get(key) - } + public operator fun get(key: String): Meta? = owner.getStyle(key) /** * Define a style without notifying owner */ public fun define(key: String, style: Meta?) { if (style == null) { - styleMap.remove(key) + styleNode?.remove(key) } else { - styleMap[key] = style + owner.config[STYLESHEET_KEY + key] = style } } @@ -64,11 +32,13 @@ public class StyleSheet private constructor(private val styleMap: MutableMap Unit): Unit = this.block() + /** * Create and set a style */ @@ -77,33 +47,33 @@ public class StyleSheet private constructor(private val styleMap: MutableMap - update(key, value) - } +internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { + if (styles.contains(key)) { + //TODO optimize set concatenation + val tokens: Collection = + ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) + .map { it.asName() } + tokens.forEach { parent?.propertyChanged(it) } } - - public companion object : KSerializer { - private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer) - override val descriptor: SerialDescriptor get() = mapSerializer.descriptor - - - override fun deserialize(decoder: Decoder): StyleSheet { - val map = mapSerializer.deserialize(decoder) - return StyleSheet(map as? MutableMap ?: LinkedHashMap(map)) - } - - override fun serialize(encoder: Encoder, value: StyleSheet) { - mapSerializer.serialize(encoder, value.items) + if (this is VisionGroup) { + for (obj in this) { + obj.styleChanged(key, oldStyle, newStyle) } } } + +/** + * A stylesheet for this group and its descendants. Stylesheet is not applied directly, + * but instead is just a repository for named configurations. + */ +public val VisionGroup.styleSheet: StyleSheet get() = StyleSheet(this) + /** * Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment. */ @@ -111,12 +81,19 @@ public fun Vision.useStyle(name: String) { styles = (properties[Vision.STYLE_KEY]?.stringList ?: emptyList()) + name } + +/** + * Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision]. + */ +public tailrec fun Vision.getStyle(name: String): Meta? = + properties?.get(StyleSheet.STYLESHEET_KEY + name).node ?: parent?.getStyle(name) + /** * Resolve an item in all style layers */ public fun Vision.getStyleItems(name: Name): Sequence> { return styles.asSequence().map { - resolveStyle(it) + getStyle(it) }.map { it[name] }.filterNotNull() @@ -125,4 +102,4 @@ public fun Vision.getStyleItems(name: Name): Sequence> { /** * Collect all styles for this object in a single laminate */ -public val Vision.allStyles: Laminate get() = Laminate(styles.mapNotNull(::resolveStyle)) \ No newline at end of file +public val Vision.allStyles: Laminate get() = Laminate(styles.mapNotNull(::getStyle)) \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt index 5de49992..058a04b3 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt @@ -98,12 +98,6 @@ public fun Vision.setProperty(key: String, value: Any?) { config[key] = value } -/** - * Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision]. - */ -public tailrec fun Vision.resolveStyle(name: String): Meta? = - (this as? VisionGroup)?.styleSheet?.get(name) ?: parent?.resolveStyle(name) - /** * Control visibility of the element */ diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt index e52041fe..6127479c 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt @@ -34,7 +34,7 @@ public open class VisionBase : Vision { override val descriptor: NodeDescriptor? get() = null protected fun updateStyles(names: List) { - names.mapNotNull { resolveStyle(it) }.asSequence() + names.mapNotNull { getStyle(it) }.asSequence() .flatMap { it.items.asSequence() } .distinctBy { it.key } .forEach { diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt index 6fd1c559..fdfb9e7a 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroup.kt @@ -3,7 +3,7 @@ package hep.dataforge.vision import hep.dataforge.names.* import hep.dataforge.provider.Provider -public interface VisionContainer{ +public interface VisionContainer { public operator fun get(name: Name): V? } @@ -18,12 +18,6 @@ public interface VisionGroup : Provider, Vision, VisionContainer { override val defaultTarget: String get() = Vision.TYPE - /** - * A stylesheet for this group and its descendants. Stylesheet is not applied directly, - * but instead is just a repository for named configurations. - */ - public val styleSheet: StyleSheet? - /** * A map of direct children for specific target * (currently "visual" or "style") @@ -38,7 +32,7 @@ public interface VisionGroup : Provider, Vision, VisionContainer { } res.entries }.associate { it.toPair() } - STYLE_TARGET -> styleSheet?.items?.mapKeys { it.key.toName() } ?: emptyMap() + STYLE_TARGET -> styleSheet.items?.mapKeys { it.key.asName() } ?: emptyMap() else -> emptyMap() } @@ -54,7 +48,6 @@ public interface VisionGroup : Provider, Vision, VisionContainer { * A fix for serialization bug that writes all proper parents inside the tree after deserialization */ public fun attachChildren() { - styleSheet?.owner = this children.values.forEach { it.parent = this (it as? VisionGroup)?.attachChildren() @@ -73,7 +66,7 @@ public operator fun VisionGroup.iterator(): Iterator = children.values.i public val VisionGroup.isEmpty: Boolean get() = this.children.isEmpty() -public interface VisionContainerBuilder{ +public interface VisionContainerBuilder { public operator fun set(name: Name, child: V?) } @@ -97,9 +90,11 @@ public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder VisionContainer.get(str: String): V? = get(str.toName()) +public operator fun VisionContainer.get(str: String): V? = get(str.toName()) -public operator fun VisionContainerBuilder.set(token: NameToken, child: V?): Unit = set(token.asName(), child) -public operator fun VisionContainerBuilder.set(key: String, child: V?): Unit = set(key.toName(), child) +public operator fun VisionContainerBuilder.set(token: NameToken, child: V?): Unit = + set(token.asName(), child) + +public operator fun VisionContainerBuilder.set(key: String, child: V?): Unit = set(key.toName(), child) public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null } \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt index 947adafd..996b0853 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt @@ -26,19 +26,6 @@ public open class VisionGroupBase : VisionBase(), MutableVisionGroup { */ override val children: Map get() = childrenInternal - final override var styleSheet: StyleSheet? = null - private set - - /** - * Update or create stylesheet - */ - public open fun styleSheet(block: StyleSheet.() -> Unit) { - if (styleSheet == null) { - styleSheet = StyleSheet(this@VisionGroupBase) - } - styleSheet!!.block() - } - override fun propertyChanged(name: Name) { super.propertyChanged(name) for (obj in this) { diff --git a/visionforge-fx/src/main/kotlin/hep/dataforge/vision/editor/VisualObjectEditorFragment.kt b/visionforge-fx/src/main/kotlin/hep/dataforge/vision/editor/VisualObjectEditorFragment.kt index 5a559d4f..251130c2 100644 --- a/visionforge-fx/src/main/kotlin/hep/dataforge/vision/editor/VisualObjectEditorFragment.kt +++ b/visionforge-fx/src/main/kotlin/hep/dataforge/vision/editor/VisualObjectEditorFragment.kt @@ -5,7 +5,7 @@ import hep.dataforge.meta.Meta import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.update import hep.dataforge.vision.Vision -import hep.dataforge.vision.resolveStyle +import hep.dataforge.vision.getStyle import hep.dataforge.vision.setProperty import javafx.beans.binding.Binding import javafx.beans.property.SimpleObjectProperty @@ -55,7 +55,7 @@ class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() { private val styleBoxProperty: Binding = configProperty.objectBinding() { VBox().apply { item?.styles?.forEach { styleName -> - val styleMeta = item?.resolveStyle(styleName) + val styleMeta = item?.getStyle(styleName) if (styleMeta != null) { titledpane(styleName, node = MetaViewer(styleMeta).root) } diff --git a/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt b/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt index 583bbb03..d3dd5b3a 100644 --- a/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GDMLTransformer.kt @@ -10,6 +10,7 @@ import hep.dataforge.names.toName import hep.dataforge.vision.set import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY +import hep.dataforge.vision.styleSheet import hep.dataforge.vision.useStyle import kscience.gdml.* import kotlin.math.cos diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Composite.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Composite.kt index b7e670d1..75ce5b02 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Composite.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/Composite.kt @@ -3,7 +3,10 @@ package hep.dataforge.vision.solid import hep.dataforge.meta.update import hep.dataforge.names.NameToken -import hep.dataforge.vision.* +import hep.dataforge.vision.Vision +import hep.dataforge.vision.VisionContainerBuilder +import hep.dataforge.vision.VisionGroup +import hep.dataforge.vision.set import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -28,9 +31,6 @@ public class Composite( override val children: Map get() = mapOf(NameToken("first") to first, NameToken("second") to second) - - override val styleSheet: StyleSheet? - get() = null } public inline fun VisionContainerBuilder.composite( diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt index 3b58e11a..7829faef 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt @@ -103,10 +103,6 @@ internal class Prototypes( children: Map = emptyMap(), ) : VisionGroupBase(), PrototypeHolder { - override fun styleSheet(block: StyleSheet.() -> Unit) { - error("Can't define stylesheet for prototypes block") - } - init { this.childrenInternal.putAll(children) } diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt index 3895171e..4df85142 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt @@ -58,8 +58,6 @@ public class SolidReference( get() = (parent as? SolidGroup)?.getPrototype(templateName) ?: error("Prototype with name $templateName not found in $parent") - override val styleSheet: StyleSheet get() = parent?.styleSheet ?: StyleSheet(this) - @Transient private val propertyCache: HashMap = HashMap() @@ -90,8 +88,6 @@ public class SolidReference( override val prototype: Solid get() = prototypeFor(name) - override val styleSheet: StyleSheet get() = this@SolidReference.styleSheet - override val children: Map get() = (prototype as? VisionGroup)?.children ?.filter { !it.key.toString().startsWith("@") } diff --git a/visionforge-solid/src/commonTest/kotlin/hep/dataforge/vision/solid/PropertyTest.kt b/visionforge-solid/src/commonTest/kotlin/hep/dataforge/vision/solid/PropertyTest.kt index 7c80a6fb..3f89c024 100644 --- a/visionforge-solid/src/commonTest/kotlin/hep/dataforge/vision/solid/PropertyTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/hep/dataforge/vision/solid/PropertyTest.kt @@ -3,6 +3,7 @@ package hep.dataforge.vision.solid import hep.dataforge.meta.int import hep.dataforge.meta.set import hep.dataforge.names.asName +import hep.dataforge.vision.styleSheet import hep.dataforge.vision.useStyle import kotlin.test.Test import kotlin.test.assertEquals