Change collector update

This commit is contained in:
Alexander Nozik 2020-11-12 12:05:43 +03:00
parent fdc221dfa1
commit dfac01d352
17 changed files with 283 additions and 235 deletions

View File

@ -3,8 +3,10 @@
## [Unreleased]
### Added
- Server module
- Change collector
### Changed
- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
### Deprecated

View File

@ -4,8 +4,8 @@ plugins {
id("ru.mipt.npm.project")
}
val dataforgeVersion by extra("0.2.0-dev-4")
val ktorVersion by extra("1.4.1")
val dataforgeVersion by extra("0.2.0-dev-7")
val ktorVersion by extra("1.4.2")
val kotlinWrappersVersion by extra("pre.129-kotlin-1.4.10")
allprojects {

View File

@ -1,8 +1,5 @@
package hep.dataforge.vision
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.node
import hep.dataforge.names.*
import kotlinx.serialization.Transient
@ -10,7 +7,7 @@ import kotlinx.serialization.Transient
/**
* Abstract implementation of mutable group of [Vision]
*/
public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
public abstract class AbstractVisionGroup : VisionBase(), MutableVisionGroup {
//protected abstract val _children: MutableMap<NameToken, T>
@ -19,13 +16,13 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
*/
abstract override val children: Map<NameToken, Vision>
abstract override var styleSheet: StyleSheet?
protected set
final override var styleSheet: StyleSheet? = null
private set
/**
* Update or create stylesheet
*/
public fun styleSheet(block: StyleSheet.() -> Unit) {
public open fun styleSheet(block: StyleSheet.() -> Unit) {
if (styleSheet == null) {
styleSheet = StyleSheet(this@AbstractVisionGroup)
}
@ -84,17 +81,18 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
* Add a static child. Statics could not be found by name, removed or replaced. Changing statics also do not trigger events.
*/
protected open fun addStatic(child: Vision): Unit {
setChild(NameToken("@static", index = child.hashCode().toString()), child)
attach(NameToken("@static", index = child.hashCode().toString()), child)
}
protected abstract fun createGroup(): AbstractVisionGroup
/**
* Set this node as parent for given node
* Set parent for given child and attach it
*/
protected fun attach(child: Vision) {
protected fun attach(token: NameToken, child: Vision) {
if (child.parent == null) {
child.parent = this
setChild(token, child)
} else if (child.parent !== this) {
error("Can't reassign existing parent for $child")
}
@ -110,8 +108,7 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
val token = name.tokens.first()
when (val current = children[token]) {
null -> createGroup().also { child ->
attach(child)
setChild(token, child)
attach(token, child)
}
is AbstractVisionGroup -> current
else -> error("Can't create group with name $name because it exists and not a group")
@ -129,7 +126,6 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
when {
name.isEmpty() -> {
if (child != null) {
attach(child)
addStatic(child)
}
}
@ -138,8 +134,7 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
if (child == null) {
removeChild(token)
} else {
attach(child)
setChild(token, child)
attach(token, child)
}
childrenChanged(token, child)
}
@ -151,11 +146,23 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
}
}
override fun update(meta: Meta) {
val styleMeta = meta.get("styleSheet").node
if (styleMeta != null) {
this.styleSheet?.update(styleMeta)
override fun update(change: Vision) {
if (change is VisionGroup) {
//update stylesheet
val changeStyleSheet = change.styleSheet
if (changeStyleSheet != null) {
styleSheet {
update(changeStyleSheet)
}
super.update(meta)
}
change.children.forEach { (token, child) ->
when {
child is NullVision -> removeChild(token)
children.containsKey(token) -> children[token]!!.update(child)
else -> attach(token, child)
}
}
}
super.update(change)
}
}

View File

@ -1,17 +1,13 @@
package hep.dataforge.vision
import hep.dataforge.meta.Config
import hep.dataforge.names.NameToken
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@SerialName("group")
@SerialName("vision.group")
public class SimpleVisionGroup : AbstractVisionGroup() {
override var styleSheet: StyleSheet? = null
@SerialName("children")
private val _children = HashMap<NameToken, Vision>()
override val children: Map<NameToken, Vision> get() = _children

View File

@ -5,7 +5,10 @@ package hep.dataforge.vision
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import kotlinx.serialization.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
@ -15,7 +18,7 @@ import kotlinx.serialization.encoding.Encoder
/**
* A container for styles
*/
@Serializable
@Serializable(StyleSheet.Companion::class)
public class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta>) {
@Transient
internal var owner: Vision? = null
@ -30,7 +33,8 @@ public class StyleSheet private constructor(private val styleMap: MutableMap<Str
private fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) {
if (styles.contains(key)) {
//TODO optimize set concatenation
val tokens: Collection<Name> = ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet()))
val tokens: Collection<Name> =
((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet()))
.map { it.asName() }
tokens.forEach { parent?.propertyChanged(it) }
}
@ -73,8 +77,17 @@ public class StyleSheet private constructor(private val styleMap: MutableMap<Str
set(key, newStyle.seal())
}
@ExperimentalSerializationApi
@Serializer(StyleSheet::class)
public fun update(key: String, meta: Meta) {
val existing = get(key)
set(key, existing?.edit { this.update(meta) } ?: meta)
}
public fun update(other: StyleSheet) {
other.items.forEach { (key, value) ->
update(key, value)
}
}
public companion object : KSerializer<StyleSheet> {
private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
@ -91,11 +104,6 @@ public class StyleSheet private constructor(private val styleMap: MutableMap<Str
}
}
public fun StyleSheet.update(styleMeta: Meta){
TODO()
}
/**
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
*/

View File

@ -1,6 +1,7 @@
package hep.dataforge.vision
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.Described
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.toName
@ -9,14 +10,15 @@ import hep.dataforge.values.asValue
import hep.dataforge.vision.Vision.Companion.TYPE
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* A root type for display hierarchy
*/
@Type(TYPE)
public interface Vision : Configurable {
public interface Vision : Configurable, Described {
/**
* The parent object of this one. If null, this one is a root.
@ -37,12 +39,7 @@ public interface Vision : Configurable {
/**
* Get property (including styles). [inherit] toggles parent node property lookup
*/
public fun getProperty(name: Name, inherit: Boolean): MetaItem<*>?
/**
* Ger a property including inherited values
*/
override fun getItem(name: Name): MetaItem<*>? = getProperty(name, true)
public fun getProperty(name: Name, inherit: Boolean = true): MetaItem<*>?
/**
* Trigger property invalidation event. If [name] is empty, notify that the whole object is changed
@ -63,7 +60,7 @@ public interface Vision : Configurable {
* List of names of styles applied to this object. Order matters. Not inherited.
*/
public var styles: List<String>
get() = properties[STYLE_KEY]?.stringList?: emptyList()
get() = properties[STYLE_KEY]?.stringList ?: emptyList()
set(value) {
config[STYLE_KEY] = value
}
@ -71,7 +68,7 @@ public interface Vision : Configurable {
/**
* Update this vision using external meta. Children are not updated.
*/
public fun update(meta: Meta)
public fun update(change: Vision)
public companion object {
public const val TYPE: String = "vision"
@ -89,16 +86,61 @@ public interface Vision : Configurable {
public fun Vision.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? =
getProperty(key.toName(), inherit)
/**
* A convenience method to pair [getProperty]
*/
public fun Vision.setProperty(key: Name, value: Any?) {
config[key] = value
}
/**
* A convenience method to pair [getProperty]
*/
public fun Vision.setProperty(key: String, value: Any?) {
config[key] = value
}
/**
* Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision].
*/
public tailrec fun Vision.resolveStyle(name: String): Meta? =
(this as? VisionGroup)?.styleSheet?.get(name) ?: parent?.resolveStyle(name)
/**
* Control visibility of the element
*/
public var Vision.visible: Boolean?
get() = getItem(VISIBLE_KEY).boolean
set(value) = setItem(VISIBLE_KEY, value?.asValue())
get() = getProperty(VISIBLE_KEY).boolean
set(value) = config.setValue(VISIBLE_KEY, value?.asValue())
/**
* Convinience delegate for properties
*/
public fun Vision.property(
default: MetaItem<*>? = null,
key: Name? = null,
inherit: Boolean = true,
): MutableItemDelegate =
object : ReadWriteProperty<Any?, MetaItem<*>?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? {
val name = key ?: property.name.toName()
return getProperty(name, inherit) ?: default
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem<*>?) {
val name = key ?: property.name.toName()
setProperty(name, value)
}
}
//TODO replace by value
fun Vision.properties(inherit: Boolean = true): MutableItemProvider = object : MutableItemProvider {
override fun getItem(name: Name): MetaItem<*>? {
return getProperty(name, inherit)
}
override fun setItem(name: Name, item: MetaItem<*>?) {
setProperty(name, item)
}
}

View File

@ -2,20 +2,24 @@ package hep.dataforge.vision
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.defaultItem
import hep.dataforge.meta.descriptors.get
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.values.ValueType
import hep.dataforge.vision.Vision.Companion.STYLE_KEY
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
internal data class PropertyListener(
val owner: Any? = null,
val action: (name: Name) -> Unit
val action: (name: Name) -> Unit,
)
@Serializable
public open class AbstractVision : Vision {
@SerialName("vision")
public open class VisionBase : Vision {
@Transient
override var parent: VisionGroup? = null
@ -26,6 +30,8 @@ public open class AbstractVision : Vision {
override var properties: Config? = null
protected set
override val descriptor: NodeDescriptor? get() = null
protected fun updateStyles(names: List<String>) {
names.mapNotNull { resolveStyle(it) }.asSequence()
.flatMap { it.items.asSequence() }
@ -76,12 +82,14 @@ public open class AbstractVision : Vision {
sequence {
yield(properties?.get(name))
yieldAll(getStyleItems(name))
yield(descriptor?.get(name)?.defaultItem())
yield(parent?.getProperty(name, inherit))
}.merge()
} else {
sequence {
yield(properties?.get(name))
yieldAll(getStyleItems(name))
yield(descriptor?.get(name)?.defaultItem())
}.merge()
}
}
@ -94,8 +102,10 @@ public open class AbstractVision : Vision {
properties = null
}
override fun update(meta: Meta) {
meta[Vision::properties.name].node?.let { configure(it) }
override fun update(change: Vision) {
if (change.properties != null) {
config.update(change.config)
}
}
public companion object {

View File

@ -1,50 +0,0 @@
package hep.dataforge.vision
import hep.dataforge.meta.Config
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.set
import hep.dataforge.names.NameToken
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
//public class VisionChange(public val properties: Meta, public val childrenChange: Map<NameToken, VisionChange>)
public class VisionChangeCollector(
public val manager: VisionManager,
public val scope: CoroutineScope,
public val vision: Vision,
public val lock: Mutex = Mutex()
) {
private val collector: Config = Config()
private val childrenCollectors = HashMap<NameToken, VisionChangeCollector>()
init {
vision.onPropertyChange(this) { propertyName ->
collector[propertyName] = vision.properties?.get(propertyName)
}
if (vision is VisionGroup) {
vision.children.forEach { (token, child) ->
childrenCollectors[token] = VisionChangeCollector(manager, scope, child, lock)
}
}
if (vision is MutableVisionGroup) {
TODO("Tread vision structure change")
// vision.onChildrenChange(this) { childName, child ->
// if(child == null){
// childrenCollectors[childName] = null
// } else {
// childrenCollectors[childName] = manager.encodeToMeta(child)
// }
// }
}
}
}
//
//fun collectUpdates(manager: VisionManager, scope: CoroutineScope, vision: Vision): Flow<Meta> {
//
//
// vision.
//}

View File

@ -3,10 +3,6 @@ package hep.dataforge.vision
import hep.dataforge.context.*
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.asName
import hep.dataforge.values.Null
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.modules.SerializersModule
@ -52,30 +48,30 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
encodeToJsonElement(vision).toMetaItem(descriptor).node
?: error("Expected node, but value found. Check your serializer!")
public fun updateVision(vision: Vision, meta: Meta) {
vision.update(meta)
if (vision is MutableVisionGroup) {
val children by meta.node()
children?.items?.forEach { (token, item) ->
when {
item.value == Null -> vision[token] = null //Null means removal
item.node != null -> {
val node = item.node!!
val type by node.string()
if (type != null) {
//If the type is present considering it as new node, not an update
vision[token.asName()] = decodeFromMeta(node)
} else {
val existing = vision.children[token]
if (existing != null) {
updateVision(existing, node)
}
}
}
}
}
}
}
// public fun updateVision(vision: Vision, meta: Meta) {
// vision.update(meta)
// if (vision is MutableVisionGroup) {
// val children by meta.node()
// children?.items?.forEach { (token, item) ->
// when {
// item.value == Null -> vision[token] = null //Null means removal
// item.node != null -> {
// val node = item.node!!
// val type by node.string()
// if (type != null) {
// //If the type is present considering it as new node, not an update
// vision[token.asName()] = decodeFromMeta(node)
// } else {
// val existing = vision.children[token]
// if (existing != null) {
// updateVision(existing, node)
// }
// }
// }
// }
// }
// }
// }
public companion object : PluginFactory<VisionManager> {
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)

View File

@ -0,0 +1,106 @@
package hep.dataforge.vision
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.ItemDescriptor
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.time.Duration
/**
* An empty vision existing only for Vision tree change representation. [NullVision] should not be used outside update logic.
*/
@Serializable
@SerialName("vision.null")
public object NullVision : Vision {
@Suppress("SetterBackingFieldAssignment")
override var parent: VisionGroup? = null
set(value) {
//do nothing
}
override val properties: Config? = null
override fun getAllProperties(): Laminate = Laminate(Meta.EMPTY)
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? = null
override fun propertyChanged(name: Name) {}
override fun onPropertyChange(owner: Any?, action: (Name) -> Unit) {}
override fun removeChangeListener(owner: Any?) {}
override fun update(change: Vision) {
error("Null vision should be removed, not updated")
}
override val config: Config get() = Config()
override val descriptor: ItemDescriptor? get() = null
}
private fun Vision.collectChange(scope: CoroutineScope, collector: Vision): Job = scope.launch {
//Store job to be able to cancel collection jobs
//TODO add lock for concurrent modification protection?
val jobStore = HashMap<NameToken, Job>()
if (this is VisionGroup) {
check(collector is MutableVisionGroup) { "Collector for a group should be a group" }
//Subscribe for children changes
children.forEach { (token, child) ->
val childCollector: Vision = if (child is VisionGroup) {
SimpleVisionGroup()
} else {
VisionBase()
}
val job = child.collectChange(this, childCollector)
jobStore[token] = job
//TODO add lazy child addition
collector[token] = childCollector
}
//Subscribe for structure change
if (this is MutableVisionGroup) {
onChildrenChange(this) { token, child ->
//Cancel collector job to avoid leaking
jobStore[token]?.cancel()
if (child != null) {
//Collect to existing Vision
val job = child.collectChange(this, child)
jobStore[token] = job
collector[token] = child
} else{
collector[token] = NullVision
}
}
}
}
//Collect properties change
collector.onPropertyChange(collector) { propertyName ->
collector.config[propertyName] = properties?.get(propertyName)
}
}
public fun Vision.flowChanges(scope: CoroutineScope, collectionDuration: Duration): Flow<Vision> = flow {
//emit initial visual tree
emit(this@flowChanges)
while (true) {
val collector: Vision = if (this is VisionGroup) {
SimpleVisionGroup()
} else {
VisionBase()
}
val collectorJob = collectChange(scope, collector)
kotlinx.coroutines.delay(collectionDuration)
emit(collector)
collectorJob.cancel()
}
}

View File

@ -1,63 +1,8 @@
//import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
plugins {
id("ru.mipt.npm.mpp")
// application
id("ru.mipt.npm.jvm")
}
val ktorVersion: String by rootProject.extra
//kscience {
// application()
//}
kotlin {
// afterEvaluate {
// val jsBrowserDistribution by tasks.getting
//
// jvm {
// withJava()
// compilations[MAIN_COMPILATION_NAME]?.apply {
// tasks.getByName<ProcessResources>(processResourcesTaskName) {
// dependsOn(jsBrowserDistribution)
// afterEvaluate {
// from(jsBrowserDistribution)
// }
// }
// }
//
// }
// }
sourceSets {
commonMain {
dependencies {
implementation(project(":visionforge-core"))
}
}
jvmMain {
dependencies {
implementation("io.ktor:ktor-server-cio:$ktorVersion")
implementation("io.ktor:ktor-serialization:$ktorVersion")
}
}
jsMain {
dependencies {
implementation("io.ktor:ktor-client-js:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-js:$ktorVersion")
}
}
}
}
//distributions {
// main {
// contents {
// from("$buildDir/libs") {
// rename("${rootProject.name}-jvm", rootProject.name)
// into("lib")
// }
// }
// }
//}

View File

@ -1,15 +1,20 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.*
import hep.dataforge.vision.AbstractVision
import hep.dataforge.meta.Meta
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.float
import hep.dataforge.meta.get
import hep.dataforge.meta.node
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionBase
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@Serializable
@SerialName("solid")
public open class BasicSolid: AbstractVision(), Solid {
public open class BasicSolid : VisionBase(), Solid {
override val descriptor: NodeDescriptor get() = Solid.descriptor
@Serializable(Point3DSerializer::class)
override var position: Point3D? = null
@ -19,16 +24,16 @@ public open class BasicSolid: AbstractVision(), Solid {
@Serializable(Point3DSerializer::class)
override var scale: Point3D? = null
override fun update(meta: Meta) {
override fun update(change: Vision) {
fun Meta.toVector(default: Float = 0f) = Point3D(
this[Solid.X_KEY].float ?: default,
this[Solid.Y_KEY].float ?: default,
this[Solid.Z_KEY].float ?: default
)
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
super.update(meta)
change.properties[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
change.properties[Solid.ROTATION].node?.toVector()?.let { rotation = it }
change.properties[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
super.update(change)
}
}

View File

@ -7,6 +7,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.vision.VisionContainerBuilder
import hep.dataforge.vision.properties
import hep.dataforge.vision.set
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -17,7 +18,7 @@ import kotlinx.serialization.UseSerializers
public class PolyLine(public var points: List<Point3D>) : BasicSolid(), Solid {
//var lineType by string()
public var thickness: Number by number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)
public var thickness: Number by properties().number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)
public companion object {
public val THICKNESS_KEY: Name = "thickness".asName()

View File

@ -10,14 +10,14 @@ import kotlinx.serialization.Transient
import kotlin.collections.set
public abstract class AbstractProxy : BasicSolid(), VisionGroup {
public abstract val prototype: Vision
public abstract val prototype: Solid
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) {
sequence {
yield(properties?.get(name))
yieldAll(getStyleItems(name))
yield(prototype.getItem(name))
yield(prototype.getProperty(name))
yield(parent?.getProperty(name, inherit))
}.merge()
} else {
@ -42,7 +42,7 @@ public abstract class AbstractProxy : BasicSolid(), VisionGroup {
//do nothing
}
override val descriptor: NodeDescriptor? get() = prototype.descriptor
override val descriptor: NodeDescriptor get() = prototype.descriptor
}
/**
@ -82,13 +82,11 @@ public class Proxy private constructor(
return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName
}
private fun prototypeFor(name: Name): Vision {
return (prototype as? VisionGroup)?.get(name)
private fun prototypeFor(name: Name): Solid {
return (prototype as? SolidGroup)?.get(name) as? Solid
?: error("Prototype with name $name not found in $this")
}
override val descriptor: NodeDescriptor? get() = prototype.descriptor
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
/**
@ -97,7 +95,7 @@ public class Proxy private constructor(
*/
public inner class ProxyChild(public val name: Name) : AbstractProxy() {
override val prototype: Vision get() = prototypeFor(name)
override val prototype: Solid get() = prototypeFor(name)
override val styleSheet: StyleSheet get() = this@Proxy.styleSheet

View File

@ -14,7 +14,6 @@ import hep.dataforge.vision.enum
import hep.dataforge.vision.solid.Solid.Companion.DETAIL_KEY
import hep.dataforge.vision.solid.Solid.Companion.IGNORE_KEY
import hep.dataforge.vision.solid.Solid.Companion.LAYER_KEY
import kotlinx.serialization.UseSerializers
/**
* Interface for 3-dimensional [Vision]
@ -24,7 +23,7 @@ public interface Solid : Vision {
public var rotation: Point3D?
public var scale: Point3D?
override val descriptor: NodeDescriptor? get() = Companion.descriptor
override val descriptor: NodeDescriptor get() = Companion.descriptor
public companion object {
// val SELECTED_KEY = "selected".asName()
@ -123,7 +122,7 @@ public enum class RotationOrder {
*/
public var Solid.rotationOrder: RotationOrder
get() = getItem(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
set(value) = setItem(Solid.ROTATION_ORDER_KEY, value.name.asValue())
set(value) = setValue(Solid.ROTATION_ORDER_KEY, value.name.asValue())
/**
@ -131,7 +130,7 @@ public var Solid.rotationOrder: RotationOrder
*/
public var Solid.detail: Int?
get() = getProperty(DETAIL_KEY, false).int
set(value) = setItem(DETAIL_KEY, value?.asValue())
set(value) = setValue(DETAIL_KEY, value?.asValue())
/**
* If this property is true, the object will be ignored on render.
@ -139,7 +138,7 @@ public var Solid.detail: Int?
*/
public var Vision.ignore: Boolean?
get() = getProperty(IGNORE_KEY, false).boolean
set(value) = setItem(IGNORE_KEY, value?.asValue())
set(value) = setValue(IGNORE_KEY, value?.asValue())
//var VisualObject.selected: Boolean?
// get() = getProperty(SELECTED_KEY).boolean

View File

@ -1,16 +1,12 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.Config
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.asName
import hep.dataforge.vision.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.json.Json
import kotlin.collections.set
public interface PrototypeHolder {
@ -25,7 +21,7 @@ public interface PrototypeHolder {
@SerialName("group.solid")
public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
override var styleSheet: StyleSheet? = null
override val descriptor: NodeDescriptor get() = Solid.descriptor
/**
* A container for templates visible inside this group
@ -44,9 +40,6 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
}).run(builder)
}
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
override var properties: Config? = null
@Serializable(Point3DSerializer::class)
override var position: Point3D? = null
@ -111,12 +104,10 @@ public fun MutableVisionGroup.group(name: String, action: SolidGroup.() -> Unit
* A special class which works as a holder for prototypes
*/
internal class Prototypes(
override var children: MutableMap<NameToken, Vision> = LinkedHashMap()
override var children: MutableMap<NameToken, Vision> = LinkedHashMap(),
) : AbstractVisionGroup(), MutableVisionGroup, PrototypeHolder {
override var styleSheet: StyleSheet?
get() = null
set(_) {
override fun styleSheet(block: StyleSheet.() -> Unit) {
error("Can't define stylesheet for prototypes block")
}

View File

@ -1,12 +1,8 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.double
import hep.dataforge.meta.transformations.MetaConverter.Companion.double
import hep.dataforge.names.NameToken
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.Vision
import hep.dataforge.vision.VisionGroup
import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.nullable
@ -18,7 +14,6 @@ import kotlinx.serialization.encoding.*
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Point3D::class)
public object Point3DSerializer : KSerializer<Point3D> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.vis.spatial.Point3D") {
element<Double>("x")
@ -54,7 +49,6 @@ public object Point3DSerializer : KSerializer<Point3D> {
}
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Point2D::class)
public object Point2DSerializer : KSerializer<Point2D> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.vis.spatial.Point2D") {
element<Double>("x")
@ -85,8 +79,6 @@ public object Point2DSerializer : KSerializer<Point2D> {
}
}
@OptIn(ExperimentalSerializationApi::class)
@Serializer(MutableVisionGroup::class)
internal object PrototypesSerializer : KSerializer<MutableVisionGroup> {
private val mapSerializer: KSerializer<Map<NameToken, Vision>> =