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] ## [Unreleased]
### Added ### Added
- Server module - Server module
- Change collector
### Changed ### Changed
- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
### Deprecated ### Deprecated

View File

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

View File

@ -1,8 +1,5 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.node
import hep.dataforge.names.* import hep.dataforge.names.*
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
@ -10,7 +7,7 @@ import kotlinx.serialization.Transient
/** /**
* Abstract implementation of mutable group of [Vision] * 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> //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 val children: Map<NameToken, Vision>
abstract override var styleSheet: StyleSheet? final override var styleSheet: StyleSheet? = null
protected set private set
/** /**
* Update or create stylesheet * Update or create stylesheet
*/ */
public fun styleSheet(block: StyleSheet.() -> Unit) { public open fun styleSheet(block: StyleSheet.() -> Unit) {
if (styleSheet == null) { if (styleSheet == null) {
styleSheet = StyleSheet(this@AbstractVisionGroup) 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. * 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 { 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 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) { if (child.parent == null) {
child.parent = this child.parent = this
setChild(token, child)
} else if (child.parent !== this) { } else if (child.parent !== this) {
error("Can't reassign existing parent for $child") error("Can't reassign existing parent for $child")
} }
@ -110,8 +108,7 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
val token = name.tokens.first() val token = name.tokens.first()
when (val current = children[token]) { when (val current = children[token]) {
null -> createGroup().also { child -> null -> createGroup().also { child ->
attach(child) attach(token, child)
setChild(token, child)
} }
is AbstractVisionGroup -> current is AbstractVisionGroup -> current
else -> error("Can't create group with name $name because it exists and not a group") 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 { when {
name.isEmpty() -> { name.isEmpty() -> {
if (child != null) { if (child != null) {
attach(child)
addStatic(child) addStatic(child)
} }
} }
@ -138,8 +134,7 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
if (child == null) { if (child == null) {
removeChild(token) removeChild(token)
} else { } else {
attach(child) attach(token, child)
setChild(token, child)
} }
childrenChanged(token, child) childrenChanged(token, child)
} }
@ -151,11 +146,23 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
} }
} }
override fun update(meta: Meta) { override fun update(change: Vision) {
val styleMeta = meta.get("styleSheet").node if (change is VisionGroup) {
if (styleMeta != null) { //update stylesheet
this.styleSheet?.update(styleMeta) val changeStyleSheet = change.styleSheet
if (changeStyleSheet != null) {
styleSheet {
update(changeStyleSheet)
}
}
change.children.forEach { (token, child) ->
when {
child is NullVision -> removeChild(token)
children.containsKey(token) -> children[token]!!.update(child)
else -> attach(token, child)
}
}
} }
super.update(meta) super.update(change)
} }
} }

View File

