[WIP] great refactoring in progress

This commit is contained in:
Alexander Nozik 2022-08-07 20:33:05 +03:00
parent 791d6d7a81
commit 9b1ca8332b
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
49 changed files with 601 additions and 672 deletions

View File

@ -3,7 +3,6 @@ package ru.mipt.npm.root
import space.kscience.dataforge.meta.double import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.doubleArray import space.kscience.dataforge.values.doubleArray
@ -322,7 +321,7 @@ private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid?
} }
return if (group.children.isEmpty()) { return if (group.children.isEmpty()) {
null 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 } group.items.values.first().apply { parent = null }
} else { } else {
group group

View File

@ -6,7 +6,6 @@ import space.kscience.dataforge.values.asValue
import space.kscience.gdml.GdmlShowCase import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.get import space.kscience.visionforge.get
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.getPropertyValue import space.kscience.visionforge.getPropertyValue
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial

View File

@ -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.CENTRAL_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.LOWER_LAYER_Z
import ru.mipt.npm.muon.monitor.Monitor.UPPER_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.VisionManager
import space.kscience.visionforge.setAsRoot import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
@ -14,7 +14,7 @@ class Model(val manager: VisionManager) {
private val map = HashMap<String, SolidGroup>() private val map = HashMap<String, SolidGroup>()
private val events = HashSet<Event>() private val events = HashSet<Event>()
private fun VisionContainerBuilder<Solid>.pixel(pixel: SC1) { private fun MutableVisionContainer<Solid>.pixel(pixel: SC1) {
val group = group(pixel.name) { val group = group(pixel.name) {
position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z) position = Point3D(pixel.center.x, pixel.center.y, pixel.center.z)
box(pixel.xSize, pixel.ySize, pixel.zSize) box(pixel.xSize, pixel.ySize, pixel.zSize)

View File

@ -49,7 +49,7 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
onPropertyChange { name -> onPropertyChange { name ->
when { when {
name == VALUE -> { name == VALUE -> {
val value = meta.get(VALUE).int ?: 0 val value = meta[VALUE].int ?: 0
val size = value.toFloat() / 255f * 20f val size = value.toFloat() / 255f * 20f
mesh.scale.z = size.toDouble() mesh.scale.z = size.toDouble()
mesh.position.z = size.toDouble() / 2 mesh.position.z = size.toDouble() / 2

View File

@ -3,102 +3,106 @@ package space.kscience.visionforge
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable import kotlinx.serialization.SerialName
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.asMutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.visionforge.VisionGroup.Companion.updateProperties import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
import kotlin.jvm.Synchronized import kotlin.jvm.Synchronized
@Serializable
public abstract class AbstractVision : Vision { public abstract class AbstractVision : Vision {
@Transient @Transient
override var parent: Vision? = null 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 protected open val defaultProperties: Meta? get() = descriptor?.defaultNode
@Transient
final override val properties: MutableVisionProperties = object : MutableVisionProperties {
override val descriptor: MetaDescriptor? get() = this@AbstractVision.descriptor
override val default: Meta? get() = defaultProperties
@Synchronized @Synchronized
private fun getOrCreateProperties(): MutableMeta { private fun getOrCreateProperties(): MutableMeta {
if (properties == null) { if (_properties == null) {
//TODO check performance issues //TODO check performance issues
val newProperties = MutableMeta() val newProperties = MutableMeta()
properties = newProperties _properties = newProperties
} }
return properties!! return _properties!!
} }
@Transient override val raw: Meta? get() = _properties
private val _propertyChanges = MutableSharedFlow<Name>()
override val propertyChanges: SharedFlow<Name> get() = _propertyChanges
override fun getPropertyValue( override fun getValue(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
includeDefaults: Boolean,
): Value? { ): Value? {
properties?.get(name)?.value?.let { return it } raw?.get(name)?.value?.let { return it }
if (includeStyles) { if (includeStyles) {
getStyleProperty(name)?.value?.let { return it } getStyleProperty(name)?.value?.let { return it }
} }
if (inherit) { if (inherit) {
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it }
} }
if (includeDefaults) { return default?.get(name)?.value
descriptor?.defaultNode?.get(name)?.value?.let { return it }
}
return null
} }
override fun setProperty(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
//TODO check old value? //TODO check old value?
if (name.isEmpty()) { if (name.isEmpty()) {
properties = node?.asMutableMeta() _properties = node?.asMutableMeta()
} else if (node == null) { } else if (node == null) {
properties?.setMeta(name, node) _properties?.setMeta(name, node)
} else { } else {
getOrCreateProperties().setMeta(name, node) getOrCreateProperties().setMeta(name, node)
} }
invalidateProperty(name) invalidate(name)
} }
override fun setPropertyValue(name: Name, value: Value?) { override fun setValue(name: Name, value: Value?) {
//TODO check old value? //TODO check old value?
if (value == null) { if (value == null) {
properties?.getMeta(name)?.value = null _properties?.getMeta(name)?.value = null
} else { } else {
getOrCreateProperties().setValue(name, value) getOrCreateProperties().setValue(name, value)
} }
invalidateProperty(name) invalidate(name)
} }
override val descriptor: MetaDescriptor? get() = null @Transient
private val _changes = MutableSharedFlow<Name>()
override val changes: SharedFlow<Name> get() = _changes
override fun invalidateProperty(propertyName: Name) { override fun invalidate(propertyName: Name) {
if (propertyName == Vision.STYLE_KEY) { if (propertyName == Vision.STYLE_KEY) {
styles.asSequence() styles.asSequence()
.mapNotNull { getStyle(it) } .mapNotNull { getStyle(it) }
.flatMap { it.items.asSequence() } .flatMap { it.items.asSequence() }
.distinctBy { it.key } .distinctBy { it.key }
.forEach { .forEach {
invalidateProperty(it.key.asName()) invalidate(it.key.asName())
} }
} }
manager.context.launch { manager.context.launch {
_propertyChanges.emit(propertyName) _changes.emit(propertyName)
} }
} }
}
override val descriptor: MetaDescriptor? get() = null
override fun update(change: VisionChange) { override fun update(change: VisionChange) {
change.properties?.let { change.properties?.let {
updateProperties(it, Name.EMPTY) updateProperties(it, Name.EMPTY)

View File

@ -15,7 +15,7 @@ import kotlin.jvm.JvmInline
@JvmInline @JvmInline
public value class StyleSheet(private val owner: Vision) { 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<NameToken, Meta> get() = styleNode.items public val items: Map<NameToken, Meta> get() = styleNode.items
@ -25,7 +25,7 @@ public value class StyleSheet(private val owner: Vision) {
* Define a style without notifying owner * Define a style without notifying owner
*/ */
public fun define(key: String, style: Meta?) { 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<Name> = val tokens: Collection<Name> =
((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet())) ((oldStyle?.items?.keys ?: emptySet()) + (newStyle?.items?.keys ?: emptySet()))
.map { it.asName() } .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) vision.styleChanged(key, oldStyle, newStyle)
} }
} }
/** /**
* 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 Vision.styles: List<String> public var Vision.styles: List<String>
get() = getPropertyValue( get() = properties.getValue(
Vision.STYLE_KEY, Vision.STYLE_KEY,
inherit = true, inherit = true,
includeStyles = false, includeStyles = false,
includeDefaults = false
)?.stringList ?: emptyList() )?.stringList ?: emptyList()
set(value) { 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. * 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) { 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]. * 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? = 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 * Resolve a property from all styles

View File

@ -1,22 +1,15 @@
package space.kscience.visionforge package space.kscience.visionforge
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import space.kscience.dataforge.context.Global 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.Described
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.boolean import space.kscience.dataforge.values.boolean
import space.kscience.visionforge.Vision.Companion.TYPE 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 manager: VisionManager get() = parent?.manager ?: Global.visionManager
public val children: VisionChildren
/** public val properties: MutableVisionProperties
* 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<Name>
/**
* 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)
/** /**
* Update this vision using a dif represented by [VisionChange]. * 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 * Control visibility of the element
*/ */
public var Vision.visible: Boolean? public var Vision.visible: Boolean?
get() = getPropertyValue(Vision.VISIBLE_KEY)?.boolean get() = properties.getValue(Vision.VISIBLE_KEY)?.boolean
set(value) { 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 * 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) callback(it)
}.launchIn(manager.context) }.launchIn(manager.context)
@ -210,17 +73,9 @@ public fun <V : Vision, T> V.useProperty(
): Job { ): Job {
//Pass initial value. //Pass initial value.
callBack(property.get(this)) callBack(property.get(this))
return propertyChanges.onEach { name -> return properties.changes.onEach { name ->
if (name.startsWith(property.name.asName())) { if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty)) callBack(property.get(this@useProperty))
} }
}.launchIn(manager.context) }.launchIn(manager.context)
} }
public interface MutableVisionGroup : Vision {
override val children: MutableVisionChildren
public fun createGroup(): MutableVisionGroup
}

View File

@ -26,7 +26,7 @@ private fun Vision.deepCopy(): Vision {
/** /**
* An update for a [Vision] * An update for a [Vision]
*/ */
public class VisionChangeBuilder : VisionContainerBuilder<Vision> { public class VisionChangeBuilder : MutableVisionContainer<Vision> {
private var reset: Boolean = false private var reset: Boolean = false
private var vision: Vision? = null private var vision: Vision? = null
@ -77,7 +77,7 @@ public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
public data class VisionChange( public data class VisionChange(
public val delete: Boolean = false, public val delete: Boolean = false,
public val vision: Vision? = null, public val vision: Vision? = null,
@Serializable(MetaSerializer::class) public val properties: Meta? = null, public val properties: Meta? = null,
public val children: Map<Name, VisionChange>? = null, public val children: Map<Name, VisionChange>? = null,
) )
@ -93,25 +93,25 @@ private fun CoroutineScope.collectChange(
//Collect properties change //Collect properties change
source.onPropertyChange { propertyName -> source.onPropertyChange { propertyName ->
val newItem = source.getProperty(propertyName, false, false, false) val newItem = source.properties.raw?.get(propertyName)
collector().propertyChanged(name, propertyName, newItem) collector().propertyChanged(name, propertyName, newItem)
} }
val children = source.children val children = source.children
//Subscribe for children changes //Subscribe for children changes
for ((token, child) in children) { children?.forEach { token, child ->
collectChange(name + token, child, collector) collectChange(name + token, child, collector)
} }
//Subscribe for structure change //Subscribe for structure change
children.changes.onEach { changedName -> children?.changes?.onEach { changedName ->
val after = children[changedName] val after = children[changedName]
val fullName = name + changedName val fullName = name + changedName
if (after != null) { if (after != null) {
collectChange(fullName, after, collector) collectChange(fullName, after, collector)
} }
collector()[fullName] = after collector()[fullName] = after
}.launchIn(this) }?.launchIn(this)
} }
/** /**

View File

@ -19,7 +19,7 @@ public interface VisionContainer<out V : Vision> {
public operator fun get(name: Name): V? public operator fun get(name: Name): V?
} }
public interface VisionContainerBuilder<in V : Vision> { public interface MutableVisionContainer<in V : Vision> {
//TODO add documentation //TODO add documentation
public operator fun set(name: Name?, child: V?) public operator fun set(name: Name?, child: V?)
} }
@ -28,7 +28,7 @@ public interface VisionContainerBuilder<in V : Vision> {
* A serializable representation of [Vision] children container * A serializable representation of [Vision] children container
*/ */
public interface VisionChildren : VisionContainer<Vision> { public interface VisionChildren : VisionContainer<Vision> {
public val parent: Vision? public val group: Vision?
public val keys: Set<NameToken> public val keys: Set<NameToken>
@ -39,14 +39,14 @@ public interface VisionChildren : VisionContainer<Vision> {
public operator fun get(token: NameToken): Vision? public operator fun get(token: NameToken): Vision?
override fun get(name: Name): Vision? = when (name.length) { override fun get(name: Name): Vision? = when (name.length) {
0 -> parent 0 -> group
1 -> get(name.first()) 1 -> get(name.first())
else -> get(name.first())?.children?.get(name.cutFirst()) else -> get(name.first())?.children?.get(name.cutFirst())
} }
public companion object { public companion object {
public fun empty(owner: Vision): VisionChildren = object : VisionChildren { public fun empty(owner: Vision): VisionChildren = object : VisionChildren {
override val parent: Vision get() = owner override val group: Vision get() = owner
override val keys: Set<NameToken> get() = emptySet() override val keys: Set<NameToken> get() = emptySet()
override val changes: Flow<Name> get() = emptyFlow() override val changes: Flow<Name> get() = emptyFlow()
override fun get(token: NameToken): Vision? = null override fun get(token: NameToken): Vision? = null
@ -56,9 +56,13 @@ public interface VisionChildren : VisionContainer<Vision> {
public fun VisionChildren.isEmpty(): Boolean = keys.isEmpty() 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) @Serializable(VisionChildrenContainerSerializer::class)
public interface MutableVisionChildren : VisionChildren, VisionContainerBuilder<Vision> { public interface MutableVisionChildren : VisionChildren, MutableVisionContainer<Vision> {
public override val parent: MutableVisionGroup? public override val group: MutableVisionGroup?
public operator fun set(token: NameToken, value: Vision?) public operator fun set(token: NameToken, value: Vision?)
@ -79,7 +83,7 @@ public interface MutableVisionChildren : VisionChildren, VisionContainerBuilder<
else -> { else -> {
val currentParent = get(name.first()) val currentParent = get(name.first())
if (currentParent != null && currentParent !is MutableVisionGroup) error("Can't assign a child to $currentParent") 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) set(name.first(), it)
} ?: error("Container owner not set") } ?: error("Container owner not set")
parent.children[name.cutFirst()] = child parent.children[name.cutFirst()] = child
@ -105,7 +109,7 @@ public operator fun VisionChildren.iterator(): Iterator<Pair<NameToken, Vision>>
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str)) public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str))
public operator fun <V : Vision> VisionContainerBuilder<V>.set( public operator fun <V : Vision> MutableVisionContainer<V>.set(
str: String?, vision: V?, str: String?, vision: V?,
): Unit = set(str?.parseAsName(), vision) ): Unit = set(str?.parseAsName(), vision)
@ -113,13 +117,13 @@ internal class VisionChildrenImpl(
items: Map<NameToken, Vision>, items: Map<NameToken, Vision>,
) : MutableVisionChildren { ) : MutableVisionChildren {
override var parent: MutableVisionGroup? = null override var group: MutableVisionGroup? = null
internal set internal set
private val items = LinkedHashMap(items) private val items = LinkedHashMap(items)
private val updateJobs = HashMap<NameToken, Job>() private val updateJobs = HashMap<NameToken, Job>()
private val scope: CoroutineScope? get() = parent?.manager?.context private val scope: CoroutineScope? get() = group?.manager?.context
override val keys: Set<NameToken> get() = items.keys override val keys: Set<NameToken> get() = items.keys
@ -149,9 +153,9 @@ internal class VisionChildrenImpl(
} else { } else {
items[token] = value items[token] = value
//check if parent already exists and is different from the current one //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 //set parent
value.parent = parent value.parent = group
//start update jobs (only if the vision is rooted) //start update jobs (only if the vision is rooted)
scope?.let { scope -> scope?.let { scope ->
val job = (value.children as? VisionChildrenImpl)?.changes?.onEach { val job = (value.children as? VisionChildrenImpl)?.changes?.onEach {

View File

@ -13,20 +13,33 @@ import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.ValueType import space.kscience.dataforge.values.ValueType
import space.kscience.visionforge.Vision.Companion.STYLE_KEY import space.kscience.visionforge.Vision.Companion.STYLE_KEY
import kotlin.js.JsName
import kotlin.jvm.Synchronized 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] * A full base implementation for a [Vision]
*/ */
@Serializable public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
@SerialName("vision.group")
public open class VisionGroup : AbstractVision(), MutableVisionGroup {
override fun update(change: VisionChange) { override fun update(change: VisionChange) {
change.children?.forEach { (name, change) -> change.children?.forEach { (name, change) ->
when { when {
change.delete -> children.set(name, null) change.delete -> children[name] = null
change.vision != null -> children.set(name, change.vision) change.vision != null -> children[name] = change.vision
else -> children[name]?.update(change) else -> children[name]?.update(change)
} }
} }
@ -45,13 +58,13 @@ public open class VisionGroup : AbstractVision(), MutableVisionGroup {
fun getOrCreateChildren(): MutableVisionChildren { fun getOrCreateChildren(): MutableVisionChildren {
if (_children == null) { if (_children == null) {
_children = VisionChildrenImpl(emptyMap()).apply { _children = VisionChildrenImpl(emptyMap()).apply {
parent = this@VisionGroup group = this@AbstractVisionGroup
} }
} }
return _children!! return _children!!
} }
override val parent: MutableVisionGroup get() = this@VisionGroup override val group: MutableVisionGroup get() = this@AbstractVisionGroup
override val keys: Set<NameToken> get() = _children?.keys ?: emptySet() override val keys: Set<NameToken> get() = _children?.keys ?: emptySet()
override val changes: Flow<Name> get() = _children?.changes ?: emptyFlow() override val changes: Flow<Name> 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 companion object {
public val descriptor: MetaDescriptor = MetaDescriptor { 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) { public fun Vision.updateProperties(item: Meta, name: Name = Name.EMPTY) {
setPropertyValue(at, item.value) properties.setValue(name, item.value)
item.items.forEach { (token, item) -> 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? { //fun VisualObject.findStyle(styleName: Name): Meta? {
// if (this is VisualGroup) { // if (this is VisualGroup) {
// val style = resolveStyle(styleName) // val style = resolveStyle(styleName)

View File

@ -68,8 +68,8 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
private val defaultSerialModule: SerializersModule = SerializersModule { private val defaultSerialModule: SerializersModule = SerializersModule {
polymorphic(Vision::class) { polymorphic(Vision::class) {
default { VisionGroup.serializer() } default { SimpleVisionGroup.serializer() }
subclass(VisionGroup.serializer()) subclass(SimpleVisionGroup.serializer())
subclass(VisionOfNumberField.serializer()) subclass(VisionOfNumberField.serializer())
subclass(VisionOfTextField.serializer()) subclass(VisionOfTextField.serializer())
subclass(VisionOfCheckbox.serializer()) subclass(VisionOfCheckbox.serializer())
@ -112,7 +112,9 @@ public fun Vision.encodeToString(): String = manager.encodeToString(this)
/** /**
* A root vision attached to [VisionManager] * 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 * Designate this [Vision] as a root and assign a [VisionManager] as its parent

View File

@ -1,40 +1,104 @@
package space.kscience.visionforge package space.kscience.visionforge
import kotlinx.coroutines.flow.Flow
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue
public interface VisionProperties {
/** /**
* A wrapper that emulates delegates reading and writing properties to Vision method * Raw Visions own properties without styles, defaults, etc.
*/ */
internal class VisionProperties( public val raw: Meta?
val vision: Vision,
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<Name>
/**
* 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 nodeName: Name,
val visionDescriptor: MetaDescriptor? = vision.descriptor,
val inherit: Boolean? = null, val inherit: Boolean? = null,
val useStyles: Boolean? = null, val useStyles: Boolean? = null,
val default: Meta? = null,
) : MutableMeta { ) : MutableMeta {
val descriptor: MetaDescriptor? by lazy { visionDescriptor?.get(nodeName) } val descriptor: MetaDescriptor? by lazy { properties.descriptor?.get(nodeName) }
override val items: Map<NameToken, MutableMeta> override val items: Map<NameToken, MutableMeta>
get() { 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 descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet()
val defaultKeys = default?.get(nodeName)?.items?.keys ?: emptySet()
val inheritFlag = descriptor?.inherited ?: inherit val inheritFlag = descriptor?.inherited ?: inherit
val stylesFlag = descriptor?.usesStyles ?: useStyles val stylesFlag = descriptor?.usesStyles ?: useStyles
return (metaKeys + descriptorKeys).associateWith { return (metaKeys + descriptorKeys + defaultKeys).associateWith {
VisionProperties( VisionPropertiesItem(
vision, properties,
nodeName + it, nodeName + it,
visionDescriptor,
inheritFlag, inheritFlag,
stylesFlag stylesFlag,
default
) )
} }
} }
@ -43,22 +107,22 @@ internal class VisionProperties(
get() { get() {
val inheritFlag = descriptor?.inherited ?: inherit ?: false val inheritFlag = descriptor?.inherited ?: inherit ?: false
val stylesFlag = descriptor?.usesStyles ?: useStyles ?: true val stylesFlag = descriptor?.usesStyles ?: useStyles ?: true
return vision.getPropertyValue(nodeName, inheritFlag, stylesFlag, true) return properties.getValue(nodeName, inheritFlag, stylesFlag) ?: default?.getValue(nodeName)
} }
set(value) { set(value) {
vision.setPropertyValue(nodeName, value) properties.setValue(nodeName, value)
} }
override fun getOrCreate(name: Name): MutableMeta = VisionProperties( override fun getOrCreate(name: Name): MutableMeta = VisionPropertiesItem(
vision, properties,
nodeName + name, nodeName + name,
visionDescriptor,
inherit, inherit,
useStyles useStyles,
default
) )
override fun setMeta(name: Name, node: Meta?) { override fun setMeta(name: Name, node: Meta?) {
vision.setProperty(nodeName + name, node) properties[nodeName + name] = node
} }
override fun toString(): String = Meta.toString(this) override fun toString(): String = Meta.toString(this)
@ -66,16 +130,96 @@ internal class VisionProperties(
override fun hashCode(): Int = Meta.hashCode(this) override fun hashCode(): Int = Meta.hashCode(this)
} }
///** public fun VisionProperties.getValue(
// * Accessor to all vision properties name: Name,
// */ inherit: Boolean? = null,
//public fun Vision.computePropertyValues( includeStyles: Boolean? = null,
// descriptor: MetaDescriptor? = this.descriptor, ): Value? {
//): MutableValueProvider = object : MutableValueProvider { val descriptor = descriptor?.get(name)
// override fun getValue(name: Name): Value? = computeProperty(name, descriptor?.get(name))?.value val inheritFlag = inherit ?: descriptor?.inherited ?: false
// val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true
// override fun setValue(name: Name, value: Value?) { return getValue(name, inheritFlag, stylesFlag)
// setProperty(name, value) }
// }
//} 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)

View File

@ -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<out V : Vision> {
public fun getProperty(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean,
): Meta?
}
public open class SimpleVisionPropertyContainer<out V : Vision>(
public val meta: MutableMeta,
) : VisionPropertyContainer<V> {
override fun getProperty(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean,
): Meta? = meta.getMeta(name)
}

View File

@ -9,14 +9,13 @@ import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.node import space.kscience.dataforge.meta.node
import space.kscience.visionforge.properties
@Serializable @Serializable
@SerialName("html.form") @SerialName("html.form")
public class VisionOfHtmlForm( public class VisionOfHtmlForm(
public val formId: String, public val formId: String,
) : VisionOfHtmlInput() { ) : VisionOfHtmlInput() {
public var values: Meta? by properties().node() public var values: Meta? by mutableProperties.node()
} }
public class HtmlFormFragment internal constructor( public class HtmlFormFragment internal constructor(

View File

@ -5,12 +5,15 @@ import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.meta.number import space.kscience.dataforge.meta.number
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.visionforge.VisionGroup import space.kscience.dataforge.names.Name
import space.kscience.visionforge.properties import space.kscience.visionforge.*
//TODO replace by something
internal val Vision.mutableProperties get() = properties[Name.EMPTY, false, false]
@Serializable @Serializable
public abstract class VisionOfHtmlInput : VisionGroup() { public abstract class VisionOfHtmlInput : AbstractVision() {
public var disabled: Boolean by properties().boolean(false) public var disabled: Boolean by mutableProperties.boolean { false }
} }
@Serializable @Serializable
@ -19,7 +22,7 @@ public class VisionOfTextField(
public val label: String? = null, public val label: String? = null,
public val name: String? = null, public val name: String? = null,
) : VisionOfHtmlInput() { ) : VisionOfHtmlInput() {
public var text: String? by properties().string() public var text: String? by mutableProperties.string()
} }
@Serializable @Serializable
@ -28,7 +31,7 @@ public class VisionOfCheckbox(
public val label: String? = null, public val label: String? = null,
public val name: String? = null, public val name: String? = null,
) : VisionOfHtmlInput() { ) : VisionOfHtmlInput() {
public var checked: Boolean? by properties().boolean() public var checked: Boolean? by mutableProperties.boolean()
} }
@Serializable @Serializable
@ -37,7 +40,7 @@ public class VisionOfNumberField(
public val label: String? = null, public val label: String? = null,
public val name: String? = null, public val name: String? = null,
) : VisionOfHtmlInput() { ) : VisionOfHtmlInput() {
public var value: Number? by properties().number() public var value: Number? by mutableProperties.number()
} }
@Serializable @Serializable
@ -49,6 +52,6 @@ public class VisionOfRangeField(
public val label: String? = null, public val label: String? = null,
public val name: String? = null, public val name: String? = null,
) : VisionOfHtmlInput() { ) : VisionOfHtmlInput() {
public var value: Number? by properties().number() public var value: Number? by mutableProperties.number()
} }

View File

@ -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<Any?, Meta?> = object : ReadWriteProperty<Any?, Meta?> {
// 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 <T> Vision.propertyNode(
// converter: MetaConverter<T>,
// name: Name? = null,
// inherit: Boolean = false,
// includeStyles: Boolean = true,
// includeDefaults: Boolean = true,
//): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
// 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<Any?, Value?> = object : ReadWriteProperty<Any?, Value?> {
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 <T> 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<Any?, T> = object : ReadWriteProperty<Any?, T> {
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<Any?, Number?> = 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<Any?, Number> = propertyValue(name, inherit, includeStyles, includeDefaults) {
it?.number ?: default()
}

View File

@ -6,7 +6,8 @@ import kotlinx.coroutines.launch
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.iterator import space.kscience.visionforge.children
import space.kscience.visionforge.forEach
public interface VisionVisitor { public interface VisionVisitor {
/** /**
@ -37,7 +38,7 @@ public interface VisionVisitor {
visionVisitor.visitChildren(name, vision) visionVisitor.visitChildren(name, vision)
for ((token, child) in vision.children) { vision.children?.forEach { token, child ->
visitTreeAsync(visionVisitor, name + token, child) visitTreeAsync(visionVisitor, name + token, child)
} }
} }

View File

@ -30,9 +30,10 @@ fun FlowContent.renderVisionFragment(
@DFExperimental @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 = { val fragment: HtmlVisionFragment = {
div { div {
@ -42,8 +43,8 @@ class HtmlTagTest {
"metaProperty" put 87 "metaProperty" put 87
} }
base { base {
setPropertyValue("myProp", 82) properties["myProp"] = 82
setPropertyValue("otherProp", false) properties["otherProp"] = false
} }
} }
} }
@ -53,7 +54,7 @@ class HtmlTagTest {
div { div {
h2 { +"Properties" } h2 { +"Properties" }
ul { ul {
vision.getProperty(Name.EMPTY).items.forEach { vision.properties.raw?.items?.forEach {
li { li {
a { +it.key.toString() } a { +it.key.toString() }
p { +it.value.toString() } p { +it.value.toString() }

View File

@ -8,45 +8,47 @@ import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.boolean import space.kscience.dataforge.values.boolean
import space.kscience.dataforge.values.int import space.kscience.dataforge.values.int
import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.getProperty import space.kscience.visionforge.get
import space.kscience.visionforge.getPropertyValue import space.kscience.visionforge.getValue
import space.kscience.visionforge.setPropertyValue import space.kscience.visionforge.set
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotEquals import kotlin.test.assertNotEquals
class VisionPropertyTest {
private class TestScheme : Scheme() {
var ddd by int()
companion object : SchemeSpec<TestScheme>(::TestScheme)
}
internal class VisionPropertyTest {
@Test @Test
fun testPropertyWrite() { fun testPropertyWrite() {
val vision = VisionGroup() val vision = VisionGroup()
vision.setPropertyValue("fff", 2) vision.properties["fff"] = 2
vision.setPropertyValue("fff.ddd", false) vision.properties["fff.ddd"] = false
assertEquals(2, vision.getPropertyValue("fff")?.int) assertEquals(2, vision.properties.getValue("fff")?.int)
assertEquals(false, vision.getPropertyValue("fff.ddd")?.boolean) assertEquals(false, vision.properties.getValue("fff.ddd")?.boolean)
} }
@Test @Test
fun testPropertyEdit() { fun testPropertyEdit() {
val vision = VisionGroup() val vision = VisionGroup()
vision.getProperty("fff.ddd").apply { vision.properties["fff.ddd"].apply {
value = 2.asValue() value = 2.asValue()
} }
assertEquals(2, vision.getPropertyValue("fff.ddd")?.int) assertEquals(2, vision.properties.getValue("fff.ddd")?.int)
assertNotEquals(true, vision.getPropertyValue("fff.ddd")?.boolean) assertNotEquals(true, vision.properties.getValue("fff.ddd")?.boolean)
}
internal class TestScheme: Scheme(){
var ddd by int()
companion object: SchemeSpec<TestScheme>(::TestScheme)
} }
@Test @Test
fun testPropertyUpdate() { fun testPropertyUpdate() {
val vision = VisionGroup() val vision = VisionGroup()
vision.getProperty("fff").updateWith(TestScheme){ vision.properties["fff"].updateWith(TestScheme) {
ddd = 2 ddd = 2
} }
assertEquals(2, vision.getPropertyValue("fff.ddd")?.int) assertEquals(2, vision.properties.getValue("fff.ddd")?.int)
} }
} }

View File

@ -9,7 +9,6 @@ import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.getStyle import space.kscience.visionforge.getStyle
import space.kscience.visionforge.styles import space.kscience.visionforge.styles
import tornadofx.* import tornadofx.*

View File

@ -16,7 +16,6 @@ import space.kscience.dataforge.context.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.Type
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE 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_KEY
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY
@ -77,7 +76,7 @@ public class FX3DPlugin : AbstractPlugin() {
is PolyLine -> PolyLine3D( is PolyLine -> PolyLine3D(
obj.points.map { Point3D(it.x, it.y, it.z) }, obj.points.map { Point3D(it.x, it.y, it.z) },
obj.thickness.toFloat(), obj.thickness.toFloat(),
obj.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).color() obj.get(SolidMaterial.MATERIAL_COLOR_KEY).color()
).apply { ).apply {
this.meshView.cullFace = CullFace.FRONT this.meshView.cullFace = CullFace.FRONT
} }

View File

@ -7,7 +7,6 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import tornadofx.* import tornadofx.*

View File

@ -76,7 +76,7 @@ public fun SolidGroup.markLayers(thresholds: List<Int> = listOf(500, 1000, 20000
node.vision.layer = layerIndex node.vision.layer = layerIndex
remaining -= node.selfCount * (node.children.size + 1) remaining -= node.selfCount * (node.children.size + 1)
logger?.apply { logger.run {
if (node.selfCount > 1) { if (node.selfCount > 1) {
info { "Prototype with name ${node.name} moved to layer $layerIndex. $remaining nodes remains" } info { "Prototype with name ${node.name} moved to layer $layerIndex. $remaining nodes remains" }
} else { } else {

View File

@ -7,13 +7,12 @@ import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.plotly.Plot import space.kscience.plotly.Plot
import space.kscience.plotly.Plotly import space.kscience.plotly.Plotly
import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.AbstractVision
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.html.VisionOutput import space.kscience.visionforge.html.VisionOutput
@Serializable @Serializable
@SerialName("vision.plotly") @SerialName("vision.plotly")
public class VisionOfPlotly private constructor() : VisionGroup() { public class VisionOfPlotly private constructor() : AbstractVision() {
public constructor(plot: Plot) : this() { public constructor(plot: Plot) : this() {
setProperty(Name.EMPTY, plot.meta) setProperty(Name.EMPTY, plot.meta)

View File

@ -7,7 +7,7 @@ import space.kscience.dataforge.values.*
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.getProperty import space.kscience.visionforge.root
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
@VisionBuilder @VisionBuilder
@ -29,7 +29,7 @@ public class ColorAccessor(
} }
public fun Vision.color(): ReadOnlyProperty<Vision, ColorAccessor> = ReadOnlyProperty { _, property -> public fun Vision.color(): ReadOnlyProperty<Vision, ColorAccessor> = ReadOnlyProperty { _, property ->
ColorAccessor(getProperty(Name.EMPTY), property.name.asName()) ColorAccessor(properties.root(), property.name.asName())
} }
public var ColorAccessor?.string: String? public var ColorAccessor?.string: String?

View File

@ -2,7 +2,6 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.* import space.kscience.visionforge.*
@ -19,10 +18,10 @@ public class Composite(
public val compositeType: CompositeType, public val compositeType: CompositeType,
public val first: Solid, public val first: Solid,
public val second: Solid, public val second: Solid,
) : SolidBase(), VisionPropertyContainer<Composite> ) : SolidBase<Composite>()
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.composite( public inline fun MutableVisionContainer<Solid>.composite(
type: CompositeType, type: CompositeType,
name: String? = null, name: String? = null,
@VisionBuilder builder: SolidGroup.() -> Unit, @VisionBuilder builder: SolidGroup.() -> Unit,
@ -34,7 +33,7 @@ public inline fun VisionContainerBuilder<Solid>.composite(
} }
val res = Composite(type, children[0], children[1]) 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) set(name, res)
return res return res
@ -50,7 +49,7 @@ public fun SolidGroup.smartComposite(
@VisionBuilder builder: SolidGroup.() -> Unit, @VisionBuilder builder: SolidGroup.() -> Unit,
): Solid = if (type == CompositeType.GROUP) { ): Solid = if (type == CompositeType.GROUP) {
val group = SolidGroup(builder) 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 //append directly to group if no properties are defined
group.items.forEach { (_, value) -> group.items.forEach { (_, value) ->
value.parent = null value.parent = null
@ -66,19 +65,19 @@ public fun SolidGroup.smartComposite(
} }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.union( public inline fun MutableVisionContainer<Solid>.union(
name: String? = null, name: String? = null,
builder: SolidGroup.() -> Unit, builder: SolidGroup.() -> Unit,
): Composite = composite(CompositeType.UNION, name, builder = builder) ): Composite = composite(CompositeType.UNION, name, builder = builder)
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.subtract( public inline fun MutableVisionContainer<Solid>.subtract(
name: String? = null, name: String? = null,
builder: SolidGroup.() -> Unit, builder: SolidGroup.() -> Unit,
): Composite = composite(CompositeType.SUBTRACT, name, builder = builder) ): Composite = composite(CompositeType.SUBTRACT, name, builder = builder)
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.intersect( public inline fun MutableVisionContainer<Solid>.intersect(
name: String? = null, name: String? = null,
builder: SolidGroup.() -> Unit, builder: SolidGroup.() -> Unit,
): Composite = composite(CompositeType.INTERSECT, name, builder = builder) ): Composite = composite(CompositeType.INTERSECT, name, builder = builder)

View File

@ -2,8 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.set import space.kscience.visionforge.set
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
@ -20,7 +20,7 @@ public class ConeSegment(
public val topRadius: Float, public val topRadius: Float,
public val startAngle: Float = 0f, public val startAngle: Float = 0f,
public val angle: Float = PI2 public val angle: Float = PI2
) : SolidBase(), GeometrySolid { ) : SolidBase<ConeSegment>(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
val segments = detail ?: 32 val segments = detail ?: 32
@ -67,7 +67,7 @@ public class ConeSegment(
} }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.cylinder( public inline fun MutableVisionContainer<Solid>.cylinder(
r: Number, r: Number,
height: Number, height: Number,
name: String? = null, name: String? = null,
@ -79,7 +79,7 @@ public inline fun VisionContainerBuilder<Solid>.cylinder(
).apply(block).also { set(name, it) } ).apply(block).also { set(name, it) }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.cone( public inline fun MutableVisionContainer<Solid>.cone(
bottomRadius: Number, bottomRadius: Number,
height: Number, height: Number,
upperRadius: Number = 0.0, upperRadius: Number = 0.0,

View File

@ -2,9 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.VisionPropertyContainer
import space.kscience.visionforge.set import space.kscience.visionforge.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
@ -24,7 +23,7 @@ public class ConeSurface(
public val topInnerRadius: Float, public val topInnerRadius: Float,
public val startAngle: Float = 0f, public val startAngle: Float = 0f,
public val angle: Float = PI2, public val angle: Float = PI2,
) : SolidBase(), GeometrySolid, VisionPropertyContainer<ConeSurface> { ) : SolidBase<ConeSurface>(), GeometrySolid {
init { init {
require(bottomRadius > 0) { "Cone surface bottom radius must be positive" } require(bottomRadius > 0) { "Cone surface bottom radius must be positive" }
@ -124,7 +123,7 @@ public class ConeSurface(
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.tube( public inline fun MutableVisionContainer<Solid>.tube(
radius: Number, radius: Number,
height: Number, height: Number,
innerRadius: Number, innerRadius: Number,
@ -143,7 +142,7 @@ public inline fun VisionContainerBuilder<Solid>.tube(
).apply(block).also { set(name, it) } ).apply(block).also { set(name, it) }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.coneSurface( public inline fun MutableVisionContainer<Solid>.coneSurface(
bottomOuterRadius: Number, bottomOuterRadius: Number,
bottomInnerRadius: Number, bottomInnerRadius: Number,
height: Number, height: Number,

View File

@ -2,16 +2,17 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.VisionContainerBuilder import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionPropertyContainer
import space.kscience.visionforge.set import space.kscience.visionforge.set
@Serializable @Serializable
@SerialName("solid.convex") @SerialName("solid.convex")
public class Convex(public val points: List<Point3D>) : SolidBase(), VisionPropertyContainer<Convex> public class Convex(public val points: List<Point3D>) : SolidBase<Convex>()
public inline fun VisionContainerBuilder<Solid>.convex(name: String? = null, action: ConvexBuilder.() -> Unit = {}): Convex = public inline fun MutableVisionContainer<Solid>.convex(
ConvexBuilder().apply(action).build().also { set(name, it) } name: String? = null,
action: ConvexBuilder.() -> Unit = {},
): Convex = ConvexBuilder().apply(action).build().also { set(name, it) }
public class ConvexBuilder { public class ConvexBuilder {
private val points = ArrayList<Point3D>() private val points = ArrayList<Point3D>()

View File

@ -3,7 +3,6 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.* import space.kscience.visionforge.*
import kotlin.math.PI 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 class Extruded(
public val shape: List<Point2D>, public val shape: List<Point2D>,
public val layers: List<Layer>, public val layers: List<Layer>,
) : SolidBase(), GeometrySolid, VisionPropertyContainer<Extruded> { ) : SolidBase<Extruded>(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
val shape: Shape2D = shape val shape: Shape2D = shape
@ -96,11 +95,9 @@ public class Extruded(
public class ExtrudeBuilder( public class ExtrudeBuilder(
public var shape: List<Point2D> = emptyList(), public var shape: List<Point2D> = emptyList(),
public var layers: MutableList<Layer> = ArrayList(), public var layers: MutableList<Layer> = ArrayList(),
public val properties: MutableMeta = MutableMeta(),
config: ObservableMutableMeta = MutableMeta(), ) {
) : SimpleVisionPropertyContainer<Extruded>(config) {
public fun shape(block: Shape2DBuilder.() -> Unit) { public fun shape(block: Shape2DBuilder.() -> Unit) {
this.shape = Shape2DBuilder().apply(block).build() this.shape = Shape2DBuilder().apply(block).build()
} }
@ -110,12 +107,12 @@ public class ExtrudeBuilder(
} }
internal fun build(): Extruded = Extruded(shape, layers).apply { internal fun build(): Extruded = Extruded(shape, layers).apply {
setProperty(Name.EMPTY, getProperty(Name.EMPTY)) this.properties[Name.EMPTY] = this@ExtrudeBuilder.properties
} }
} }
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.extruded( public fun MutableVisionContainer<Solid>.extruded(
name: String? = null, name: String? = null,
action: ExtrudeBuilder.() -> Unit = {}, action: ExtrudeBuilder.() -> Unit = {},
): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) } ): Extruded = ExtrudeBuilder().apply(action).build().also { set(name, it) }

View File

@ -2,8 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.set import space.kscience.visionforge.set
public interface Hexagon : GeometrySolid { public interface Hexagon : GeometrySolid {
@ -35,7 +35,7 @@ public class Box(
public val xSize: Float, public val xSize: Float,
public val ySize: Float, public val ySize: Float,
public val zSize: Float, public val zSize: Float,
) : SolidBase(), Hexagon { ) : SolidBase<Box>(), Hexagon {
private inline val dx get() = xSize / 2 private inline val dx get() = xSize / 2
private inline val dy get() = ySize / 2 private inline val dy get() = ySize / 2
@ -52,7 +52,7 @@ public class Box(
} }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.box( public inline fun MutableVisionContainer<Solid>.box(
xSize: Number, xSize: Number,
ySize: Number, ySize: Number,
zSize: Number, zSize: Number,
@ -71,10 +71,10 @@ public class GenericHexagon(
override val node6: Point3D, override val node6: Point3D,
override val node7: Point3D, override val node7: Point3D,
override val node8: Point3D, override val node8: Point3D,
) : SolidBase(), Hexagon ) : SolidBase<GenericHexagon>(), Hexagon
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.hexagon( public inline fun MutableVisionContainer<Solid>.hexagon(
node1: Point3D, node1: Point3D,
node2: Point3D, node2: Point3D,
node3: Point3D, node3: Point3D,

View File

@ -5,15 +5,16 @@ import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.node import space.kscience.dataforge.meta.descriptors.node
import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.descriptors.value
import space.kscience.dataforge.meta.number
import space.kscience.dataforge.values.ValueType import space.kscience.dataforge.values.ValueType
import space.kscience.visionforge.* import space.kscience.visionforge.*
@Serializable @Serializable
public abstract class LightSource : SolidBase() { public abstract class LightSource : SolidBase<LightSource>() {
override val descriptor: MetaDescriptor get() = LightSource.descriptor override val descriptor: MetaDescriptor get() = LightSource.descriptor
public val color: ColorAccessor by color() 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 companion object{
public val descriptor: MetaDescriptor by lazy { public val descriptor: MetaDescriptor by lazy {
@ -51,7 +52,7 @@ public abstract class LightSource : SolidBase() {
public class AmbientLightSource : LightSource() public class AmbientLightSource : LightSource()
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.ambientLight( public fun MutableVisionContainer<Solid>.ambientLight(
name: String? = "@ambientLight", name: String? = "@ambientLight",
block: AmbientLightSource.() -> Unit = {}, block: AmbientLightSource.() -> Unit = {},
): AmbientLightSource = AmbientLightSource().apply(block).also { set(name, it) } ): AmbientLightSource = AmbientLightSource().apply(block).also { set(name, it) }
@ -62,7 +63,7 @@ public class PointLightSource : LightSource()
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.pointLight( public fun MutableVisionContainer<Solid>.pointLight(
x: Number, x: Number,
y: Number, y: Number,
z: Number, z: Number,

View File

@ -2,27 +2,19 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.names.Name import space.kscience.dataforge.meta.number
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.visionforge.* import space.kscience.visionforge.*
@Serializable @Serializable
@SerialName("solid.line") @SerialName("solid.line")
public class PolyLine(public val points: List<Point3D>) : SolidBase(), VisionPropertyContainer<PolyLine> { public class PolyLine(public val points: List<Point3D>) : SolidBase<PolyLine>() {
//var lineType by string() //var lineType by string()
public var thickness: Number by numberProperty(name = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY) { 1.0 } public var thickness: Number by properties[SolidMaterial.MATERIAL_KEY].number { 1.0 }
public companion object {
public val THICKNESS_KEY: Name = "thickness".asName()
}
} }
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.polyline( public fun MutableVisionContainer<Solid>.polyline(
vararg points: Point3D, vararg points: Point3D,
name: String? = null, name: String? = null,
action: PolyLine.() -> Unit = {}, action: PolyLine.() -> Unit = {},

View File

@ -115,9 +115,9 @@ public interface Solid : Vision {
* Get the layer number this solid belongs to. Return 0 if layer is not defined. * Get the layer number this solid belongs to. Return 0 if layer is not defined.
*/ */
public var Solid.layer: Int public var Solid.layer: Int
get() = getPropertyValue(LAYER_KEY, inherit = true)?.int ?: 0 get() = properties.getValue(LAYER_KEY, inherit = true)?.int ?: 0
set(value) { set(value) {
setPropertyValue(LAYER_KEY, value) properties.set(LAYER_KEY, value)
} }
// Common properties // Common properties
@ -135,24 +135,24 @@ public enum class RotationOrder {
* Rotation order * Rotation order
*/ */
public var Solid.rotationOrder: RotationOrder public var Solid.rotationOrder: RotationOrder
get() = getPropertyValue(Solid.ROTATION_ORDER_KEY)?.enum<RotationOrder>() ?: RotationOrder.XYZ get() = properties.getValue(Solid.ROTATION_ORDER_KEY)?.enum<RotationOrder>() ?: RotationOrder.XYZ
set(value) = setPropertyValue(Solid.ROTATION_ORDER_KEY, value.name.asValue()) 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 * Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
*/ */
public var Solid.detail: Int? public var Solid.detail: Int?
get() = getPropertyValue(DETAIL_KEY, inherit = false)?.int get() = properties.getValue(DETAIL_KEY, inherit = false)?.int
set(value) = setPropertyValue(DETAIL_KEY, value?.asValue()) set(value) = properties.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.
* Property is not inherited. * Property is not inherited.
*/ */
public var Vision.ignore: Boolean? public var Vision.ignore: Boolean?
get() = getPropertyValue(IGNORE_KEY, inherit = false)?.boolean get() = properties.getValue(IGNORE_KEY, inherit = false, includeStyles = false)?.boolean
set(value) = setPropertyValue(IGNORE_KEY, value?.asValue()) set(value) = properties.setValue(IGNORE_KEY, value?.asValue())
//var VisualObject.selected: Boolean? //var VisualObject.selected: Boolean?
// get() = getProperty(SELECTED_KEY).boolean // get() = getProperty(SELECTED_KEY).boolean
@ -161,18 +161,18 @@ public var Vision.ignore: Boolean?
internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> = internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
object : ReadWriteProperty<Solid, Number> { object : ReadWriteProperty<Solid, Number> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Number { 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) { 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<Solid, Point3D?> = internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
object : ReadWriteProperty<Solid, Point3D?> { object : ReadWriteProperty<Solid, Point3D?> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? { 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 { return object : Point3D {
override val x: Float get() = item[X_KEY]?.float ?: default override val x: Float get() = item[X_KEY]?.float ?: default
override val y: Float get() = item[Y_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<Solid, Point3D
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) { override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
if (value == null) { if (value == null) {
thisRef.setProperty(name, null) thisRef.properties[name] = null
} else { } else {
thisRef.setPropertyValue(name + X_KEY, value.x) thisRef.properties[name + X_KEY] = value.x
thisRef.setPropertyValue(name + Y_KEY, value.y) thisRef.properties[name + Y_KEY] = value.y
thisRef.setPropertyValue(name + Z_KEY, value.z) thisRef.properties[name + Z_KEY] = value.z
} }
} }
} }

View File

@ -2,24 +2,11 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.AbstractVision import space.kscience.visionforge.AbstractVision
import space.kscience.visionforge.VisionChildren
@Serializable @Serializable
@SerialName("solid") @SerialName("solid")
public open class SolidBase : AbstractVision(), Solid { public open class SolidBase<T : Solid> : AbstractVision(), Solid {
override val descriptor: MetaDescriptor get() = Solid.descriptor 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<AbstractVision>.getProperty(name, inherit, includeStyles, includeDefaults)
}
} }

View File

@ -16,7 +16,7 @@ public interface PrototypeHolder {
* Build or update prototype tree * Build or update prototype tree
*/ */
@VisionBuilder @VisionBuilder
public fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit) public fun prototypes(builder: MutableVisionContainer<Solid>.() -> Unit)
/** /**
* Resolve a prototype from this container. Should never return a ref. * Resolve a prototype from this container. Should never return a ref.
@ -30,7 +30,7 @@ public interface PrototypeHolder {
*/ */
@Serializable @Serializable
@SerialName("group.solid") @SerialName("group.solid")
public class SolidGroup : VisionGroup(), Solid, PrototypeHolder, MutableVisionGroup, VisionContainerBuilder<Solid> { public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder, MutableVisionGroup, MutableVisionContainer<Solid> {
public val items: Map<NameToken, Solid> public val items: Map<NameToken, Solid>
get() = children.keys.mapNotNull { get() = children.keys.mapNotNull {
@ -59,7 +59,7 @@ public class SolidGroup : VisionGroup(), Solid, PrototypeHolder, MutableVisionGr
/** /**
* Create or edit prototype node as a group * Create or edit prototype node as a group
*/ */
override fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit): Unit { override fun prototypes(builder: MutableVisionContainer<Solid>.() -> Unit): Unit {
(prototypes ?: SolidGroup().also { prototypes = it }).children.run(builder) (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) public inline fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.group( public fun MutableVisionContainer<Solid>.group(
name: Name? = null, name: Name? = null,
builder: SolidGroup.() -> Unit = {}, builder: SolidGroup.() -> Unit = {},
): SolidGroup = SolidGroup(builder).also { set(name, it) } ): SolidGroup = SolidGroup(builder).also { set(name, it) }
@ -91,7 +91,7 @@ public fun VisionContainerBuilder<Solid>.group(
* Define a group with given [name], attach it to this parent and return it. * Define a group with given [name], attach it to this parent and return it.
*/ */
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.group( public fun MutableVisionContainer<Solid>.group(
name: String, name: String,
action: SolidGroup.() -> Unit = {}, action: SolidGroup.() -> Unit = {},
): SolidGroup = SolidGroup(action).also { set(name, it) } ): SolidGroup = SolidGroup(action).also { set(name, it) }

View File

@ -2,9 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.VisionPropertyContainer
import space.kscience.visionforge.set import space.kscience.visionforge.set
@Serializable @Serializable
@ -13,10 +12,10 @@ public class SolidLabel(
public val text: String, public val text: String,
public val fontSize: Double, public val fontSize: Double,
public val fontFamily: String, public val fontFamily: String,
) : SolidBase(), VisionPropertyContainer<SolidLabel> ) : SolidBase<SolidLabel>()
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Solid>.label( public fun MutableVisionContainer<Solid>.label(
text: String, text: String,
fontSize: Number = 20, fontSize: Number = 20,
fontFamily: String = "Arial", fontFamily: String = "Arial",

View File

@ -102,19 +102,19 @@ public class SolidMaterial : Scheme() {
} }
public val Solid.color: ColorAccessor 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? public var Solid.material: SolidMaterial?
get() = SolidMaterial.read(getProperty(MATERIAL_KEY)) get() = SolidMaterial.read(properties[MATERIAL_KEY])
set(value) = setProperty(MATERIAL_KEY, value?.meta) set(value) = properties.set(MATERIAL_KEY, value?.meta)
@VisionBuilder @VisionBuilder
public fun Solid.material(builder: SolidMaterial.() -> Unit) { public fun Solid.material(builder: SolidMaterial.() -> Unit) {
getProperty(MATERIAL_KEY).updateWith(SolidMaterial, builder) properties[MATERIAL_KEY].updateWith(SolidMaterial, builder)
} }
public var Solid.opacity: Number? public var Solid.opacity: Number?
get() = getPropertyValue(MATERIAL_OPACITY_KEY, inherit = true)?.number get() = properties.getValue(MATERIAL_OPACITY_KEY, inherit = true)?.number
set(value) { set(value) {
setPropertyValue(MATERIAL_OPACITY_KEY, value?.asValue()) properties.setValue(MATERIAL_OPACITY_KEY, value?.asValue())
} }

View File

@ -1,14 +1,15 @@
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable 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.names.*
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.visionforge.* import space.kscience.visionforge.*
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX 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") else -> error("This Vision is neither Solid nor SolidReference")
} }
@Serializable
@SerialName("solid.ref")
public class SolidReference(
@SerialName("prototype") public val prototypeName: Name,
) : SolidBase<SolidReference>(), 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<NameToken> get() = prototype.children?.keys ?: emptySet()
override val changes: Flow<Name> 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 * @param name A name of reference child relative to prototype root
*/ */
@ -30,62 +96,74 @@ internal class SolidReferenceChild(
val owner: SolidReference, val owner: SolidReference,
override var parent: Vision?, override var parent: Vision?,
val childName: Name, val childName: Name,
) : Solid { ) : Solid, VisionGroup {
val prototype: Solid 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") ?: 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( @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, name: Name,
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
includeDefaults: Boolean,
): Value? { ): Value? {
owner.getPropertyValue( raw[name]?.value?.let { return it }
childPropertyName(childName, name), inherit, includeStyles, includeDefaults
)?.let { return it }
if (includeStyles) { if (includeStyles) {
getStyleProperty(name)?.value?.let { return it } getStyleProperty(name)?.value?.let { return it }
} }
prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
if (inherit) { if (inherit) {
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it } parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it }
} }
return null return default[name]?.value
} }
override fun setProperty(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
owner.setProperty(childPropertyName(childName, name), node) raw.setMeta(name, node)
} }
override fun setPropertyValue(name: Name, value: Value?) { override fun setValue(name: Name, value: Value?) {
owner.setPropertyValue(childPropertyName(childName, name), value) raw.setValue(name, value)
} }
override val changes: Flow<Name> get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }
override val propertyChanges: SharedFlow<Name> override fun invalidate(propertyName: Name) {
get() = TODO("Not yet implemented") owner.properties.invalidate(childPropertyName(childName, propertyName))
}
override fun invalidateProperty(propertyName: Name) {
owner.invalidateProperty(childPropertyName(childName, propertyName))
} }
override fun update(change: VisionChange) { 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 children: VisionChildren = object : VisionChildren {
override val parent: Vision get() = this@SolidReferenceChild override val group: Vision get() = this@SolidReferenceChild
override val keys: Set<NameToken> get() = prototype.children.keys override val keys: Set<NameToken> get() = prototype.children?.keys ?: emptySet()
override val changes: Flow<Name> get() = emptyFlow() override val changes: Flow<Name> get() = emptyFlow()
override fun get(token: NameToken): SolidReferenceChild? { 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) 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<NameToken> get() = prototype.children.keys
override val changes: Flow<Name> 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 * Create ref for existing prototype
*/ */
public fun VisionContainerBuilder<Solid>.ref( public fun MutableVisionContainer<Solid>.ref(
templateName: Name, templateName: Name,
name: String? = null, name: String? = null,
): SolidReference = SolidReference(templateName).also { set(name, it) } ): SolidReference = SolidReference(templateName).also { set(name, it) }
public fun VisionContainerBuilder<Solid>.ref( public fun MutableVisionContainer<Solid>.ref(
templateName: String, templateName: String,
name: String? = null, name: String? = null,
): SolidReference = ref(Name.parse(templateName), name) ): SolidReference = ref(Name.parse(templateName), name)

View File

@ -6,6 +6,7 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass import kotlinx.serialization.modules.subclass
import kotlinx.serialization.serializer
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag import space.kscience.dataforge.context.PluginTag
@ -47,12 +48,12 @@ public class Solids(meta: Meta) : VisionPlugin(meta) {
public val serializersModuleForSolids: SerializersModule = SerializersModule { public val serializersModuleForSolids: SerializersModule = SerializersModule {
polymorphic(Vision::class) { polymorphic(Vision::class) {
subclass(VisionGroup.serializer()) subclass(SimpleVisionGroup.serializer())
solids() solids()
} }
polymorphic(Solid::class) { polymorphic(Solid::class) {
default { SolidBase.serializer() } default { SolidBase.serializer(serializer<Solid>()) }
solids() solids()
} }
} }

View File

@ -2,9 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.VisionPropertyContainer
import space.kscience.visionforge.set import space.kscience.visionforge.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
@ -18,7 +17,7 @@ public class Sphere(
public val phi: Float = PI2, public val phi: Float = PI2,
public val thetaStart: Float = 0f, public val thetaStart: Float = 0f,
public val theta: Float = PI.toFloat(), public val theta: Float = PI.toFloat(),
) : SolidBase(), GeometrySolid, VisionPropertyContainer<Sphere> { ) : SolidBase<Sphere>(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>) {
fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D { fun point3dFromSphCoord(r: Float, theta: Float, phi: Float): Point3D {
@ -53,7 +52,7 @@ public class Sphere(
} }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.sphere( public inline fun MutableVisionContainer<Solid>.sphere(
radius: Number, radius: Number,
name: String? = null, name: String? = null,
action: Sphere.() -> Unit = {}, action: Sphere.() -> Unit = {},

View File

@ -2,8 +2,8 @@ package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.VisionContainerBuilder
import space.kscience.visionforge.set import space.kscience.visionforge.set
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
@ -21,7 +21,7 @@ public class SphereLayer(
public val phi: Float = PI2, public val phi: Float = PI2,
public val thetaStart: Float = 0f, public val thetaStart: Float = 0f,
public val theta: Float = PI.toFloat(), public val theta: Float = PI.toFloat(),
) : SolidBase(), GeometrySolid { ) : SolidBase<SphereLayer>(), GeometrySolid {
override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>): Unit = geometryBuilder.run { override fun <T : Any> toGeometry(geometryBuilder: GeometryBuilder<T>): Unit = geometryBuilder.run {
require(outerRadius > 0) { "Outer radius must be positive" } require(outerRadius > 0) { "Outer radius must be positive" }
@ -69,7 +69,7 @@ public class SphereLayer(
} }
@VisionBuilder @VisionBuilder
public inline fun VisionContainerBuilder<Solid>.sphereLayer( public inline fun MutableVisionContainer<Solid>.sphereLayer(
outerRadius: Number, outerRadius: Number,
innerRadius: Number, innerRadius: Number,
phiStart: Number = 0f, phiStart: Number = 0f,

View File

@ -3,7 +3,7 @@ package space.kscience.visionforge.solid.transform
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.visionforge.getProperty import space.kscience.visionforge.root
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat() private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
@ -20,7 +20,7 @@ internal fun Solid.updateFrom(other: Solid): Solid {
scaleX *= other.scaleX scaleX *= other.scaleX
scaleY *= other.scaleY scaleY *= other.scaleY
scaleZ *= other.scaleZ scaleZ *= other.scaleZ
setProperty(Name.EMPTY, other.getProperty(Name.EMPTY)) properties[Name.EMPTY] = other.properties.root()
return this return this
} }

View File

@ -1,9 +1,8 @@
package space.kscience.visionforge.solid 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.names.asName
import space.kscience.dataforge.values.int import space.kscience.dataforge.values.int
import space.kscience.dataforge.values.string
import space.kscience.visionforge.* import space.kscience.visionforge.*
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -17,7 +16,7 @@ class PropertyTest {
//meta["color"] = "pink" //meta["color"] = "pink"
color.set("pink") color.set("pink")
} }
assertEquals("pink", box.meta["material.color"]?.string) assertEquals("pink", box.properties.getValue("material.color")?.string)
assertEquals("pink", box.color.string) assertEquals("pink", box.color.string)
} }
@ -43,12 +42,12 @@ class PropertyTest {
fun testInheritedProperty() { fun testInheritedProperty() {
var box: Box? = null var box: Box? = null
val group = SolidGroup().apply { val group = SolidGroup().apply {
setPropertyValue("test", 22) properties["test"] = 22
group { group {
box = box(100, 100, 100) box = box(100, 100, 100)
} }
} }
assertEquals(22, box?.getPropertyValue("test", inherit = true)?.int) assertEquals(22, box?.properties?.getValue("test", inherit = true)?.int)
} }
@Test @Test
@ -66,7 +65,7 @@ class PropertyTest {
} }
} }
} }
assertEquals(22, box?.getPropertyValue("test")?.int) assertEquals(22, box?.properties?.getValue("test")?.int)
} }
@Test @Test

View File

@ -31,7 +31,7 @@ class SerializationTest {
val string = Solids.encodeToString(cube) val string = Solids.encodeToString(cube)
println(string) println(string)
val newCube = Solids.decodeFromString(string) val newCube = Solids.decodeFromString(string)
assertEquals(cube.meta, newCube.meta) assertEquals(cube.properties.raw, newCube.properties.raw)
} }
@Test @Test
@ -52,7 +52,7 @@ class SerializationTest {
val string = Solids.encodeToString(group) val string = Solids.encodeToString(group)
println(string) println(string)
val reconstructed = Solids.decodeFromString(string) as SolidGroup 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 @Test

View File

@ -12,7 +12,7 @@ import space.kscience.dataforge.values.Null
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.tables.* import space.kscience.tables.*
import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.AbstractVision
import space.kscience.visionforge.html.VisionOutput import space.kscience.visionforge.html.VisionOutput
import space.kscience.visionforge.properties import space.kscience.visionforge.properties
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
@ -42,10 +42,14 @@ public val ColumnHeader<Value>.properties: ValueColumnScheme get() = ValueColumn
@SerialName("vision.table") @SerialName("vision.table")
public class VisionOfTable( public class VisionOfTable(
override val headers: List<@Serializable(ColumnHeaderSerializer::class) ColumnHeader<Value>>, override val headers: List<@Serializable(ColumnHeaderSerializer::class) ColumnHeader<Value>>,
) : VisionGroup(), Rows<Value> { ) : AbstractVision(), Rows<Value> {
public var data: List<Meta> public var data: List<Meta>
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) { set(value) {
//TODO Make it better //TODO Make it better
properties()["rows"] = value properties()["rows"] = value

View File

@ -10,7 +10,6 @@ import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.setPropertyValue import space.kscience.visionforge.setPropertyValue
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid

View File

@ -11,7 +11,6 @@ import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.CanvasTextBaseline import org.w3c.dom.CanvasTextBaseline
import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.MIDDLE import org.w3c.dom.MIDDLE
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.solid.SolidLabel import space.kscience.visionforge.solid.SolidLabel
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
@ -27,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
val canvas = document.createElement("canvas") as HTMLCanvasElement val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D val context = canvas.getContext("2d") as CanvasRenderingContext2D
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}" 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 context.textBaseline = CanvasTextBaseline.MIDDLE
val metrics = context.measureText(obj.text) val metrics = context.measureText(obj.text)
//canvas.width = metrics.width.toInt() //canvas.width = metrics.width.toInt()

View File

@ -4,7 +4,6 @@ import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.math.Color import info.laht.threekt.math.Color
import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.LineSegments
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.solid.PolyLine import space.kscience.visionforge.solid.PolyLine
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial
@ -25,7 +24,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
} }
val material = ThreeMaterials.getLineMaterial( val material = ThreeMaterials.getLineMaterial(
obj.getProperty(SolidMaterial.MATERIAL_KEY), obj.get(SolidMaterial.MATERIAL_KEY),
false false
) )