Handle property clearing in updates.

This commit is contained in:
Alexander Nozik 2020-12-22 13:33:05 +03:00
parent 66ea23ad60
commit 216be4a6a1
7 changed files with 90 additions and 53 deletions

View File

@ -3,6 +3,7 @@ package ru.mipt.npm.sat
import hep.dataforge.names.toName
import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.clear
import hep.dataforge.vision.solid.color
import hep.dataforge.vision.solid.invoke
import hep.dataforge.vision.three.server.*
@ -42,7 +43,7 @@ fun main() {
val targetVision = sat[target] as Solid
targetVision.color("red")
delay(300)
targetVision.color("darkgreen")
targetVision.color.clear()
delay(10)
}
}

View File

@ -57,6 +57,9 @@ public interface Vision : Described {
*/
public fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean = true)
/**
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
*/
public fun onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit)
/**
@ -81,7 +84,7 @@ public interface Vision : Described {
public suspend fun notifyPropertyChanged(propertyName: Name): Unit
/**
* Update this vision using external meta. Children are not updated.
* Update this vision using a dif represented by [VisionChange].
*/
public fun update(change: VisionChange)

View File

@ -3,12 +3,14 @@ package hep.dataforge.vision
import hep.dataforge.meta.Config
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MutableMeta
import hep.dataforge.meta.asMetaItem
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.defaultItem
import hep.dataforge.meta.descriptors.get
import hep.dataforge.meta.update
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.values.Null
import hep.dataforge.values.ValueType
import hep.dataforge.vision.Vision.Companion.STYLE_KEY
import kotlinx.coroutines.CoroutineScope
@ -27,6 +29,7 @@ internal data class PropertyListener(
val action: (name: Name) -> Unit,
)
@Serializable
@SerialName("vision")
public open class VisionBase : Vision {
@ -100,6 +103,8 @@ public open class VisionBase : Vision {
}
}
//TODO check memory consumption for the flow
@Transient
private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()
@ -116,13 +121,30 @@ public open class VisionBase : Vision {
propertyInvalidationFlow.emit(propertyName)
}
public fun configure(block: MutableMeta<*>.() -> Unit) {
getOrCreateConfig().block()
public fun configure(block: suspend MutableMeta<*>.() -> Unit) {
scope.launch {
getOrCreateConfig().block()
}
}
override fun update(change: VisionChange) {
fun updateProperties(at: Name, item: MetaItem<*>) {
when (item) {
is MetaItem.ValueItem -> {
if (item.value == Null) {
setProperty(at, null)
} else
setProperty(at, item)
}
is MetaItem.NodeItem -> item.node.items.forEach { (token, childItem) ->
updateProperties(at + token, childItem)
}
}
}
change.properties?.let {
getOrCreateConfig().update(it)
updateProperties(Name.EMPTY, it.asMetaItem())
}
}

View File

@ -3,6 +3,7 @@ package hep.dataforge.vision
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.names.plus
import hep.dataforge.values.Null
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
@ -30,7 +31,8 @@ public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
public fun propertyChanged(visionName: Name, propertyName: Name, item: MetaItem<*>?) {
if (visionName == Name.EMPTY) {
propertyChange[propertyName] = item
//Write property removal as [Null]
propertyChange[propertyName] = (item ?: Null.asMetaItem())
} else {
getOrPutChild(visionName).propertyChanged(Name.EMPTY, propertyName, item)
}
@ -112,6 +114,10 @@ public fun Vision.flowChanges(
coroutineScope {
collectChange(Name.EMPTY, this@flowChanges) { collector }
//Send initial vision state
val initialChange = VisionChange(vision = isolate(manager))
emit(initialChange)
while (currentCoroutineContext().isActive) {
//Wait for changes to accumulate
delay(collectionDuration)

View File

@ -134,14 +134,6 @@ public class VisionServer internal constructor(
try {
withContext(visionManager.context.coroutineContext) {
val initialVision = VisionChange(vision = vision)
val initialJson = visionManager.jsonFormat.encodeToString(
VisionChange.serializer(),
initialVision
)
outgoing.send(Frame.Text(initialJson))
vision.flowChanges(visionManager, updateInterval.milliseconds).collect { update ->
val json = visionManager.jsonFormat.encodeToString(
VisionChange.serializer(),

View File

@ -0,0 +1,51 @@
package hep.dataforge.vision.solid
import hep.dataforge.meta.MutableItemProvider
import hep.dataforge.meta.set
import hep.dataforge.meta.value
import hep.dataforge.names.Name
import hep.dataforge.values.Value
import hep.dataforge.values.asValue
import hep.dataforge.values.string
import hep.dataforge.vision.Colors
import hep.dataforge.vision.VisionBuilder
@VisionBuilder
public class ColorAccessor(private val parent: MutableItemProvider, private val colorKey: Name) {
public var value: Value?
get() = parent.getItem(colorKey).value
set(value) {
parent[colorKey] = value
}
}
public var ColorAccessor?.string: String?
get() = this?.value?.string
set(value) {
this?.value = value?.asValue()
}
/**
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
*/
public operator fun ColorAccessor?.invoke(webColor: String) {
this?.value = webColor.asValue()
}
/**
* Set color as RGB integer
*/
public operator fun ColorAccessor?.invoke(rgb: Int) {
this?.value = Colors.rgbToString(rgb).asValue()
}
/**
* Set color as RGB
*/
public operator fun ColorAccessor?.invoke(r: UByte, g: UByte, b: UByte) {
this?.value = Colors.rgbToString(r, g, b).asValue()
}
public fun ColorAccessor?.clear(){
this?.value = null
}

View File

@ -6,51 +6,13 @@ import hep.dataforge.meta.descriptors.attributes
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.values.Value
import hep.dataforge.values.ValueType
import hep.dataforge.values.asValue
import hep.dataforge.values.string
import hep.dataforge.vision.*
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_OPACITY_KEY
@VisionBuilder
public class ColorAccessor(private val parent: MutableItemProvider, private val colorKey: Name) {
public var value: Value?
get() = parent.getItem(colorKey).value
set(value) {
parent[colorKey] = value
}
}
public var ColorAccessor?.string: String?
get() = this?.value?.string
set(value) {
this?.value = value?.asValue()
}
/**
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
*/
public operator fun ColorAccessor?.invoke(webColor: String) {
this?.value = webColor.asValue()
}
/**
* Set color as RGB integer
*/
public operator fun ColorAccessor?.invoke(rgb: Int) {
this?.value = Colors.rgbToString(rgb).asValue()
}
/**
* Set color as RGB
*/
public operator fun ColorAccessor?.invoke(r: UByte, g: UByte, b: UByte) {
this?.value = Colors.rgbToString(r, g, b).asValue()
}
@VisionBuilder
public class SolidMaterial : Scheme() {