@ -1,17 +1,13 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.meta.Config
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("group") @SerialName("vision.group")
public class SimpleVisionGroup : AbstractVisionGroup() { public class SimpleVisionGroup : AbstractVisionGroup() {
override var styleSheet: StyleSheet? = null
@SerialName("children") @SerialName("children")
private val _children = HashMap<NameToken, Vision>() private val _children = HashMap<NameToken, Vision>()
override val children: Map<NameToken, Vision> get() = _children 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.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName 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.MapSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
@ -15,7 +18,7 @@ import kotlinx.serialization.encoding.Encoder
/** /**
* A container for styles * A container for styles
*/ */
@Serializable @Serializable(StyleSheet.Companion::class)
public class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta>) { public class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta>) {
@Transient @Transient
internal var owner: Vision? = null internal var owner: Vision? = null
@ -30,8 +33,9 @@ public class StyleSheet private constructor(private val styleMap: MutableMap<Str
private fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) { private fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) {
if (styles.contains(key)) { if (styles.contains(key)) {
//TODO optimize set concatenation //TODO optimize set concatenation
val tokens: Collection<Name> = ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) val tokens: Collection<Name> =
.map { it.asName() } ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet()))
.map { it.asName() }
tokens.forEach { parent?.propertyChanged(it) } tokens.forEach { parent?.propertyChanged(it) }
} }
if (this is VisionGroup) { if (this is VisionGroup) {
@ -73,8 +77,17 @@ public class StyleSheet private constructor(private val styleMap: MutableMap<Str
set(key, newStyle.seal()) set(key, newStyle.seal())
} }
@ExperimentalSerializationApi public fun update(key: String, meta: Meta) {
@Serializer(StyleSheet::class) 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> { public companion object : KSerializer<StyleSheet> {
private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer) private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor 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. * 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 package hep.dataforge.vision
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.Described
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName 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.TYPE
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/** /**
* A root type for display hierarchy * A root type for display hierarchy
*/ */
@Type(TYPE) @Type(TYPE)
public interface Vision : Configurable { public interface Vision : Configurable, Described {
/** /**
* The parent object of this one. If null, this one is a root. * 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 * Get property (including styles). [inherit] toggles parent node property lookup
*/ */
public fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? public fun getProperty(name: Name, inherit: Boolean = true): MetaItem<*>?
/**
* Ger a property including inherited values
*/
override fun getItem(name: Name): MetaItem<*>? = getProperty(name, true)
/** /**
* Trigger property invalidation event. If [name] is empty, notify that the whole object is changed * 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. * List of names of styles applied to this object. Order matters. Not inherited.
*/ */
public var styles: List<String> public var styles: List<String>
get() = properties[STYLE_KEY]?.stringList?: emptyList() get() = properties[STYLE_KEY]?.stringList ?: emptyList()
set(value) { set(value) {
config[STYLE_KEY] = value config[STYLE_KEY] = value
} }
@ -71,7 +68,7 @@ public interface Vision : Configurable {
/** /**
* Update this vision using external meta. Children are not updated. * Update this vision using external meta. Children are not updated.
*/ */
public fun update(meta: Meta) public fun update(change: Vision)
public companion object { public companion object {
public const val TYPE: String = "vision" public const val TYPE: String = "vision"
@ -89,16 +86,61 @@ public interface Vision : Configurable {
public fun Vision.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = public fun Vision.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? =
getProperty(key.toName(), inherit) 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]. * 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? = public tailrec fun Vision.resolveStyle(name: String): Meta? =
(this as? VisionGroup)?.styleSheet?.get(name) ?: parent?.resolveStyle(name) (this as? VisionGroup)?.styleSheet?.get(name) ?: parent?.resolveStyle(name)
/** /**
* Control visibility of the element * Control visibility of the element
*/ */
public var Vision.visible: Boolean? public var Vision.visible: Boolean?
get() = getItem(VISIBLE_KEY).boolean get() = getProperty(VISIBLE_KEY).boolean
set(value) = setItem(VISIBLE_KEY, value?.asValue()) 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.*
import hep.dataforge.meta.descriptors.NodeDescriptor 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.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.vision.Vision.Companion.STYLE_KEY import hep.dataforge.vision.Vision.Companion.STYLE_KEY
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
internal data class PropertyListener( internal data class PropertyListener(
val owner: Any? = null, val owner: Any? = null,
val action: (name: Name) -> Unit val action: (name: Name) -> Unit,
) )
@Serializable @Serializable
public open class AbstractVision : Vision { @SerialName("vision")
public open class VisionBase : Vision {
@Transient @Transient
override var parent: VisionGroup? = null override var parent: VisionGroup? = null
@ -26,6 +30,8 @@ public open class AbstractVision : Vision {
override var properties: Config? = null override var properties: Config? = null
protected set protected set
override val descriptor: NodeDescriptor? get() = null
protected fun updateStyles(names: List<String>) { protected fun updateStyles(names: List<String>) {
names.mapNotNull { resolveStyle(it) }.asSequence() names.mapNotNull { resolveStyle(it) }.asSequence()
.flatMap { it.items.asSequence() } .flatMap { it.items.asSequence() }
@ -76,12 +82,14 @@ public open class AbstractVision : Vision {
sequence { sequence {
yield(properties?.get(name)) yield(properties?.get(name))
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
yield(descriptor?.get(name)?.defaultItem())
yield(parent?.getProperty(name, inherit)) yield(parent?.getProperty(name, inherit))
}.merge() }.merge()
} else { } else {
sequence { sequence {
yield(properties?.get(name)) yield(properties?.get(name))
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
yield(descriptor?.get(name)?.defaultItem())
}.merge() }.merge()
} }
} }
@ -94,8 +102,10 @@ public open class AbstractVision : Vision {
properties = null properties = null
} }
override fun update(meta: Meta) { override fun update(change: Vision) {
meta[Vision::properties.name].node?.let { configure(it) } if (change.properties != null) {
config.update(change.config)
}
} }
public companion object { 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.context.*
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor 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.Json
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.SerializersModule
@ -52,30 +48,30 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
encodeToJsonElement(vision).toMetaItem(descriptor).node encodeToJsonElement(vision).toMetaItem(descriptor).node
?: error("Expected node, but value found. Check your serializer!") ?: error("Expected node, but value found. Check your serializer!")
public fun updateVision(vision: Vision, meta: Meta) { // public fun updateVision(vision: Vision, meta: Meta) {
vision.update(meta) // vision.update(meta)
if (vision is MutableVisionGroup) { // if (vision is MutableVisionGroup) {
val children by meta.node() // val children by meta.node()
children?.items?.forEach { (token, item) -> // children?.items?.forEach { (token, item) ->
when { // when {
item.value == Null -> vision[token] = null //Null means removal // item.value == Null -> vision[token] = null //Null means removal
item.node != null -> { // item.node != null -> {
val node = item.node!! // val node = item.node!!
val type by node.string() // val type by node.string()
if (type != null) { // if (type != null) {
//If the type is present considering it as new node, not an update // //If the type is present considering it as new node, not an update
vision[token.asName()] = decodeFromMeta(node) // vision[token.asName()] = decodeFromMeta(node)
} else { // } else {
val existing = vision.children[token] // val existing = vision.children[token]
if (existing != null) { // if (existing != null) {
updateVision(existing, node) // updateVision(existing, node)
} // }
} // }
} // }
} // }
} // }
} // }
} // }
public companion object : PluginFactory<VisionManager> { public companion object : PluginFactory<VisionManager> {
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP) 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 //import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.jvm")
// application
} }
val ktorVersion: String by rootProject.extra 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 package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.Meta
import hep.dataforge.vision.AbstractVision 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.Vision
import hep.dataforge.vision.VisionBase
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@Serializable @Serializable
@SerialName("solid") @SerialName("solid")
public open class BasicSolid: AbstractVision(), Solid { public open class BasicSolid : VisionBase(), Solid {
override val descriptor: NodeDescriptor get() = Solid.descriptor
@Serializable(Point3DSerializer::class) @Serializable(Point3DSerializer::class)
override var position: Point3D? = null override var position: Point3D? = null
@ -19,16 +24,16 @@ public open class BasicSolid: AbstractVision(), Solid {
@Serializable(Point3DSerializer::class) @Serializable(Point3DSerializer::class)
override var scale: Point3D? = null override var scale: Point3D? = null
override fun update(meta: Meta) { override fun update(change: Vision) {
fun Meta.toVector(default: Float = 0f) = Point3D( fun Meta.toVector(default: Float = 0f) = Point3D(
this[Solid.X_KEY].float ?: default, this[Solid.X_KEY].float ?: default,
this[Solid.Y_KEY].float ?: default, this[Solid.Y_KEY].float ?: default,
this[Solid.Z_KEY].float ?: default this[Solid.Z_KEY].float ?: default
) )
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it } change.properties[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
meta[Solid.ROTATION].node?.toVector()?.let { rotation = it } change.properties[Solid.ROTATION].node?.toVector()?.let { rotation = it }
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it } change.properties[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
super.update(meta) super.update(change)
} }
} }

View File

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

View File

@ -10,14 +10,14 @@ import kotlinx.serialization.Transient
import kotlin.collections.set import kotlin.collections.set
public abstract class AbstractProxy : BasicSolid(), VisionGroup { public abstract class AbstractProxy : BasicSolid(), VisionGroup {
public abstract val prototype: Vision public abstract val prototype: Solid
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) { return if (inherit) {
sequence { sequence {
yield(properties?.get(name)) yield(properties?.get(name))
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
yield(prototype.getItem(name)) yield(prototype.getProperty(name))
yield(parent?.getProperty(name, inherit)) yield(parent?.getProperty(name, inherit))
}.merge() }.merge()
} else { } else {
@ -42,7 +42,7 @@ public abstract class AbstractProxy : BasicSolid(), VisionGroup {
//do nothing //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 return NameToken(PROXY_CHILD_PROPERTY_PREFIX, childName.toString()) + propertyName
} }
private fun prototypeFor(name: Name): Vision { private fun prototypeFor(name: Name): Solid {
return (prototype as? VisionGroup)?.get(name) return (prototype as? SolidGroup)?.get(name) as? Solid
?: error("Prototype with name $name not found in $this") ?: 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) }) //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() { 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 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.DETAIL_KEY
import hep.dataforge.vision.solid.Solid.Companion.IGNORE_KEY import hep.dataforge.vision.solid.Solid.Companion.IGNORE_KEY
import hep.dataforge.vision.solid.Solid.Companion.LAYER_KEY import hep.dataforge.vision.solid.Solid.Companion.LAYER_KEY
import kotlinx.serialization.UseSerializers
/** /**
* Interface for 3-dimensional [Vision] * Interface for 3-dimensional [Vision]
@ -24,7 +23,7 @@ public interface Solid : Vision {
public var rotation: Point3D? public var rotation: Point3D?
public var scale: Point3D? public var scale: Point3D?
override val descriptor: NodeDescriptor? get() = Companion.descriptor override val descriptor: NodeDescriptor get() = Companion.descriptor
public companion object { public companion object {
// val SELECTED_KEY = "selected".asName() // val SELECTED_KEY = "selected".asName()
@ -123,7 +122,7 @@ public enum class RotationOrder {
*/ */
public var Solid.rotationOrder: RotationOrder public var Solid.rotationOrder: RotationOrder
get() = getItem(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ 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? public var Solid.detail: Int?
get() = getProperty(DETAIL_KEY, false).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. * 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? public var Vision.ignore: Boolean?
get() = getProperty(IGNORE_KEY, false).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? //var VisualObject.selected: Boolean?
// get() = getProperty(SELECTED_KEY).boolean // get() = getProperty(SELECTED_KEY).boolean

View File

@ -1,16 +1,12 @@
package hep.dataforge.vision.solid package hep.dataforge.vision.solid
import hep.dataforge.meta.Config 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.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.asName
import hep.dataforge.vision.* import hep.dataforge.vision.*
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.json.Json
import kotlin.collections.set import kotlin.collections.set
public interface PrototypeHolder { public interface PrototypeHolder {
@ -25,7 +21,7 @@ public interface PrototypeHolder {
@SerialName("group.solid") @SerialName("group.solid")
public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder { 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 * A container for templates visible inside this group
@ -44,9 +40,6 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder {
}).run(builder) }).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) @Serializable(Point3DSerializer::class)
override var position: Point3D? = null override var position: Point3D? = null
@ -111,14 +104,12 @@ public fun MutableVisionGroup.group(name: String, action: SolidGroup.() -> Unit
* A special class which works as a holder for prototypes * A special class which works as a holder for prototypes
*/ */
internal class Prototypes( internal class Prototypes(
override var children: MutableMap<NameToken, Vision> = LinkedHashMap() override var children: MutableMap<NameToken, Vision> = LinkedHashMap(),
) : AbstractVisionGroup(), MutableVisionGroup, PrototypeHolder { ) : AbstractVisionGroup(), MutableVisionGroup, PrototypeHolder {
override var styleSheet: StyleSheet? override fun styleSheet(block: StyleSheet.() -> Unit) {
get() = null error("Can't define stylesheet for prototypes block")
set(_) { }
error("Can't define stylesheet for prototypes block")
}
override fun removeChild(token: NameToken) { override fun removeChild(token: NameToken) {
children.remove(token) children.remove(token)

View File

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