diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt index fbeb84dd..8cc4c258 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/dRootToSolid.kt @@ -3,7 +3,6 @@ package ru.mipt.npm.root import space.kscience.dataforge.meta.double import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.int -import space.kscience.dataforge.meta.isEmpty import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.plus import space.kscience.dataforge.values.doubleArray @@ -322,7 +321,7 @@ private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid? } return if (group.children.isEmpty()) { null - } else if (group.items.size == 1 && group.meta.isEmpty()) { + } else if (group.items.size == 1 && group.meta== null) { group.items.values.first().apply { parent = null } } else { group diff --git a/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt b/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt index afb23f16..c46f49ff 100644 --- a/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt +++ b/demo/gdml/src/commonTest/kotlin/space/kscience/visionforge/gdml/GDMLVisionTest.kt @@ -6,7 +6,6 @@ import space.kscience.dataforge.values.asValue import space.kscience.gdml.GdmlShowCase import space.kscience.visionforge.Vision import space.kscience.visionforge.get -import space.kscience.visionforge.getProperty import space.kscience.visionforge.getPropertyValue import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.SolidMaterial diff --git a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt index 596b11dd..dff6da3f 100644 --- a/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt +++ b/demo/muon-monitor/src/commonMain/kotlin/ru/mipt/npm/muon/monitor/Model.kt @@ -3,7 +3,7 @@ package ru.mipt.npm.muon.monitor import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z -import space.kscience.visionforge.VisionContainerBuilder +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionManager import space.kscience.visionforge.setAsRoot import space.kscience.visionforge.solid.* @@ -14,7 +14,7 @@ class Model(val manager: VisionManager) { private val map = HashMap() private val events = HashSet() - private fun VisionContainerBuilder.pixel(pixel: SC1) { + private fun MutableVisionContainer.pixel(pixel: SC1) { val group = group(pixel.name) { position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z) box(pixel.xSize, pixel.ySize, pixel.zSize) diff --git a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt index 84a164c8..d429cafb 100644 --- a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt +++ b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt @@ -49,7 +49,7 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision onPropertyChange { name -> when { name == VALUE -> { - val value = meta.get(VALUE).int ?: 0 + val value = meta[VALUE].int ?: 0 val size = value.toFloat() / 255f * 20f mesh.scale.z = size.toDouble() mesh.position.z = size.toDouble() / 2 diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt index c6cba1ba..f6b38880 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt @@ -3,101 +3,105 @@ package space.kscience.visionforge import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.launch -import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName import kotlinx.serialization.Transient -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.meta.asMutableMeta +import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.get import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.values.Value -import space.kscience.visionforge.VisionGroup.Companion.updateProperties +import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties import kotlin.jvm.Synchronized -@Serializable + public abstract class AbstractVision : Vision { @Transient override var parent: Vision? = null - protected var properties: MutableMeta? = null + @SerialName("properties") + internal var _properties: MutableMeta? = null - override val meta: Meta get() = properties ?: Meta.EMPTY - - @Synchronized - private fun getOrCreateProperties(): MutableMeta { - if (properties == null) { - //TODO check performance issues - val newProperties = MutableMeta() - properties = newProperties - } - return properties!! - } + protected open val defaultProperties: Meta? get() = descriptor?.defaultNode @Transient - private val _propertyChanges = MutableSharedFlow() - override val propertyChanges: SharedFlow get() = _propertyChanges + final override val properties: MutableVisionProperties = object : MutableVisionProperties { + override val descriptor: MetaDescriptor? get() = this@AbstractVision.descriptor + override val default: Meta? get() = defaultProperties - override fun getPropertyValue( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): Value? { - properties?.get(name)?.value?.let { return it } - if (includeStyles) { - getStyleProperty(name)?.value?.let { return it } + @Synchronized + private fun getOrCreateProperties(): MutableMeta { + if (_properties == null) { + //TODO check performance issues + val newProperties = MutableMeta() + _properties = newProperties + } + return _properties!! } - if (inherit) { - parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } - } - if (includeDefaults) { - descriptor?.defaultNode?.get(name)?.value?.let { return it } - } - return null - } - override fun setProperty(name: Name, node: Meta?) { - //TODO check old value? - if (name.isEmpty()) { - properties = node?.asMutableMeta() - } else if (node == null) { - properties?.setMeta(name, node) - } else { - getOrCreateProperties().setMeta(name, node) - } - invalidateProperty(name) - } + override val raw: Meta? get() = _properties - override fun setPropertyValue(name: Name, value: Value?) { - //TODO check old value? - if (value == null) { - properties?.getMeta(name)?.value = null - } else { - getOrCreateProperties().setValue(name, value) + override fun getValue( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + ): Value? { + raw?.get(name)?.value?.let { return it } + if (includeStyles) { + getStyleProperty(name)?.value?.let { return it } + } + if (inherit) { + parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it } + } + return default?.get(name)?.value } - invalidateProperty(name) + + override fun set(name: Name, node: Meta?) { + //TODO check old value? + if (name.isEmpty()) { + _properties = node?.asMutableMeta() + } else if (node == null) { + _properties?.setMeta(name, node) + } else { + getOrCreateProperties().setMeta(name, node) + } + invalidate(name) + } + + override fun setValue(name: Name, value: Value?) { + //TODO check old value? + if (value == null) { + _properties?.getMeta(name)?.value = null + } else { + getOrCreateProperties().setValue(name, value) + } + invalidate(name) + } + + @Transient + private val _changes = MutableSharedFlow() + override val changes: SharedFlow get() = _changes + + override fun invalidate(propertyName: Name) { + if (propertyName == Vision.STYLE_KEY) { + styles.asSequence() + .mapNotNull { getStyle(it) } + .flatMap { it.items.asSequence() } + .distinctBy { it.key } + .forEach { + invalidate(it.key.asName()) + } + } + manager.context.launch { + _changes.emit(propertyName) + } + } + } override val descriptor: MetaDescriptor? get() = null - override fun invalidateProperty(propertyName: Name) { - if (propertyName == Vision.STYLE_KEY) { - styles.asSequence() - .mapNotNull { getStyle(it) } - .flatMap { it.items.asSequence() } - .distinctBy { it.key } - .forEach { - invalidateProperty(it.key.asName()) - } - } - manager.context.launch { - _propertyChanges.emit(propertyName) - } - } override fun update(change: VisionChange) { change.properties?.let { diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt index cc465d87..aed19706 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt @@ -15,7 +15,7 @@ import kotlin.jvm.JvmInline @JvmInline public value class StyleSheet(private val owner: Vision) { - private val styleNode: Meta get() = owner.getProperty(STYLESHEET_KEY) + private val styleNode: Meta get() = owner.properties[STYLESHEET_KEY] public val items: Map get() = styleNode.items @@ -25,7 +25,7 @@ public value class StyleSheet(private val owner: Vision) { * Define a style without notifying owner */ public fun define(key: String, style: Meta?) { - owner.setProperty(STYLESHEET_KEY + key, style) + owner.properties[STYLESHEET_KEY + key] = style } /** @@ -58,26 +58,24 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) val tokens: Collection = ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) .map { it.asName() } - tokens.forEach { parent?.invalidateProperty(it) } + tokens.forEach { parent?.properties?.invalidate(it) } } - children.values.forEach { vision -> + children?.forEach { _, vision -> vision.styleChanged(key, oldStyle, newStyle) } } - /** * List of names of styles applied to this object. Order matters. Not inherited. */ public var Vision.styles: List - get() = getPropertyValue( + get() = properties.getValue( Vision.STYLE_KEY, inherit = true, includeStyles = false, - includeDefaults = false )?.stringList ?: emptyList() set(value) { - setPropertyValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) + properties.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) } /** @@ -90,7 +88,7 @@ public val Vision.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. */ public fun Vision.useStyle(name: String) { - styles = (getPropertyValue(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name + styles = (properties.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name } @@ -98,7 +96,7 @@ public fun Vision.useStyle(name: String) { * Resolve a style with given name for given [Vision]. The style is not necessarily applied to this [Vision]. */ public fun Vision.getStyle(name: String): Meta? = - meta.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name) + properties.raw?.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name) /** * Resolve a property from all styles diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt index b25f200c..e538b226 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt @@ -1,22 +1,15 @@ package space.kscience.visionforge import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import space.kscience.dataforge.context.Global -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.meta.MutableMetaProvider import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.misc.Type import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.startsWith -import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.boolean import space.kscience.visionforge.Vision.Companion.TYPE @@ -38,49 +31,8 @@ public interface Vision : Described { */ public val manager: VisionManager get() = parent?.manager ?: Global.visionManager - public val children: VisionChildren - /** - * Own properties without inheritance or styles. - */ - public val meta: Meta - - public fun getPropertyValue( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): Value? - - /** - * Get property with given layer flags. - * @param inherit toggles parent node property lookup. Null means inference from descriptor. - * @param includeStyles toggles inclusion of properties from styles. - */ - public fun getProperty( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): MutableMeta = VisionProperties(this, name, descriptor?.get(name), inherit, includeStyles) - - public fun setProperty( - name: Name, - node: Meta?, - ) - - public fun setPropertyValue( - name: Name, - value: Value?, - ) - - public val propertyChanges: SharedFlow - - /** - * Notify all listeners that a property has been changed and should be invalidated. - * This method does not check that the property has actually changed. - */ - public fun invalidateProperty(propertyName: Name) + public val properties: MutableVisionProperties /** * Update this vision using a dif represented by [VisionChange]. @@ -98,108 +50,19 @@ public interface Vision : Described { } } -public fun Vision.getPropertyValue( - name: Name, - inherit: Boolean? = null, - includeStyles: Boolean? = null, - includeDefaults: Boolean = true, - metaDescriptor: MetaDescriptor? = descriptor?.get(name), -): Value? { - val inheritFlag = inherit ?: metaDescriptor?.inherited ?: false - val stylesFlag = includeStyles ?: metaDescriptor?.usesStyles ?: true - return getPropertyValue(name, inheritFlag, stylesFlag, includeDefaults) -} - -public fun Vision.getPropertyValue( - name: String, - inherit: Boolean? = null, - includeStyles: Boolean? = null, - includeDefaults: Boolean = true, - metaDescriptor: MetaDescriptor? = descriptor?.get(name), -): Value? = getPropertyValue(name.parseAsName(), inherit, includeStyles, includeDefaults, metaDescriptor) - -/** - * Compute the property based on the provided value descriptor. By default, use Vision own descriptor - */ -public fun Vision.getProperty( - name: Name, - inherit: Boolean? = null, - includeStyles: Boolean? = null, - includeDefaults: Boolean = true, - metaDescriptor: MetaDescriptor? = descriptor?.get(name), -): MutableMeta { - val inheritFlag = inherit ?: metaDescriptor?.inherited ?: false - val stylesFlag = includeStyles ?: metaDescriptor?.usesStyles ?: true - return getProperty(name, inheritFlag, stylesFlag, includeDefaults) -} - - -/** - * Get [Vision] property using key as a String - */ -public fun Vision.getProperty( - name: String, - inherit: Boolean? = null, - includeStyles: Boolean? = null, - includeDefaults: Boolean = true, - metaDescriptor: MetaDescriptor? = descriptor?.get(name), -): MutableMeta = getProperty(name.parseAsName(), inherit, includeStyles, includeDefaults, metaDescriptor) - - -/** - * Vision's own non-inheritable, non-styleable properties - */ -public fun Vision.properties( - inherit: Boolean? = null, - useStyles: Boolean? = null, -): MutableMetaProvider = VisionProperties(this, Name.EMPTY, inherit = inherit, useStyles = useStyles) - -public fun Vision.setPropertyValue(name: Name, value: Number?) { - if (value == null) { - setPropertyValue(name, null) - } else { - setPropertyValue(name, value.asValue()) - } -} - -public fun Vision.setPropertyValue(name: String, value: Number?): Unit = - setPropertyValue(name.parseAsName(), value) - -public fun Vision.setPropertyValue(name: Name, value: Boolean?) { - if (value == null) { - setPropertyValue(name, null) - } else { - setPropertyValue(name, value.asValue()) - } -} - -public fun Vision.setPropertyValue(name: String, value: Boolean?): Unit = - setPropertyValue(name.parseAsName(), value) - -public fun Vision.setPropertyValue(name: Name, value: String?) { - if (value == null) { - setPropertyValue(name, null) - } else { - setPropertyValue(name, value.asValue()) - } -} - -public fun Vision.setPropertyValue(name: String, value: String?): Unit = - setPropertyValue(name.parseAsName(), value) - /** * Control visibility of the element */ public var Vision.visible: Boolean? - get() = getPropertyValue(Vision.VISIBLE_KEY)?.boolean + get() = properties.getValue(Vision.VISIBLE_KEY)?.boolean set(value) { - setPropertyValue(Vision.VISIBLE_KEY, value) + properties.setValue(Vision.VISIBLE_KEY, value?.asValue()) } /** * Subscribe on property updates. The subscription is bound to the given scope and canceled when the scope is canceled */ -public fun Vision.onPropertyChange(callback: (Name) -> Unit): Job = propertyChanges.onEach { +public fun Vision.onPropertyChange(callback: (Name) -> Unit): Job = properties.changes.onEach { callback(it) }.launchIn(manager.context) @@ -210,17 +73,9 @@ public fun V.useProperty( ): Job { //Pass initial value. callBack(property.get(this)) - return propertyChanges.onEach { name -> + return properties.changes.onEach { name -> if (name.startsWith(property.name.asName())) { callBack(property.get(this@useProperty)) } }.launchIn(manager.context) -} - - -public interface MutableVisionGroup : Vision { - - override val children: MutableVisionChildren - - public fun createGroup(): MutableVisionGroup -} +} \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt index abea638a..a4667b2f 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionChange.kt @@ -26,7 +26,7 @@ private fun Vision.deepCopy(): Vision { /** * An update for a [Vision] */ -public class VisionChangeBuilder : VisionContainerBuilder { +public class VisionChangeBuilder : MutableVisionContainer { private var reset: Boolean = false private var vision: Vision? = null @@ -77,7 +77,7 @@ public class VisionChangeBuilder : VisionContainerBuilder { public data class VisionChange( public val delete: Boolean = false, public val vision: Vision? = null, - @Serializable(MetaSerializer::class) public val properties: Meta? = null, + public val properties: Meta? = null, public val children: Map? = null, ) @@ -93,25 +93,25 @@ private fun CoroutineScope.collectChange( //Collect properties change source.onPropertyChange { propertyName -> - val newItem = source.getProperty(propertyName, false, false, false) + val newItem = source.properties.raw?.get(propertyName) collector().propertyChanged(name, propertyName, newItem) } val children = source.children //Subscribe for children changes - for ((token, child) in children) { + children?.forEach { token, child -> collectChange(name + token, child, collector) } //Subscribe for structure change - children.changes.onEach { changedName -> + children?.changes?.onEach { changedName -> val after = children[changedName] val fullName = name + changedName if (after != null) { collectChange(fullName, after, collector) } collector()[fullName] = after - }.launchIn(this) + }?.launchIn(this) } /** diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt index f7056d59..81f7d9da 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt @@ -19,7 +19,7 @@ public interface VisionContainer { public operator fun get(name: Name): V? } -public interface VisionContainerBuilder { +public interface MutableVisionContainer { //TODO add documentation public operator fun set(name: Name?, child: V?) } @@ -28,7 +28,7 @@ public interface VisionContainerBuilder { * A serializable representation of [Vision] children container */ public interface VisionChildren : VisionContainer { - public val parent: Vision? + public val group: Vision? public val keys: Set @@ -39,14 +39,14 @@ public interface VisionChildren : VisionContainer { public operator fun get(token: NameToken): Vision? override fun get(name: Name): Vision? = when (name.length) { - 0 -> parent + 0 -> group 1 -> get(name.first()) else -> get(name.first())?.children?.get(name.cutFirst()) } public companion object { public fun empty(owner: Vision): VisionChildren = object : VisionChildren { - override val parent: Vision get() = owner + override val group: Vision get() = owner override val keys: Set get() = emptySet() override val changes: Flow get() = emptyFlow() override fun get(token: NameToken): Vision? = null @@ -56,9 +56,13 @@ public interface VisionChildren : VisionContainer { public fun VisionChildren.isEmpty(): Boolean = keys.isEmpty() +public inline fun VisionChildren.forEach(block: (NameToken, Vision) -> Unit) { + keys.forEach { block(it, get(it)!!) } +} + @Serializable(VisionChildrenContainerSerializer::class) -public interface MutableVisionChildren : VisionChildren, VisionContainerBuilder { - public override val parent: MutableVisionGroup? +public interface MutableVisionChildren : VisionChildren, MutableVisionContainer { + public override val group: MutableVisionGroup? public operator fun set(token: NameToken, value: Vision?) @@ -79,7 +83,7 @@ public interface MutableVisionChildren : VisionChildren, VisionContainerBuilder< else -> { val currentParent = get(name.first()) if (currentParent != null && currentParent !is MutableVisionGroup) error("Can't assign a child to $currentParent") - val parent: MutableVisionGroup = currentParent as? MutableVisionGroup ?: parent?.createGroup().also { + val parent: MutableVisionGroup = currentParent as? MutableVisionGroup ?: group?.createGroup().also { set(name.first(), it) } ?: error("Container owner not set") parent.children[name.cutFirst()] = child @@ -105,7 +109,7 @@ public operator fun VisionChildren.iterator(): Iterator> public operator fun VisionContainer.get(str: String): V? = get(Name.parse(str)) -public operator fun VisionContainerBuilder.set( +public operator fun MutableVisionContainer.set( str: String?, vision: V?, ): Unit = set(str?.parseAsName(), vision) @@ -113,13 +117,13 @@ internal class VisionChildrenImpl( items: Map, ) : MutableVisionChildren { - override var parent: MutableVisionGroup? = null + override var group: MutableVisionGroup? = null internal set private val items = LinkedHashMap(items) private val updateJobs = HashMap() - private val scope: CoroutineScope? get() = parent?.manager?.context + private val scope: CoroutineScope? get() = group?.manager?.context override val keys: Set get() = items.keys @@ -149,9 +153,9 @@ internal class VisionChildrenImpl( } else { items[token] = value //check if parent already exists and is different from the current one - if (value.parent != null && value.parent != parent) error("Can't reassign parent Vision for $value") + if (value.parent != null && value.parent != group) error("Can't reassign parent Vision for $value") //set parent - value.parent = parent + value.parent = group //start update jobs (only if the vision is rooted) scope?.let { scope -> val job = (value.children as? VisionChildrenImpl)?.changes?.onEach { @@ -179,7 +183,7 @@ internal class VisionChildrenImpl( } internal object VisionChildrenContainerSerializer : KSerializer { - private val mapSerializer = serializer>() + private val mapSerializer = serializer>() override val descriptor: SerialDescriptor = mapSerializer.descriptor diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt index 3c843b85..f87650a7 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt @@ -13,20 +13,33 @@ import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.plus import space.kscience.dataforge.values.ValueType import space.kscience.visionforge.Vision.Companion.STYLE_KEY +import kotlin.js.JsName import kotlin.jvm.Synchronized + +public interface VisionGroup : Vision { + public val children: VisionChildren +} + +public interface MutableVisionGroup : VisionGroup { + + override val children: MutableVisionChildren + + public fun createGroup(): MutableVisionGroup +} + +public val Vision.children: VisionChildren? get() = (this as? VisionGroup)?.children + /** * A full base implementation for a [Vision] */ -@Serializable -@SerialName("vision.group") -public open class VisionGroup : AbstractVision(), MutableVisionGroup { +public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup { override fun update(change: VisionChange) { change.children?.forEach { (name, change) -> when { - change.delete -> children.set(name, null) - change.vision != null -> children.set(name, change.vision) + change.delete -> children[name] = null + change.vision != null -> children[name] = change.vision else -> children[name]?.update(change) } } @@ -45,13 +58,13 @@ public open class VisionGroup : AbstractVision(), MutableVisionGroup { fun getOrCreateChildren(): MutableVisionChildren { if (_children == null) { _children = VisionChildrenImpl(emptyMap()).apply { - parent = this@VisionGroup + group = this@AbstractVisionGroup } } return _children!! } - override val parent: MutableVisionGroup get() = this@VisionGroup + override val group: MutableVisionGroup get() = this@AbstractVisionGroup override val keys: Set get() = _children?.keys ?: emptySet() override val changes: Flow get() = _children?.changes ?: emptyFlow() @@ -71,7 +84,7 @@ public open class VisionGroup : AbstractVision(), MutableVisionGroup { } } - override fun createGroup(): VisionGroup = VisionGroup() + abstract override fun createGroup(): AbstractVisionGroup public companion object { public val descriptor: MetaDescriptor = MetaDescriptor { @@ -80,16 +93,28 @@ public open class VisionGroup : AbstractVision(), MutableVisionGroup { } } - public fun Vision.updateProperties(item: Meta, at: Name = Name.EMPTY) { - setPropertyValue(at, item.value) + public fun Vision.updateProperties(item: Meta, name: Name = Name.EMPTY) { + properties.setValue(name, item.value) item.items.forEach { (token, item) -> - updateProperties(item, at + token) + updateProperties(item, name + token) } } } } +/** + * A simple vision group that just holds children. Nothing else. + */ +@Serializable +@SerialName("vision.group") +public class SimpleVisionGroup : AbstractVisionGroup() { + override fun createGroup(): SimpleVisionGroup = SimpleVisionGroup() +} + +@JsName("createVisionGroup") +public fun VisionGroup(): VisionGroup = SimpleVisionGroup() + //fun VisualObject.findStyle(styleName: Name): Meta? { // if (this is VisualGroup) { // val style = resolveStyle(styleName) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt index a11ad358..3428dd33 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionManager.kt @@ -68,8 +68,8 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) { private val defaultSerialModule: SerializersModule = SerializersModule { polymorphic(Vision::class) { - default { VisionGroup.serializer() } - subclass(VisionGroup.serializer()) + default { SimpleVisionGroup.serializer() } + subclass(SimpleVisionGroup.serializer()) subclass(VisionOfNumberField.serializer()) subclass(VisionOfTextField.serializer()) subclass(VisionOfCheckbox.serializer()) @@ -112,7 +112,9 @@ public fun Vision.encodeToString(): String = manager.encodeToString(this) /** * A root vision attached to [VisionManager] */ -public class RootVision(override val manager: VisionManager) : VisionGroup() +public class RootVision(override val manager: VisionManager) : AbstractVisionGroup() { + override fun createGroup(): SimpleVisionGroup = SimpleVisionGroup() +} /** * Designate this [Vision] as a root and assign a [VisionManager] as its parent diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt index 140170d3..b4ca16ec 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt @@ -1,40 +1,104 @@ package space.kscience.visionforge +import kotlinx.coroutines.flow.Flow import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.get +import space.kscience.dataforge.meta.get import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken +import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.plus import space.kscience.dataforge.values.Value +import space.kscience.dataforge.values.asValue -/** - * A wrapper that emulates delegates reading and writing properties to Vision method - */ -internal class VisionProperties( - val vision: Vision, +public interface VisionProperties { + + /** + * Raw Visions own properties without styles, defaults, etc. + */ + public val raw: Meta? + + public val descriptor: MetaDescriptor? + public val default: Meta? + + public fun getValue( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + ): Value? + + /** + * Get property with given layer flags. + * @param inherit toggles parent node property lookup. Null means inference from descriptor. + * @param includeStyles toggles inclusion of properties from styles. + */ + public operator fun get( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + ): Meta + + public val changes: Flow + + /** + * Notify all listeners that a property has been changed and should be invalidated. + * This method does not check that the property has actually changed. + */ + public fun invalidate(propertyName: Name) +} + +public interface MutableVisionProperties : VisionProperties { + + override operator fun get( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + ): MutableMeta = VisionPropertiesItem( + this, + name, + inherit, + includeStyles, + ) + + + public operator fun set( + name: Name, + node: Meta?, + ) + + public fun setValue( + name: Name, + value: Value?, + ) +} + +private class VisionPropertiesItem( + val properties: MutableVisionProperties, val nodeName: Name, - val visionDescriptor: MetaDescriptor? = vision.descriptor, val inherit: Boolean? = null, val useStyles: Boolean? = null, + val default: Meta? = null, ) : MutableMeta { - val descriptor: MetaDescriptor? by lazy { visionDescriptor?.get(nodeName) } + val descriptor: MetaDescriptor? by lazy { properties.descriptor?.get(nodeName) } + override val items: Map get() { - val metaKeys = vision.meta.getMeta(nodeName)?.items?.keys ?: emptySet() + val metaKeys = properties.raw?.getMeta(nodeName)?.items?.keys ?: emptySet() val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet() + val defaultKeys = default?.get(nodeName)?.items?.keys ?: emptySet() val inheritFlag = descriptor?.inherited ?: inherit val stylesFlag = descriptor?.usesStyles ?: useStyles - return (metaKeys + descriptorKeys).associateWith { - VisionProperties( - vision, + return (metaKeys + descriptorKeys + defaultKeys).associateWith { + VisionPropertiesItem( + properties, nodeName + it, - visionDescriptor, inheritFlag, - stylesFlag + stylesFlag, + default ) } } @@ -43,22 +107,22 @@ internal class VisionProperties( get() { val inheritFlag = descriptor?.inherited ?: inherit ?: false val stylesFlag = descriptor?.usesStyles ?: useStyles ?: true - return vision.getPropertyValue(nodeName, inheritFlag, stylesFlag, true) + return properties.getValue(nodeName, inheritFlag, stylesFlag) ?: default?.getValue(nodeName) } set(value) { - vision.setPropertyValue(nodeName, value) + properties.setValue(nodeName, value) } - override fun getOrCreate(name: Name): MutableMeta = VisionProperties( - vision, + override fun getOrCreate(name: Name): MutableMeta = VisionPropertiesItem( + properties, nodeName + name, - visionDescriptor, inherit, - useStyles + useStyles, + default ) override fun setMeta(name: Name, node: Meta?) { - vision.setProperty(nodeName + name, node) + properties[nodeName + name] = node } override fun toString(): String = Meta.toString(this) @@ -66,16 +130,96 @@ internal class VisionProperties( override fun hashCode(): Int = Meta.hashCode(this) } -///** -// * Accessor to all vision properties -// */ -//public fun Vision.computePropertyValues( -// descriptor: MetaDescriptor? = this.descriptor, -//): MutableValueProvider = object : MutableValueProvider { -// override fun getValue(name: Name): Value? = computeProperty(name, descriptor?.get(name))?.value -// -// override fun setValue(name: Name, value: Value?) { -// setProperty(name, value) -// } -//} +public fun VisionProperties.getValue( + name: Name, + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): Value? { + val descriptor = descriptor?.get(name) + val inheritFlag = inherit ?: descriptor?.inherited ?: false + val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true + return getValue(name, inheritFlag, stylesFlag) +} + +public fun VisionProperties.getValue( + name: String, + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): Value? = getValue(name.parseAsName(), inherit, includeStyles) + +/** + * Compute the property based on the provided value descriptor. By default, use Vision own descriptor + */ +public operator fun VisionProperties.get( + name: Name, + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): Meta { + val descriptor: MetaDescriptor? = descriptor?.get(name) + val inheritFlag = inherit ?: descriptor?.inherited ?: false + val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true + return get(name, inheritFlag, stylesFlag) +} + + +/** + * Get [Vision] property using key as a String + */ +public operator fun VisionProperties.get( + name: String, + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): Meta = get(name.parseAsName(), inherit, includeStyles) + + +/** + * Compute the property based on the provided value descriptor. By default, use Vision own descriptor + */ +public operator fun MutableVisionProperties.get( + name: Name, + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): MutableMeta { + val descriptor: MetaDescriptor? = descriptor?.get(name) + val inheritFlag = inherit ?: descriptor?.inherited ?: false + val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true + return get(name, inheritFlag, stylesFlag) +} + +/** + * The root property node with given inheritance and style flags + */ +public fun MutableVisionProperties.root( + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): MutableMeta = get(Name.EMPTY, inherit, includeStyles) + + +/** + * Get [Vision] property using key as a String + */ +public operator fun MutableVisionProperties.get( + name: String, + inherit: Boolean? = null, + includeStyles: Boolean? = null, +): MutableMeta = get(name.parseAsName(), inherit, includeStyles) + + +public operator fun MutableVisionProperties.set(name: Name, value: Number): Unit = + setValue(name, value.asValue()) + +public operator fun MutableVisionProperties.set(name: String, value: Number): Unit = + set(name.parseAsName(), value) + +public operator fun MutableVisionProperties.set(name: Name, value: Boolean): Unit = + setValue(name, value.asValue()) + +public operator fun MutableVisionProperties.set(name: String, value: Boolean): Unit = + set(name.parseAsName(), value) + +public operator fun MutableVisionProperties.set(name: Name, value: String): Unit = + setValue(name, value.asValue()) + +public operator fun MutableVisionProperties.set(name: String, value: String): Unit = + set(name.parseAsName(), value) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt deleted file mode 100644 index 83b6c93c..00000000 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionPropertyContainer.kt +++ /dev/null @@ -1,29 +0,0 @@ -package space.kscience.visionforge - -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.names.Name - -/** - * Property containers are used to create a symmetric behaviors for vision properties and style builders - */ -public interface VisionPropertyContainer { - - public fun getProperty( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): Meta? -} - -public open class SimpleVisionPropertyContainer( - public val meta: MutableMeta, -) : VisionPropertyContainer { - override fun getProperty( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): Meta? = meta.getMeta(name) -} \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt index 82e59c2c..4315066a 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt @@ -9,14 +9,13 @@ import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.node -import space.kscience.visionforge.properties @Serializable @SerialName("html.form") public class VisionOfHtmlForm( public val formId: String, ) : VisionOfHtmlInput() { - public var values: Meta? by properties().node() + public var values: Meta? by mutableProperties.node() } public class HtmlFormFragment internal constructor( diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt index 34f49027..19106240 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlInput.kt @@ -5,12 +5,15 @@ import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.number import space.kscience.dataforge.meta.string -import space.kscience.visionforge.VisionGroup -import space.kscience.visionforge.properties +import space.kscience.dataforge.names.Name +import space.kscience.visionforge.* + +//TODO replace by something +internal val Vision.mutableProperties get() = properties[Name.EMPTY, false, false] @Serializable -public abstract class VisionOfHtmlInput : VisionGroup() { - public var disabled: Boolean by properties().boolean(false) +public abstract class VisionOfHtmlInput : AbstractVision() { + public var disabled: Boolean by mutableProperties.boolean { false } } @Serializable @@ -19,7 +22,7 @@ public class VisionOfTextField( public val label: String? = null, public val name: String? = null, ) : VisionOfHtmlInput() { - public var text: String? by properties().string() + public var text: String? by mutableProperties.string() } @Serializable @@ -28,7 +31,7 @@ public class VisionOfCheckbox( public val label: String? = null, public val name: String? = null, ) : VisionOfHtmlInput() { - public var checked: Boolean? by properties().boolean() + public var checked: Boolean? by mutableProperties.boolean() } @Serializable @@ -37,7 +40,7 @@ public class VisionOfNumberField( public val label: String? = null, public val name: String? = null, ) : VisionOfHtmlInput() { - public var value: Number? by properties().number() + public var value: Number? by mutableProperties.number() } @Serializable @@ -49,6 +52,6 @@ public class VisionOfRangeField( public val label: String? = null, public val name: String? = null, ) : VisionOfHtmlInput() { - public var value: Number? by properties().number() + public var value: Number? by mutableProperties.number() } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDelegates.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDelegates.kt deleted file mode 100644 index 185c98a9..00000000 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visionDelegates.kt +++ /dev/null @@ -1,91 +0,0 @@ -package space.kscience.visionforge - -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.values.Value -import space.kscience.dataforge.values.number -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty - -//public fun Vision.propertyNode( -// name: Name? = null, -// inherit: Boolean = false, -// includeStyles: Boolean = true, -// includeDefaults: Boolean = true, -//): ReadWriteProperty = object : ReadWriteProperty { -// override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? = -// getProperty(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults) -// -// override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) { -// meta.setMeta(name ?: Name.parse(property.name), value) -// } -//} -// -//public fun Vision.propertyNode( -// converter: MetaConverter, -// name: Name? = null, -// inherit: Boolean = false, -// includeStyles: Boolean = true, -// includeDefaults: Boolean = true, -//): ReadWriteProperty = object : ReadWriteProperty { -// override fun getValue(thisRef: Any?, property: KProperty<*>): T? = getProperty( -// name ?: Name.parse(property.name), -// inherit, -// includeStyles, -// includeDefaults -// )?.let(converter::metaToObject) -// -// override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { -// meta.setMeta(name ?: Name.parse(property.name), value?.let(converter::objectToMeta)) -// } -//} - -public fun Vision.propertyValue( - name: Name? = null, - inherit: Boolean = false, - includeStyles: Boolean = true, - includeDefaults: Boolean = true, -): ReadWriteProperty = object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): Value? = - getPropertyValue(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults) - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { - setPropertyValue(name ?: Name.parse(property.name), value) - } -} - -public fun Vision.propertyValue( - name: Name? = null, - inherit: Boolean = false, - includeStyles: Boolean = true, - includeDefaults: Boolean = true, - setter: (T) -> Value? = { it?.let(Value::of) }, - getter: (Value?) -> T, -): ReadWriteProperty = object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T = getPropertyValue( - name ?: Name.parse(property.name), - inherit, - includeStyles, - includeDefaults - ).let(getter) - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { - setPropertyValue(name ?: Name.parse(property.name), value?.let(setter)) - } -} - -public fun Vision.numberProperty( - name: Name? = null, - inherit: Boolean = false, - includeStyles: Boolean = true, - includeDefaults: Boolean = true -): ReadWriteProperty = propertyValue(name, inherit, includeStyles, includeDefaults) { it?.number } - -public fun Vision.numberProperty( - name: Name? = null, - inherit: Boolean = false, - includeStyles: Boolean = true, - includeDefaults: Boolean = true, - default: () -> Number -): ReadWriteProperty = propertyValue(name, inherit, includeStyles, includeDefaults) { - it?.number ?: default() -} \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visitor/VisionVisitor.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visitor/VisionVisitor.kt index 3ba313a9..4ceab3d9 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visitor/VisionVisitor.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/visitor/VisionVisitor.kt @@ -6,7 +6,8 @@ import kotlinx.coroutines.launch import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.plus import space.kscience.visionforge.Vision -import space.kscience.visionforge.iterator +import space.kscience.visionforge.children +import space.kscience.visionforge.forEach public interface VisionVisitor { /** @@ -37,7 +38,7 @@ public interface VisionVisitor { visionVisitor.visitChildren(name, vision) - for ((token, child) in vision.children) { + vision.children?.forEach { token, child -> visitTreeAsync(visionVisitor, name + token, child) } } diff --git a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt index b7b8208d..d6128963 100644 --- a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt +++ b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt @@ -30,9 +30,10 @@ fun FlowContent.renderVisionFragment( @DFExperimental -class HtmlTagTest { +private fun VisionOutput.base(block: VisionGroup.() -> Unit) = VisionGroup().apply(block) - fun VisionOutput.base(block: VisionGroup.() -> Unit) = VisionGroup().apply(block) +@DFExperimental +class HtmlTagTest { val fragment: HtmlVisionFragment = { div { @@ -42,8 +43,8 @@ class HtmlTagTest { "metaProperty" put 87 } base { - setPropertyValue("myProp", 82) - setPropertyValue("otherProp", false) + properties["myProp"] = 82 + properties["otherProp"] = false } } } @@ -53,7 +54,7 @@ class HtmlTagTest { div { h2 { +"Properties" } ul { - vision.getProperty(Name.EMPTY).items.forEach { + vision.properties.raw?.items?.forEach { li { a { +it.key.toString() } p { +it.value.toString() } diff --git a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt index 234d0043..f488bcf7 100644 --- a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt +++ b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/meta/VisionPropertyTest.kt @@ -8,45 +8,47 @@ import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.boolean import space.kscience.dataforge.values.int import space.kscience.visionforge.VisionGroup -import space.kscience.visionforge.getProperty -import space.kscience.visionforge.getPropertyValue -import space.kscience.visionforge.setPropertyValue +import space.kscience.visionforge.get +import space.kscience.visionforge.getValue +import space.kscience.visionforge.set import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals -class VisionPropertyTest { - @Test - fun testPropertyWrite(){ - val vision = VisionGroup() - vision.setPropertyValue("fff", 2) - vision.setPropertyValue("fff.ddd", false) - assertEquals(2, vision.getPropertyValue("fff")?.int) - assertEquals(false, vision.getPropertyValue("fff.ddd")?.boolean) +private class TestScheme : Scheme() { + var ddd by int() + + companion object : SchemeSpec(::TestScheme) +} + +internal class VisionPropertyTest { + @Test + fun testPropertyWrite() { + val vision = VisionGroup() + vision.properties["fff"] = 2 + vision.properties["fff.ddd"] = false + + assertEquals(2, vision.properties.getValue("fff")?.int) + assertEquals(false, vision.properties.getValue("fff.ddd")?.boolean) } @Test - fun testPropertyEdit(){ + fun testPropertyEdit() { val vision = VisionGroup() - vision.getProperty("fff.ddd").apply { + vision.properties["fff.ddd"].apply { value = 2.asValue() } - assertEquals(2, vision.getPropertyValue("fff.ddd")?.int) - assertNotEquals(true, vision.getPropertyValue("fff.ddd")?.boolean) - } - - internal class TestScheme: Scheme(){ - var ddd by int() - companion object: SchemeSpec(::TestScheme) + assertEquals(2, vision.properties.getValue("fff.ddd")?.int) + assertNotEquals(true, vision.properties.getValue("fff.ddd")?.boolean) } @Test - fun testPropertyUpdate(){ + fun testPropertyUpdate() { val vision = VisionGroup() - vision.getProperty("fff").updateWith(TestScheme){ + vision.properties["fff"].updateWith(TestScheme) { ddd = 2 } - assertEquals(2, vision.getPropertyValue("fff.ddd")?.int) + assertEquals(2, vision.properties.getValue("fff.ddd")?.int) } } \ No newline at end of file diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt index 7b1299f4..0185dc43 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/editor/VisionEditorFragment.kt @@ -9,7 +9,6 @@ import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.names.Name import space.kscience.visionforge.Vision -import space.kscience.visionforge.getProperty import space.kscience.visionforge.getStyle import space.kscience.visionforge.styles import tornadofx.* diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt index cd45c6e1..90c94b35 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/FX3DPlugin.kt @@ -16,7 +16,6 @@ import space.kscience.dataforge.context.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.misc.Type -import space.kscience.visionforge.getProperty import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY @@ -77,7 +76,7 @@ public class FX3DPlugin : AbstractPlugin() { is PolyLine -> PolyLine3D( obj.points.map { Point3D(it.x, it.y, it.z) }, obj.thickness.toFloat(), - obj.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).color() + obj.get(SolidMaterial.MATERIAL_COLOR_KEY).color() ).apply { this.meshView.cullFace = CullFace.FRONT } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt index 680033d4..78d02164 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/VisualObjectFXBinding.kt @@ -7,7 +7,6 @@ import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.values.Value import space.kscience.visionforge.Vision -import space.kscience.visionforge.getProperty import space.kscience.visionforge.onPropertyChange import tornadofx.* diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt index afc6c99a..b2dbce57 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/markLayers.kt @@ -76,7 +76,7 @@ public fun SolidGroup.markLayers(thresholds: List = listOf(500, 1000, 20000 node.vision.layer = layerIndex remaining -= node.selfCount * (node.children.size + 1) - logger?.apply { + logger.run { if (node.selfCount > 1) { info { "Prototype with name ${node.name} moved to layer $layerIndex. $remaining nodes remains" } } else { diff --git a/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt b/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt index 880a1961..732358bf 100644 --- a/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt +++ b/visionforge-plotly/src/commonMain/kotlin/space/kscience/visionforge/plotly/VisionOfPlotly.kt @@ -7,13 +7,12 @@ import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.plotly.Plot import space.kscience.plotly.Plotly -import space.kscience.visionforge.VisionGroup -import space.kscience.visionforge.getProperty +import space.kscience.visionforge.AbstractVision import space.kscience.visionforge.html.VisionOutput @Serializable @SerialName("vision.plotly") -public class VisionOfPlotly private constructor() : VisionGroup() { +public class VisionOfPlotly private constructor() : AbstractVision() { public constructor(plot: Plot) : this() { setProperty(Name.EMPTY, plot.meta) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt index 39b7e7b0..62a3b2a0 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt @@ -7,7 +7,7 @@ import space.kscience.dataforge.values.* import space.kscience.visionforge.Colors import space.kscience.visionforge.Vision import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.getProperty +import space.kscience.visionforge.root import kotlin.properties.ReadOnlyProperty @VisionBuilder @@ -29,7 +29,7 @@ public class ColorAccessor( } public fun Vision.color(): ReadOnlyProperty = ReadOnlyProperty { _, property -> - ColorAccessor(getProperty(Name.EMPTY), property.name.asName()) + ColorAccessor(properties.root(), property.name.asName()) } public var ColorAccessor?.string: String? diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt index d300b06b..f30c641b 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Composite.kt @@ -2,7 +2,6 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.dataforge.meta.isEmpty import space.kscience.dataforge.names.Name import space.kscience.visionforge.* @@ -19,10 +18,10 @@ public class Composite( public val compositeType: CompositeType, public val first: Solid, public val second: Solid, -) : SolidBase(), VisionPropertyContainer +) : SolidBase() @VisionBuilder -public inline fun VisionContainerBuilder.composite( +public inline fun MutableVisionContainer.composite( type: CompositeType, name: String? = null, @VisionBuilder builder: SolidGroup.() -> Unit, @@ -34,7 +33,7 @@ public inline fun VisionContainerBuilder.composite( } val res = Composite(type, children[0], children[1]) - res.setProperty(Name.EMPTY, group.getProperty(Name.EMPTY)) + res.properties[Name.EMPTY] = group.properties.raw set(name, res) return res @@ -50,7 +49,7 @@ public fun SolidGroup.smartComposite( @VisionBuilder builder: SolidGroup.() -> Unit, ): Solid = if (type == CompositeType.GROUP) { val group = SolidGroup(builder) - if (name == null && group.meta.isEmpty()) { + if (name == null && group.properties.raw == null) { //append directly to group if no properties are defined group.items.forEach { (_, value) -> value.parent = null @@ -66,19 +65,19 @@ public fun SolidGroup.smartComposite( } @VisionBuilder -public inline fun VisionContainerBuilder.union( +public inline fun MutableVisionContainer.union( name: String? = null, builder: SolidGroup.() -> Unit, ): Composite = composite(CompositeType.UNION, name, builder = builder) @VisionBuilder -public inline fun VisionContainerBuilder.subtract( +public inline fun MutableVisionContainer.subtract( name: String? = null, builder: SolidGroup.() -> Unit, ): Composite = composite(CompositeType.SUBTRACT, name, builder = builder) @VisionBuilder -public inline fun VisionContainerBuilder.intersect( +public inline fun MutableVisionContainer.intersect( name: String? = null, builder: SolidGroup.() -> Unit, ): Composite = composite(CompositeType.INTERSECT, name, builder = builder) \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt index 560ec496..1a8e4a9d 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSegment.kt @@ -2,8 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder import space.kscience.visionforge.set import kotlin.math.cos import kotlin.math.sin @@ -20,7 +20,7 @@ public class ConeSegment( public val topRadius: Float, public val startAngle: Float = 0f, public val angle: Float = PI2 -) : SolidBase(), GeometrySolid { +) : SolidBase(), GeometrySolid { override fun toGeometry(geometryBuilder: GeometryBuilder) { val segments = detail ?: 32 @@ -67,7 +67,7 @@ public class ConeSegment( } @VisionBuilder -public inline fun VisionContainerBuilder.cylinder( +public inline fun MutableVisionContainer.cylinder( r: Number, height: Number, name: String? = null, @@ -79,7 +79,7 @@ public inline fun VisionContainerBuilder.cylinder( ).apply(block).also { set(name, it) } @VisionBuilder -public inline fun VisionContainerBuilder.cone( +public inline fun MutableVisionContainer.cone( bottomRadius: Number, height: Number, upperRadius: Number = 0.0, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt index 25f79ee8..b5a4d5cf 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ConeSurface.kt @@ -2,9 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder -import space.kscience.visionforge.VisionPropertyContainer import space.kscience.visionforge.set import kotlin.math.PI import kotlin.math.cos @@ -24,7 +23,7 @@ public class ConeSurface( public val topInnerRadius: Float, public val startAngle: Float = 0f, public val angle: Float = PI2, -) : SolidBase(), GeometrySolid, VisionPropertyContainer { +) : SolidBase(), GeometrySolid { init { require(bottomRadius > 0) { "Cone surface bottom radius must be positive" } @@ -124,7 +123,7 @@ public class ConeSurface( @VisionBuilder -public inline fun VisionContainerBuilder.tube( +public inline fun MutableVisionContainer.tube( radius: Number, height: Number, innerRadius: Number, @@ -143,7 +142,7 @@ public inline fun VisionContainerBuilder.tube( ).apply(block).also { set(name, it) } @VisionBuilder -public inline fun VisionContainerBuilder.coneSurface( +public inline fun MutableVisionContainer.coneSurface( bottomOuterRadius: Number, bottomInnerRadius: Number, height: Number, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt index 24d1ff16..ad0a456e 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Convex.kt @@ -2,16 +2,17 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.visionforge.VisionContainerBuilder -import space.kscience.visionforge.VisionPropertyContainer +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.set @Serializable @SerialName("solid.convex") -public class Convex(public val points: List) : SolidBase(), VisionPropertyContainer +public class Convex(public val points: List) : SolidBase() -public inline fun VisionContainerBuilder.convex(name: String? = null, action: ConvexBuilder.() -> Unit = {}): Convex = - ConvexBuilder().apply(action).build().also { set(name, it) } +public inline fun MutableVisionContainer.convex( + name: String? = null, + action: ConvexBuilder.() -> Unit = {}, +): Convex = ConvexBuilder().apply(action).build().also { set(name, it) } public class ConvexBuilder { private val points = ArrayList() diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt index 6e5a8bb7..0b1c2e20 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Extruded.kt @@ -3,7 +3,6 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.meta.ObservableMutableMeta import space.kscience.dataforge.names.Name import space.kscience.visionforge.* import kotlin.math.PI @@ -41,7 +40,7 @@ public data class Layer(var x: Float, var y: Float, var z: Float, var scale: Flo public class Extruded( public val shape: List, public val layers: List, -) : SolidBase(), GeometrySolid, VisionPropertyContainer { +) : SolidBase(), GeometrySolid { override fun toGeometry(geometryBuilder: GeometryBuilder) { val shape: Shape2D = shape @@ -96,11 +95,9 @@ public class Extruded( public class ExtrudeBuilder( public var shape: List = emptyList(), - public var layers: MutableList = ArrayList(), - - config: ObservableMutableMeta = MutableMeta(), -) : SimpleVisionPropertyContainer(config) { + public val properties: MutableMeta = MutableMeta(), +) { public fun shape(block: Shape2DBuilder.() -> Unit) { this.shape = Shape2DBuilder().apply(block).build() } @@ -110,12 +107,12 @@ public class ExtrudeBuilder( } internal fun build(): Extruded = Extruded(shape, layers).apply { - setProperty(Name.EMPTY, getProperty(Name.EMPTY)) + this.properties[Name.EMPTY] = this@ExtrudeBuilder.properties } } @VisionBuilder -public fun VisionContainerBuilder.extruded( +public fun MutableVisionContainer.extruded( name: String? = null, action: ExtrudeBuilder.() -> Unit = {}, ): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Hexagon.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Hexagon.kt index 7f42a3eb..b327f9bf 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Hexagon.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Hexagon.kt @@ -2,8 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder import space.kscience.visionforge.set public interface Hexagon : GeometrySolid { @@ -35,7 +35,7 @@ public class Box( public val xSize: Float, public val ySize: Float, public val zSize: Float, -) : SolidBase(), Hexagon { +) : SolidBase(), Hexagon { private inline val dx get() = xSize / 2 private inline val dy get() = ySize / 2 @@ -52,7 +52,7 @@ public class Box( } @VisionBuilder -public inline fun VisionContainerBuilder.box( +public inline fun MutableVisionContainer.box( xSize: Number, ySize: Number, zSize: Number, @@ -71,10 +71,10 @@ public class GenericHexagon( override val node6: Point3D, override val node7: Point3D, override val node8: Point3D, -) : SolidBase(), Hexagon +) : SolidBase(), Hexagon @VisionBuilder -public inline fun VisionContainerBuilder.hexagon( +public inline fun MutableVisionContainer.hexagon( node1: Point3D, node2: Point3D, node3: Point3D, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt index 6bab2cf3..3f90d903 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt @@ -5,15 +5,16 @@ import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.node import space.kscience.dataforge.meta.descriptors.value +import space.kscience.dataforge.meta.number import space.kscience.dataforge.values.ValueType import space.kscience.visionforge.* @Serializable -public abstract class LightSource : SolidBase() { +public abstract class LightSource : SolidBase() { override val descriptor: MetaDescriptor get() = LightSource.descriptor public val color: ColorAccessor by color() - public var intensity: Number by numberProperty(includeStyles = false) { 1.0 } + public var intensity: Number by properties.root(includeStyles = false).number { 1.0 } public companion object{ public val descriptor: MetaDescriptor by lazy { @@ -51,7 +52,7 @@ public abstract class LightSource : SolidBase() { public class AmbientLightSource : LightSource() @VisionBuilder -public fun VisionContainerBuilder.ambientLight( +public fun MutableVisionContainer.ambientLight( name: String? = "@ambientLight", block: AmbientLightSource.() -> Unit = {}, ): AmbientLightSource = AmbientLightSource().apply(block).also { set(name, it) } @@ -62,7 +63,7 @@ public class PointLightSource : LightSource() @VisionBuilder -public fun VisionContainerBuilder.pointLight( +public fun MutableVisionContainer.pointLight( x: Number, y: Number, z: Number, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt index 05d58744..df28b344 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/PolyLine.kt @@ -2,27 +2,19 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.plus +import space.kscience.dataforge.meta.number import space.kscience.visionforge.* @Serializable @SerialName("solid.line") -public class PolyLine(public val points: List) : SolidBase(), VisionPropertyContainer { +public class PolyLine(public val points: List) : SolidBase() { //var lineType by string() - public var thickness: Number by numberProperty(name = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY) { 1.0 } - - - public companion object { - public val THICKNESS_KEY: Name = "thickness".asName() - } - + public var thickness: Number by properties[SolidMaterial.MATERIAL_KEY].number { 1.0 } } @VisionBuilder -public fun VisionContainerBuilder.polyline( +public fun MutableVisionContainer.polyline( vararg points: Point3D, name: String? = null, action: PolyLine.() -> Unit = {}, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index c3111d4e..1cfc1d3b 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -115,9 +115,9 @@ public interface Solid : Vision { * Get the layer number this solid belongs to. Return 0 if layer is not defined. */ public var Solid.layer: Int - get() = getPropertyValue(LAYER_KEY, inherit = true)?.int ?: 0 + get() = properties.getValue(LAYER_KEY, inherit = true)?.int ?: 0 set(value) { - setPropertyValue(LAYER_KEY, value) + properties.set(LAYER_KEY, value) } // Common properties @@ -135,24 +135,24 @@ public enum class RotationOrder { * Rotation order */ public var Solid.rotationOrder: RotationOrder - get() = getPropertyValue(Solid.ROTATION_ORDER_KEY)?.enum() ?: RotationOrder.XYZ - set(value) = setPropertyValue(Solid.ROTATION_ORDER_KEY, value.name.asValue()) + get() = properties.getValue(Solid.ROTATION_ORDER_KEY)?.enum() ?: RotationOrder.XYZ + set(value) = properties.setValue(Solid.ROTATION_ORDER_KEY, value.name.asValue()) /** * Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited */ public var Solid.detail: Int? - get() = getPropertyValue(DETAIL_KEY, inherit = false)?.int - set(value) = setPropertyValue(DETAIL_KEY, value?.asValue()) + get() = properties.getValue(DETAIL_KEY, inherit = false)?.int + set(value) = properties.setValue(DETAIL_KEY, value?.asValue()) /** * If this property is true, the object will be ignored on render. * Property is not inherited. */ public var Vision.ignore: Boolean? - get() = getPropertyValue(IGNORE_KEY, inherit = false)?.boolean - set(value) = setPropertyValue(IGNORE_KEY, value?.asValue()) + get() = properties.getValue(IGNORE_KEY, inherit = false, includeStyles = false)?.boolean + set(value) = properties.setValue(IGNORE_KEY, value?.asValue()) //var VisualObject.selected: Boolean? // get() = getProperty(SELECTED_KEY).boolean @@ -161,18 +161,18 @@ public var Vision.ignore: Boolean? internal fun float(name: Name, default: Number): ReadWriteProperty = object : ReadWriteProperty { override fun getValue(thisRef: Solid, property: KProperty<*>): Number { - return thisRef.getPropertyValue(name)?.number ?: default + return thisRef.properties.getValue(name)?.number ?: default } override fun setValue(thisRef: Solid, property: KProperty<*>, value: Number) { - thisRef.setPropertyValue(name, value) + thisRef.properties.setValue(name, value.asValue()) } } internal fun point(name: Name, default: Float): ReadWriteProperty = object : ReadWriteProperty { override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? { - val item = thisRef.meta[name] ?: return null + val item = thisRef.properties.raw?.get(name) ?: return null return object : Point3D { override val x: Float get() = item[X_KEY]?.float ?: default override val y: Float get() = item[Y_KEY]?.float ?: default @@ -182,11 +182,11 @@ internal fun point(name: Name, default: Float): ReadWriteProperty, value: Point3D?) { if (value == null) { - thisRef.setProperty(name, null) + thisRef.properties[name] = null } else { - thisRef.setPropertyValue(name + X_KEY, value.x) - thisRef.setPropertyValue(name + Y_KEY, value.y) - thisRef.setPropertyValue(name + Z_KEY, value.z) + thisRef.properties[name + X_KEY] = value.x + thisRef.properties[name + Y_KEY] = value.y + thisRef.properties[name + Z_KEY] = value.z } } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt index 6d4b2faf..7aef3f82 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidBase.kt @@ -2,24 +2,11 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.names.Name import space.kscience.visionforge.AbstractVision -import space.kscience.visionforge.VisionChildren @Serializable @SerialName("solid") -public open class SolidBase : AbstractVision(), Solid { +public open class SolidBase : AbstractVision(), Solid { override val descriptor: MetaDescriptor get() = Solid.descriptor - override val children: VisionChildren get() = VisionChildren.empty(this) - - override fun getProperty( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): MutableMeta { - return super.getProperty(name, inherit, includeStyles, includeDefaults) - } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index 20528056..e514dee4 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -16,7 +16,7 @@ public interface PrototypeHolder { * Build or update prototype tree */ @VisionBuilder - public fun prototypes(builder: VisionContainerBuilder.() -> Unit) + public fun prototypes(builder: MutableVisionContainer.() -> Unit) /** * Resolve a prototype from this container. Should never return a ref. @@ -30,7 +30,7 @@ public interface PrototypeHolder { */ @Serializable @SerialName("group.solid") -public class SolidGroup : VisionGroup(), Solid, PrototypeHolder, MutableVisionGroup, VisionContainerBuilder { +public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder, MutableVisionGroup, MutableVisionContainer { public val items: Map get() = children.keys.mapNotNull { @@ -59,7 +59,7 @@ public class SolidGroup : VisionGroup(), Solid, PrototypeHolder, MutableVisionGr /** * Create or edit prototype node as a group */ - override fun prototypes(builder: VisionContainerBuilder.() -> Unit): Unit { + override fun prototypes(builder: MutableVisionContainer.() -> Unit): Unit { (prototypes ?: SolidGroup().also { prototypes = it }).children.run(builder) } @@ -82,7 +82,7 @@ public class SolidGroup : VisionGroup(), Solid, PrototypeHolder, MutableVisionGr public inline fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block) @VisionBuilder -public fun VisionContainerBuilder.group( +public fun MutableVisionContainer.group( name: Name? = null, builder: SolidGroup.() -> Unit = {}, ): SolidGroup = SolidGroup(builder).also { set(name, it) } @@ -91,7 +91,7 @@ public fun VisionContainerBuilder.group( * Define a group with given [name], attach it to this parent and return it. */ @VisionBuilder -public fun VisionContainerBuilder.group( +public fun MutableVisionContainer.group( name: String, action: SolidGroup.() -> Unit = {}, ): SolidGroup = SolidGroup(action).also { set(name, it) } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt index 8cf27881..649e7f7c 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidLabel.kt @@ -2,9 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder -import space.kscience.visionforge.VisionPropertyContainer import space.kscience.visionforge.set @Serializable @@ -13,10 +12,10 @@ public class SolidLabel( public val text: String, public val fontSize: Double, public val fontFamily: String, -) : SolidBase(), VisionPropertyContainer +) : SolidBase() @VisionBuilder -public fun VisionContainerBuilder.label( +public fun MutableVisionContainer.label( text: String, fontSize: Number = 20, fontFamily: String = "Arial", diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt index c68af09c..87a39ac4 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt @@ -102,19 +102,19 @@ public class SolidMaterial : Scheme() { } public val Solid.color: ColorAccessor - get() = ColorAccessor(getProperty(Name.EMPTY), MATERIAL_COLOR_KEY) + get() = ColorAccessor(properties.root(), MATERIAL_COLOR_KEY) public var Solid.material: SolidMaterial? - get() = SolidMaterial.read(getProperty(MATERIAL_KEY)) - set(value) = setProperty(MATERIAL_KEY, value?.meta) + get() = SolidMaterial.read(properties[MATERIAL_KEY]) + set(value) = properties.set(MATERIAL_KEY, value?.meta) @VisionBuilder public fun Solid.material(builder: SolidMaterial.() -> Unit) { - getProperty(MATERIAL_KEY).updateWith(SolidMaterial, builder) + properties[MATERIAL_KEY].updateWith(SolidMaterial, builder) } public var Solid.opacity: Number? - get() = getPropertyValue(MATERIAL_OPACITY_KEY, inherit = true)?.number + get() = properties.getValue(MATERIAL_OPACITY_KEY, inherit = true)?.number set(value) { - setPropertyValue(MATERIAL_OPACITY_KEY, value?.asValue()) + properties.setValue(MATERIAL_OPACITY_KEY, value?.asValue()) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index 8e6e6f59..3e34212a 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -1,14 +1,15 @@ package space.kscience.visionforge.solid -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.* import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import space.kscience.dataforge.meta.Meta +import kotlinx.serialization.Transient +import space.kscience.dataforge.meta.* +import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.names.* import space.kscience.dataforge.values.Value import space.kscience.visionforge.* +import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX @@ -23,6 +24,71 @@ public val Vision.unref: Solid else -> error("This Vision is neither Solid nor SolidReference") } +@Serializable +@SerialName("solid.ref") +public class SolidReference( + @SerialName("prototype") public val prototypeName: Name, +) : SolidBase(), VisionGroup { + + /** + * The prototype for this reference. + */ + public val prototype: Solid by lazy { + //Recursively search for defined template in the parent + if (parent == null) error("No parent is present for SolidReference") + if (parent !is PrototypeHolder) error("Parent does not hold prototypes") + (parent as? PrototypeHolder)?.getPrototype(prototypeName) + ?: error("Prototype with name $prototypeName not found") + } + + override val descriptor: MetaDescriptor get() = prototype.descriptor + + override val defaultProperties: Meta + get() = prototype.properties.raw?.withDefault(descriptor.defaultNode) ?: descriptor.defaultNode + + override val children: VisionChildren + get() = object : VisionChildren { + override val group: Vision get() = this@SolidReference + + override val keys: Set get() = prototype.children?.keys ?: emptySet() + + override val changes: Flow get() = emptyFlow() + + override fun get(token: NameToken): SolidReferenceChild? { + if (token !in (prototype.children?.keys ?: emptySet())) return null + return SolidReferenceChild(this@SolidReference, this@SolidReference, token.asName()) + } + } + +// override fun getPropertyValue( +// name: Name, +// inherit: Boolean, +// includeStyles: Boolean, +// includeDefaults: Boolean, +// ): Value? { +// meta?.getValue(name)?.let { return it } +// if (includeStyles) { +// getStyleProperty(name)?.value?.let { return it } +// } +// prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } +// if (inherit) { +// parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } +// } +// return null +// } +// +// override fun getProperty( +// name: Name, +// inherit: Boolean, +// includeStyles: Boolean, +// includeDefaults: Boolean, +// ): MutableMeta = VisionProperties(this, name, descriptor[name], inherit, includeStyles, prototype.meta) + + public companion object { + public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child" + } +} + /** * @param name A name of reference child relative to prototype root */ @@ -30,62 +96,74 @@ internal class SolidReferenceChild( val owner: SolidReference, override var parent: Vision?, val childName: Name, -) : Solid { +) : Solid, VisionGroup { val prototype: Solid - get() = owner.prototype.children[childName] as? Solid + get() = owner.prototype.children?.get(childName) as? Solid ?: error("Prototype with name $childName not found") - override val meta: Meta get() = owner.getProperty(childToken(childName).asName()) + override val descriptor: MetaDescriptor get() = prototype.descriptor - override fun getPropertyValue( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - includeDefaults: Boolean, - ): Value? { - owner.getPropertyValue( - childPropertyName(childName, name), inherit, includeStyles, includeDefaults - )?.let { return it } - if (includeStyles) { - getStyleProperty(name)?.value?.let { return it } + @Transient + override val properties: MutableVisionProperties = object : MutableVisionProperties { + override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor + override val default: Meta + get() = prototype.properties.raw?.withDefault(descriptor.defaultNode) ?: descriptor.defaultNode + + override val raw: MutableMeta by lazy { owner.properties[childToken(childName).asName()] } + + override fun getValue( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + ): Value? { + raw[name]?.value?.let { return it } + if (includeStyles) { + getStyleProperty(name)?.value?.let { return it } + } + if (inherit) { + parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it } + } + return default[name]?.value } - prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } - if (inherit) { - parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } + + override fun set(name: Name, node: Meta?) { + raw.setMeta(name, node) } - return null - } - override fun setProperty(name: Name, node: Meta?) { - owner.setProperty(childPropertyName(childName, name), node) - } + override fun setValue(name: Name, value: Value?) { + raw.setValue(name, value) + } + override val changes: Flow get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) } - override fun setPropertyValue(name: Name, value: Value?) { - owner.setPropertyValue(childPropertyName(childName, name), value) - } - - override val propertyChanges: SharedFlow - get() = TODO("Not yet implemented") - - override fun invalidateProperty(propertyName: Name) { - owner.invalidateProperty(childPropertyName(childName, propertyName)) + override fun invalidate(propertyName: Name) { + owner.properties.invalidate(childPropertyName(childName, propertyName)) + } } override fun update(change: VisionChange) { - TODO("Not yet implemented") + change.children?.forEach { (name, change) -> + when { + change.delete -> error("Deleting children inside ref is not allowed.") + change.vision != null -> error("Updating content of the ref is not allowed") + else -> children[name]?.update(change) + } + } + change.properties?.let { + updateProperties(it, Name.EMPTY) + } } override val children: VisionChildren = object : VisionChildren { - override val parent: Vision get() = this@SolidReferenceChild + override val group: Vision get() = this@SolidReferenceChild - override val keys: Set get() = prototype.children.keys + override val keys: Set get() = prototype.children?.keys ?: emptySet() override val changes: Flow get() = emptyFlow() override fun get(token: NameToken): SolidReferenceChild? { - if (token !in prototype.children.keys) return null + if (token !in (prototype.children?.keys ?: emptySet())) return null return SolidReferenceChild(this@SolidReferenceChild.owner, this@SolidReferenceChild, childName + token) } } @@ -101,51 +179,15 @@ internal class SolidReferenceChild( } } -@Serializable -@SerialName("solid.ref") -public class SolidReference( - @SerialName("prototype") public val prototypeName: Name, -) : SolidBase() { - - /** - * The prototype for this reference. - */ - public val prototype: Solid by lazy { - //Recursively search for defined template in the parent - if (parent == null) error("No parent is present for SolidReference") - if (parent !is PrototypeHolder) error("Parent does not hold prototypes") - (parent as? PrototypeHolder)?.getPrototype(prototypeName) - ?: error("Prototype with name $prototypeName not found") - } - - override val children: VisionChildren - get() = object : VisionChildren { - override val parent: Vision get() = this@SolidReference - - override val keys: Set get() = prototype.children.keys - - override val changes: Flow get() = emptyFlow() - - override fun get(token: NameToken): SolidReferenceChild? { - if (token !in prototype.children.keys) return null - return SolidReferenceChild(this@SolidReference, this@SolidReference, token.asName()) - } - } - - public companion object{ - public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child" - } -} - /** * Create ref for existing prototype */ -public fun VisionContainerBuilder.ref( +public fun MutableVisionContainer.ref( templateName: Name, name: String? = null, ): SolidReference = SolidReference(templateName).also { set(name, it) } -public fun VisionContainerBuilder.ref( +public fun MutableVisionContainer.ref( templateName: String, name: String? = null, ): SolidReference = ref(Name.parse(templateName), name) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt index 6e9d00d9..722c97f8 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt @@ -6,6 +6,7 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass +import kotlinx.serialization.serializer import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginTag @@ -47,12 +48,12 @@ public class Solids(meta: Meta) : VisionPlugin(meta) { public val serializersModuleForSolids: SerializersModule = SerializersModule { polymorphic(Vision::class) { - subclass(VisionGroup.serializer()) + subclass(SimpleVisionGroup.serializer()) solids() } polymorphic(Solid::class) { - default { SolidBase.serializer() } + default { SolidBase.serializer(serializer()) } solids() } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt index 45305e4a..0ce0d893 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Sphere.kt @@ -2,9 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder -import space.kscience.visionforge.VisionPropertyContainer import space.kscience.visionforge.set import kotlin.math.PI import kotlin.math.cos @@ -17,8 +16,8 @@ public class Sphere( public val phiStart: Float = 0f, public val phi: Float = PI2, public val thetaStart: Float = 0f, - public val theta: Float = PI .toFloat(), -) : SolidBase(), GeometrySolid, VisionPropertyContainer { + public val theta: Float = PI.toFloat(), +) : SolidBase(), GeometrySolid { override fun toGeometry(geometryBuilder: GeometryBuilder) { fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D { @@ -53,7 +52,7 @@ public class Sphere( } @VisionBuilder -public inline fun VisionContainerBuilder.sphere( +public inline fun MutableVisionContainer.sphere( radius: Number, name: String? = null, action: Sphere.() -> Unit = {}, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt index b5ae5500..709968af 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SphereLayer.kt @@ -2,8 +2,8 @@ package space.kscience.visionforge.solid import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import space.kscience.visionforge.MutableVisionContainer import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.VisionContainerBuilder import space.kscience.visionforge.set import kotlin.math.PI import kotlin.math.cos @@ -21,7 +21,7 @@ public class SphereLayer( public val phi: Float = PI2, public val thetaStart: Float = 0f, public val theta: Float = PI.toFloat(), -) : SolidBase(), GeometrySolid { +) : SolidBase(), GeometrySolid { override fun toGeometry(geometryBuilder: GeometryBuilder): Unit = geometryBuilder.run { require(outerRadius > 0) { "Outer radius must be positive" } @@ -69,7 +69,7 @@ public class SphereLayer( } @VisionBuilder -public inline fun VisionContainerBuilder.sphereLayer( +public inline fun MutableVisionContainer.sphereLayer( outerRadius: Number, innerRadius: Number, phiStart: Number = 0f, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt index bab2e518..dbdc58ec 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/transform/RemoveSingleChild.kt @@ -3,7 +3,7 @@ package space.kscience.visionforge.solid.transform import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName -import space.kscience.visionforge.getProperty +import space.kscience.visionforge.root import space.kscience.visionforge.solid.* private operator fun Number.plus(other: Number) = toFloat() + other.toFloat() @@ -20,7 +20,7 @@ internal fun Solid.updateFrom(other: Solid): Solid { scaleX *= other.scaleX scaleY *= other.scaleY scaleZ *= other.scaleZ - setProperty(Name.EMPTY, other.getProperty(Name.EMPTY)) + properties[Name.EMPTY] = other.properties.root() return this } diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt index 8e6f0b89..688712e6 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/PropertyTest.kt @@ -1,9 +1,8 @@ package space.kscience.visionforge.solid -import space.kscience.dataforge.meta.get -import space.kscience.dataforge.meta.string import space.kscience.dataforge.names.asName import space.kscience.dataforge.values.int +import space.kscience.dataforge.values.string import space.kscience.visionforge.* import kotlin.test.Test import kotlin.test.assertEquals @@ -17,7 +16,7 @@ class PropertyTest { //meta["color"] = "pink" color.set("pink") } - assertEquals("pink", box.meta["material.color"]?.string) + assertEquals("pink", box.properties.getValue("material.color")?.string) assertEquals("pink", box.color.string) } @@ -43,12 +42,12 @@ class PropertyTest { fun testInheritedProperty() { var box: Box? = null val group = SolidGroup().apply { - setPropertyValue("test", 22) + properties["test"] = 22 group { box = box(100, 100, 100) } } - assertEquals(22, box?.getPropertyValue("test", inherit = true)?.int) + assertEquals(22, box?.properties?.getValue("test", inherit = true)?.int) } @Test @@ -66,7 +65,7 @@ class PropertyTest { } } } - assertEquals(22, box?.getPropertyValue("test")?.int) + assertEquals(22, box?.properties?.getValue("test")?.int) } @Test diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt index 70cb9c4e..baad6110 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt @@ -31,7 +31,7 @@ class SerializationTest { val string = Solids.encodeToString(cube) println(string) val newCube = Solids.decodeFromString(string) - assertEquals(cube.meta, newCube.meta) + assertEquals(cube.properties.raw, newCube.properties.raw) } @Test @@ -52,7 +52,7 @@ class SerializationTest { val string = Solids.encodeToString(group) println(string) val reconstructed = Solids.decodeFromString(string) as SolidGroup - assertEquals(group.children["cube"]?.meta, reconstructed.children["cube"]?.meta) + assertEquals(group.children["cube"]?.properties?.raw, reconstructed.children["cube"]?.properties?.raw) } @Test diff --git a/visionforge-tables/src/commonMain/kotlin/space/kscience/visionforge/tables/VisionOfTable.kt b/visionforge-tables/src/commonMain/kotlin/space/kscience/visionforge/tables/VisionOfTable.kt index d76398fc..cb870da8 100644 --- a/visionforge-tables/src/commonMain/kotlin/space/kscience/visionforge/tables/VisionOfTable.kt +++ b/visionforge-tables/src/commonMain/kotlin/space/kscience/visionforge/tables/VisionOfTable.kt @@ -12,7 +12,7 @@ import space.kscience.dataforge.values.Null import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.asValue import space.kscience.tables.* -import space.kscience.visionforge.VisionGroup +import space.kscience.visionforge.AbstractVision import space.kscience.visionforge.html.VisionOutput import space.kscience.visionforge.properties import kotlin.jvm.JvmName @@ -42,10 +42,14 @@ public val ColumnHeader.properties: ValueColumnScheme get() = ValueColumn @SerialName("vision.table") public class VisionOfTable( override val headers: List<@Serializable(ColumnHeaderSerializer::class) ColumnHeader>, -) : VisionGroup(), Rows { +) : AbstractVision(), Rows { public var data: List - get() = meta.getIndexed("rows").entries.sortedBy { it.key?.toInt() }.map { it.value } + get() = meta?.getIndexed("rows")?.entries?.sortedBy { + it.key?.toInt() + }?.map { + it.value + } ?: emptyList() set(value) { //TODO Make it better properties()["rows"] = value diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt index 68b44fc5..b7d8244d 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt @@ -10,7 +10,6 @@ import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.startsWith import space.kscience.visionforge.VisionBuilder -import space.kscience.visionforge.getProperty import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.setPropertyValue import space.kscience.visionforge.solid.Solid diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt index 3fb87c7b..42a8b6e6 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvasLabelFactory.kt @@ -11,7 +11,6 @@ import org.w3c.dom.CanvasRenderingContext2D import org.w3c.dom.CanvasTextBaseline import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.MIDDLE -import space.kscience.visionforge.getProperty import space.kscience.visionforge.solid.SolidLabel import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG @@ -27,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory { val canvas = document.createElement("canvas") as HTMLCanvasElement val context = canvas.getContext("2d") as CanvasRenderingContext2D context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}" - context.fillStyle = obj.getProperty(SolidMaterial.MATERIAL_COLOR_KEY)?.value ?: "black" + context.fillStyle = obj.get(SolidMaterial.MATERIAL_COLOR_KEY)?.value ?: "black" context.textBaseline = CanvasTextBaseline.MIDDLE val metrics = context.measureText(obj.text) //canvas.width = metrics.width.toInt() diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt index da1984f3..6e9c7472 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLineFactory.kt @@ -4,7 +4,6 @@ import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D import info.laht.threekt.math.Color import info.laht.threekt.objects.LineSegments -import space.kscience.visionforge.getProperty import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.solid.PolyLine import space.kscience.visionforge.solid.SolidMaterial @@ -25,7 +24,7 @@ public object ThreeLineFactory : ThreeFactory { } val material = ThreeMaterials.getLineMaterial( - obj.getProperty(SolidMaterial.MATERIAL_KEY), + obj.get(SolidMaterial.MATERIAL_KEY), false )