forked from kscience/visionforge
[WIP] Change property and structure subscription to flows.
This commit is contained in:
parent
6a6d9659ca
commit
97cdfd3719
@ -10,9 +10,9 @@ import hep.dataforge.vision.bootstrap.canvasControls
|
|||||||
import hep.dataforge.vision.bootstrap.card
|
import hep.dataforge.vision.bootstrap.card
|
||||||
import hep.dataforge.vision.bootstrap.gridRow
|
import hep.dataforge.vision.bootstrap.gridRow
|
||||||
import hep.dataforge.vision.react.ThreeCanvasComponent
|
import hep.dataforge.vision.react.ThreeCanvasComponent
|
||||||
import hep.dataforge.vision.react.configEditor
|
|
||||||
import hep.dataforge.vision.react.flexColumn
|
import hep.dataforge.vision.react.flexColumn
|
||||||
import hep.dataforge.vision.react.objectTree
|
import hep.dataforge.vision.react.objectTree
|
||||||
|
import hep.dataforge.vision.react.propertyEditor
|
||||||
import hep.dataforge.vision.solid.specifications.Camera
|
import hep.dataforge.vision.solid.specifications.Camera
|
||||||
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
|
import hep.dataforge.vision.solid.specifications.Canvas3DOptions
|
||||||
import hep.dataforge.vision.solid.three.ThreeCanvas
|
import hep.dataforge.vision.solid.three.ThreeCanvas
|
||||||
@ -193,7 +193,7 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
|
|||||||
else -> root[selected]
|
else -> root[selected]
|
||||||
}
|
}
|
||||||
if (selectedObject != null) {
|
if (selectedObject != null) {
|
||||||
configEditor(
|
propertyEditor(
|
||||||
selectedObject.config,
|
selectedObject.config,
|
||||||
selectedObject.descriptor,
|
selectedObject.descriptor,
|
||||||
default = selectedObject.allProperties,
|
default = selectedObject.allProperties,
|
||||||
|
@ -5,7 +5,6 @@ import hep.dataforge.names.plus
|
|||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
import hep.dataforge.values.asValue
|
import hep.dataforge.values.asValue
|
||||||
import hep.dataforge.vision.getProperty
|
import hep.dataforge.vision.getProperty
|
||||||
import hep.dataforge.vision.properties
|
|
||||||
import hep.dataforge.vision.set
|
import hep.dataforge.vision.set
|
||||||
import hep.dataforge.vision.setProperty
|
import hep.dataforge.vision.setProperty
|
||||||
import hep.dataforge.vision.solid.*
|
import hep.dataforge.vision.solid.*
|
||||||
@ -34,8 +33,8 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
|
|||||||
scaleX = xSize
|
scaleX = xSize
|
||||||
scaleY = ySize
|
scaleY = ySize
|
||||||
scaleZ = zSize
|
scaleZ = zSize
|
||||||
properties[MeshThreeFactory.EDGES_ENABLED_KEY] = false
|
getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, false)
|
||||||
properties[MeshThreeFactory.WIREFRAME_ENABLED_KEY] = false
|
getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(three: ThreePlugin): Object3D {
|
override fun render(three: ThreePlugin): Object3D {
|
||||||
@ -63,7 +62,7 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
|
|||||||
mesh.scale.set(xSize, ySize, zSize)
|
mesh.scale.set(xSize, ySize, zSize)
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
propertyInvalidated.onEach { name ->
|
propertyNameFlow.onEach { name ->
|
||||||
when {
|
when {
|
||||||
name.startsWith(GEOMETRY_KEY) -> {
|
name.startsWith(GEOMETRY_KEY) -> {
|
||||||
val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
val kotlinVersion = "1.4.20"
|
val kotlinVersion = "1.4.21"
|
||||||
val toolsVersion = "0.7.0"
|
val toolsVersion = "0.7.1"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
|
@ -3,29 +3,30 @@ package hep.dataforge.vision.bootstrap
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.vision.Vision
|
import hep.dataforge.vision.Vision
|
||||||
|
import hep.dataforge.vision.allProperties
|
||||||
import hep.dataforge.vision.getStyle
|
import hep.dataforge.vision.getStyle
|
||||||
import hep.dataforge.vision.properties
|
|
||||||
import hep.dataforge.vision.react.configEditor
|
import hep.dataforge.vision.react.configEditor
|
||||||
import hep.dataforge.vision.react.metaViewer
|
import hep.dataforge.vision.react.metaViewer
|
||||||
|
import hep.dataforge.vision.styles
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import react.RBuilder
|
import react.RBuilder
|
||||||
import react.dom.render
|
import react.dom.render
|
||||||
|
|
||||||
public fun RBuilder.visionPropertyEditor(
|
public fun RBuilder.visionPropertyEditor(
|
||||||
item: Vision,
|
vision: Vision,
|
||||||
descriptor: NodeDescriptor? = item.descriptor,
|
descriptor: NodeDescriptor? = vision.descriptor,
|
||||||
default: Meta? = null,
|
default: Meta? = null,
|
||||||
key: Any? = null
|
key: Any? = null,
|
||||||
) {
|
) {
|
||||||
card("Properties") {
|
card("Properties") {
|
||||||
configEditor(item.properties, descriptor, default, key)
|
configEditor(vision.allProperties(), descriptor, default, key)
|
||||||
}
|
}
|
||||||
val styles = item.styles
|
val styles = vision.styles
|
||||||
if(styles.isNotEmpty()) {
|
if (styles.isNotEmpty()) {
|
||||||
card("Styles") {
|
card("Styles") {
|
||||||
accordion("styles") {
|
accordion("styles") {
|
||||||
styles.forEach { styleName ->
|
styles.forEach { styleName ->
|
||||||
val style = item.getStyle(styleName)
|
val style = vision.getStyle(styleName)
|
||||||
if (style != null) {
|
if (style != null) {
|
||||||
entry(styleName) {
|
entry(styleName) {
|
||||||
metaViewer(style)
|
metaViewer(style)
|
||||||
@ -40,7 +41,7 @@ public fun RBuilder.visionPropertyEditor(
|
|||||||
public fun Element.visionPropertyEditor(
|
public fun Element.visionPropertyEditor(
|
||||||
item: Vision,
|
item: Vision,
|
||||||
descriptor: NodeDescriptor? = item.descriptor,
|
descriptor: NodeDescriptor? = item.descriptor,
|
||||||
default: Meta? = null
|
default: Meta? = null,
|
||||||
): Unit = render(this) {
|
): Unit = render(this) {
|
||||||
visionPropertyEditor(item, descriptor, default)
|
visionPropertyEditor(item, descriptor, default)
|
||||||
}
|
}
|
@ -7,6 +7,14 @@ import hep.dataforge.names.NameToken
|
|||||||
import hep.dataforge.names.lastOrNull
|
import hep.dataforge.names.lastOrNull
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.html.js.onClickFunction
|
import kotlinx.html.js.onClickFunction
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
@ -14,55 +22,59 @@ import react.*
|
|||||||
import react.dom.render
|
import react.dom.render
|
||||||
import styled.*
|
import styled.*
|
||||||
|
|
||||||
public external interface ConfigEditorItemProps : RProps {
|
public external interface PropertyEditorItemProps : RProps {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root config object - always non null
|
* Root config object - always non null
|
||||||
*/
|
*/
|
||||||
public var root: MutableItemProvider
|
public var provider: MutableItemProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full path to the displayed node in [root]. Could be empty
|
* Full path to the displayed node in [provider]. Could be empty
|
||||||
*/
|
*/
|
||||||
public var name: Name
|
public var name: Name
|
||||||
|
|
||||||
/**
|
|
||||||
* Root default
|
|
||||||
*/
|
|
||||||
public var default: Meta?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root descriptor
|
* Root descriptor
|
||||||
*/
|
*/
|
||||||
public var descriptor: NodeDescriptor?
|
public var descriptor: NodeDescriptor?
|
||||||
|
|
||||||
|
|
||||||
|
public var scope: CoroutineScope?
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public var updateFlow: Flow<Name>?
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ConfigEditorItem: FunctionalComponent<ConfigEditorItemProps> =
|
private val PropertyEditorItem: FunctionalComponent<PropertyEditorItemProps> =
|
||||||
functionalComponent("ConfigEditorItem") { props ->
|
functionalComponent("ConfigEditorItem") { props ->
|
||||||
configEditorItem(props)
|
propertyEditorItem(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
|
||||||
var expanded: Boolean by useState { true }
|
var expanded: Boolean by useState { true }
|
||||||
var item: MetaItem<*>? by useState { props.root.getItem(props.name) }
|
var item: MetaItem<*>? by useState { props.provider.getItem(props.name) }
|
||||||
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
|
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
|
||||||
val defaultItem = props.default?.get(props.name)
|
var actualItem: MetaItem<Meta>? by useState { item ?: descriptorItem?.defaultItem() }
|
||||||
var actualItem: MetaItem<Meta>? by useState { item ?: defaultItem ?: descriptorItem?.defaultItem() }
|
|
||||||
|
|
||||||
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
||||||
|
|
||||||
fun update() {
|
fun update() {
|
||||||
item = props.root.getItem(props.name)
|
item = props.provider.getItem(props.name)
|
||||||
actualItem = item ?: defaultItem ?: descriptorItem?.defaultItem()
|
actualItem = item ?: descriptorItem?.defaultItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffectWithCleanup(listOf(props.root)) {
|
if (props.updateFlow != null) {
|
||||||
props.root.onChange(this) { name, _, _ ->
|
useEffectWithCleanup(listOf(props.provider, props.updateFlow)) {
|
||||||
if (name == props.name) {
|
val updateJob = props.updateFlow!!.onEach { updatedName ->
|
||||||
|
if (updatedName == props.name) {
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
}.launchIn(props.scope ?: GlobalScope)
|
||||||
|
return@useEffectWithCleanup { updateJob.cancel() }
|
||||||
}
|
}
|
||||||
return@useEffectWithCleanup { props.root.removeListener(this) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val expanderClick: (Event) -> Unit = {
|
val expanderClick: (Event) -> Unit = {
|
||||||
@ -71,15 +83,15 @@ private fun RBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
|||||||
|
|
||||||
val valueChanged: (Value?) -> Unit = {
|
val valueChanged: (Value?) -> Unit = {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
props.root.remove(props.name)
|
props.provider.remove(props.name)
|
||||||
} else {
|
} else {
|
||||||
props.root[props.name] = it
|
props.provider[props.name] = it
|
||||||
}
|
}
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
val removeClick: (Event) -> Unit = {
|
val removeClick: (Event) -> Unit = {
|
||||||
props.root.remove(props.name)
|
props.provider.remove(props.name)
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +133,6 @@ private fun RBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
|||||||
add(NameToken(it))
|
add(NameToken(it))
|
||||||
}
|
}
|
||||||
item?.node?.items?.keys?.let { addAll(it) }
|
item?.node?.items?.keys?.let { addAll(it) }
|
||||||
defaultItem?.node?.items?.keys?.let { addAll(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keys.filter { !it.body.startsWith("@") }.forEach { token ->
|
keys.filter { !it.body.startsWith("@") }.forEach { token ->
|
||||||
@ -129,12 +140,11 @@ private fun RBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
|||||||
css {
|
css {
|
||||||
+TreeStyles.treeItem
|
+TreeStyles.treeItem
|
||||||
}
|
}
|
||||||
child(ConfigEditorItem) {
|
child(PropertyEditorItem) {
|
||||||
attrs {
|
attrs {
|
||||||
this.key = props.name.toString()
|
this.key = props.name.toString()
|
||||||
this.root = props.root
|
this.provider = props.provider
|
||||||
this.name = props.name + token
|
this.name = props.name + token
|
||||||
this.default = props.default
|
|
||||||
this.descriptor = props.descriptor
|
this.descriptor = props.descriptor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,63 +200,79 @@ private fun RBuilder.configEditorItem(props: ConfigEditorItemProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public external interface ConfigEditorProps : RProps {
|
public external interface PropertyEditorProps : RProps {
|
||||||
public var id: Name
|
public var provider: MutableItemProvider
|
||||||
public var root: MutableItemProvider
|
public var updateFlow: Flow<Name>?
|
||||||
public var default: Meta?
|
|
||||||
public var descriptor: NodeDescriptor?
|
public var descriptor: NodeDescriptor?
|
||||||
|
public var scope: CoroutineScope?
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ConfigEditor: FunctionalComponent<ConfigEditorProps> = functionalComponent("ConfigEditor") { props ->
|
public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functionalComponent("ConfigEditor") { props ->
|
||||||
child(ConfigEditorItem) {
|
child(PropertyEditorItem) {
|
||||||
attrs {
|
attrs {
|
||||||
this.key = ""
|
this.key = ""
|
||||||
this.root = props.root
|
this.provider = props.provider
|
||||||
this.name = Name.EMPTY
|
this.name = Name.EMPTY
|
||||||
this.default = props.default
|
|
||||||
this.descriptor = props.descriptor
|
this.descriptor = props.descriptor
|
||||||
|
this.scope = props.scope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.propertyEditor(
|
||||||
|
provider: MutableItemProvider,
|
||||||
|
updateFlow: Flow<Name>? = null,
|
||||||
|
descriptor: NodeDescriptor? = null,
|
||||||
|
key: Any? = null,
|
||||||
|
scope: CoroutineScope? = null,
|
||||||
|
) {
|
||||||
|
child(PropertyEditor) {
|
||||||
|
attrs {
|
||||||
|
this.key = key?.toString() ?: ""
|
||||||
|
this.provider = provider
|
||||||
|
this.updateFlow = updateFlow
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.scope = scope
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Config.flowUpdates(): Flow<Name> = callbackFlow {
|
||||||
|
onChange(this) { name, _, _ ->
|
||||||
|
launch {
|
||||||
|
send(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitClose {
|
||||||
|
removeListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun MutableItemProvider.withDefault(default: ItemProvider): MutableItemProvider = object : MutableItemProvider {
|
||||||
|
override fun getItem(name: Name): MetaItem<*>? = getItem(name) ?: default.getItem(name)
|
||||||
|
|
||||||
|
override fun setItem(name: Name, item: MetaItem<*>?) = this@withDefault.setItem(name, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public fun RBuilder.configEditor(
|
||||||
|
config: Config,
|
||||||
|
descriptor: NodeDescriptor? = null,
|
||||||
|
default: Meta? = null,
|
||||||
|
key: Any? = null,
|
||||||
|
scope: CoroutineScope? = null,
|
||||||
|
) = propertyEditor(config.withDefault(default ?: ItemProvider.EMPTY), config.flowUpdates(), descriptor, key, scope)
|
||||||
|
|
||||||
public fun Element.configEditor(
|
public fun Element.configEditor(
|
||||||
config: Config,
|
config: Config,
|
||||||
descriptor: NodeDescriptor? = null,
|
descriptor: NodeDescriptor? = null,
|
||||||
default: Meta? = null,
|
default: Meta? = null,
|
||||||
key: Any? = null,
|
key: Any? = null,
|
||||||
|
scope: CoroutineScope? = null,
|
||||||
) {
|
) {
|
||||||
render(this) {
|
render(this) {
|
||||||
child(ConfigEditor) {
|
configEditor(config,descriptor,default, key, scope)
|
||||||
attrs {
|
|
||||||
this.key = key?.toString() ?: ""
|
|
||||||
this.root = config
|
|
||||||
this.descriptor = descriptor
|
|
||||||
this.default = default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun RBuilder.configEditor(
|
|
||||||
config: MutableItemProvider,
|
|
||||||
descriptor: NodeDescriptor? = null,
|
|
||||||
default: Meta? = null,
|
|
||||||
key: Any? = null,
|
|
||||||
) {
|
|
||||||
child(ConfigEditor) {
|
|
||||||
attrs {
|
|
||||||
this.key = key?.toString() ?: ""
|
|
||||||
this.root = config
|
|
||||||
this.descriptor = descriptor
|
|
||||||
this.default = default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
//public fun RBuilder.configEditor(
|
|
||||||
// obj: Configurable,
|
|
||||||
// descriptor: NodeDescriptor?,
|
|
||||||
// default: Meta? = null,
|
|
||||||
// key: Any? = null
|
|
||||||
//): Unit = configEditor(obj.config, descriptor, default, key)
|
|
@ -64,6 +64,15 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of names of styles applied to this object. Order matters. Not inherited.
|
||||||
|
*/
|
||||||
|
public var Vision.styles: List<String>
|
||||||
|
get() = getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()
|
||||||
|
set(value) {
|
||||||
|
setProperty(Vision.STYLE_KEY, value)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stylesheet for this group and its descendants. Stylesheet is not applied directly,
|
* A stylesheet for this group and its descendants. Stylesheet is not applied directly,
|
||||||
* but instead is just a repository for named configurations.
|
* but instead is just a repository for named configurations.
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package hep.dataforge.vision
|
package hep.dataforge.vision
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.MutableItemProvider
|
||||||
import hep.dataforge.meta.descriptors.Described
|
import hep.dataforge.meta.descriptors.Described
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.meta.descriptors.get
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.values.asValue
|
|
||||||
import hep.dataforge.vision.Vision.Companion.TYPE
|
import hep.dataforge.vision.Vision.Companion.TYPE
|
||||||
import hep.dataforge.vision.Vision.Companion.VISIBLE_KEY
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
@ -26,7 +26,8 @@ public interface Vision : Described {
|
|||||||
public var parent: VisionGroup?
|
public var parent: VisionGroup?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fast accessor method to get own property (no inheritance or styles
|
* A fast accessor method to get own property (no inheritance or styles).
|
||||||
|
* Should be equivalent to `getProperty(name,false,false,false)`.
|
||||||
*/
|
*/
|
||||||
public fun getOwnProperty(name: Name): MetaItem<*>?
|
public fun getOwnProperty(name: Name): MetaItem<*>?
|
||||||
|
|
||||||
@ -46,13 +47,13 @@ public interface Vision : Described {
|
|||||||
/**
|
/**
|
||||||
* Set the property value
|
* Set the property value
|
||||||
*/
|
*/
|
||||||
public fun setProperty(name: Name, item: MetaItem<*>?)
|
public fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean = true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flow of property invalidation events. It does not contain property values after invalidation since it is not clear
|
* Flow of property invalidation events. It does not contain property values after invalidation since it is not clear
|
||||||
* if it should include inherited properties etc.
|
* if it should include inherited properties etc.
|
||||||
*/
|
*/
|
||||||
public val propertyInvalidated: Flow<Name>
|
public val propertyNameFlow: Flow<Name>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,20 +61,6 @@ public interface Vision : Described {
|
|||||||
*/
|
*/
|
||||||
public fun notifyPropertyChanged(propertyName: Name): Unit
|
public fun notifyPropertyChanged(propertyName: Name): Unit
|
||||||
|
|
||||||
/**
|
|
||||||
* List of names of styles applied to this object. Order matters. Not inherited.
|
|
||||||
*/
|
|
||||||
public var styles: List<String>
|
|
||||||
get() = getProperty(
|
|
||||||
STYLE_KEY,
|
|
||||||
inherit = false,
|
|
||||||
includeStyles = false,
|
|
||||||
includeDefaults = true
|
|
||||||
)?.stringList ?: emptyList()
|
|
||||||
set(value) {
|
|
||||||
setProperty(STYLE_KEY, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update this vision using external meta. Children are not updated.
|
* Update this vision using external meta. Children are not updated.
|
||||||
*/
|
*/
|
||||||
@ -90,18 +77,26 @@ public interface Vision : Described {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenient accessor for all properties of a vision. Provided properties include styles and defaults, but do not inherit.
|
* Convenient accessor for all properties of a vision.
|
||||||
|
* @param inherit - inherit property value from the parent by default. If null, inheritance is inferred from descriptor
|
||||||
*/
|
*/
|
||||||
public val Vision.properties: MutableItemProvider
|
public fun Vision.allProperties(
|
||||||
get() = object : MutableItemProvider {
|
inherit: Boolean? = null,
|
||||||
override fun getItem(name: Name): MetaItem<*>? = getProperty(name,
|
includeStyles: Boolean = true,
|
||||||
inherit = false,
|
includeDefaults: Boolean = true,
|
||||||
includeStyles = true,
|
): MutableItemProvider = object : MutableItemProvider {
|
||||||
includeDefaults = true
|
override fun getItem(name: Name): MetaItem<*>? {
|
||||||
|
val actualInherit = inherit ?: descriptor?.get(name)?.inherited ?: false
|
||||||
|
return getProperty(
|
||||||
|
name,
|
||||||
|
inherit = actualInherit,
|
||||||
|
includeStyles = includeStyles,
|
||||||
|
includeDefaults = includeDefaults
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun setItem(name: Name, item: MetaItem<*>?): Unit = setProperty(name, item)
|
override fun setItem(name: Name, item: MetaItem<*>?): Unit = setProperty(name, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get [Vision] property using key as a String
|
* Get [Vision] property using key as a String
|
||||||
@ -116,31 +111,13 @@ public fun Vision.getProperty(
|
|||||||
/**
|
/**
|
||||||
* A convenience method to pair [getProperty]
|
* A convenience method to pair [getProperty]
|
||||||
*/
|
*/
|
||||||
public fun Vision.setProperty(key: Name, value: Any?) {
|
public fun Vision.setProperty(key: Name, item: Any?) {
|
||||||
properties[key] = value
|
setProperty(key, MetaItem.of(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to pair [getProperty]
|
* A convenience method to pair [getProperty]
|
||||||
*/
|
*/
|
||||||
public fun Vision.setProperty(key: String, value: Any?) {
|
public fun Vision.setProperty(key: String, item: Any?) {
|
||||||
properties[key] = value
|
setProperty(key.toName(), MetaItem.of(item))
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control visibility of the element
|
|
||||||
*/
|
|
||||||
public var Vision.visible: Boolean?
|
|
||||||
get() = getProperty(VISIBLE_KEY).boolean
|
|
||||||
set(value) = setProperty(VISIBLE_KEY, value?.asValue())
|
|
||||||
|
|
||||||
public fun Vision.props(inherit: Boolean = true): MutableItemProvider = object : MutableItemProvider {
|
|
||||||
override fun getItem(name: Name): MetaItem<*>? {
|
|
||||||
return getProperty(name, inherit)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setItem(name: Name, item: MetaItem<*>?) {
|
|
||||||
setProperty(name, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,9 +1,12 @@
|
|||||||
package hep.dataforge.vision
|
package hep.dataforge.vision
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.Config
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.MutableMeta
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.meta.descriptors.defaultItem
|
import hep.dataforge.meta.descriptors.defaultItem
|
||||||
import hep.dataforge.meta.descriptors.get
|
import hep.dataforge.meta.descriptors.get
|
||||||
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
@ -30,34 +33,28 @@ public open class VisionBase : Vision {
|
|||||||
/**
|
/**
|
||||||
* Object own properties excluding styles and inheritance
|
* Object own properties excluding styles and inheritance
|
||||||
*/
|
*/
|
||||||
@SerialName("properties")
|
public var properties: Config? = null
|
||||||
protected var innerProperties: Config? = null
|
|
||||||
private set
|
private set
|
||||||
|
|
||||||
/**
|
|
||||||
* All own properties as a read-only Meta
|
|
||||||
*/
|
|
||||||
public val ownProperties: Meta get() = innerProperties ?: Meta.EMPTY
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun getOrCreateConfig(): Config {
|
private fun getOrCreateConfig(): Config {
|
||||||
if (innerProperties == null) {
|
if (properties == null) {
|
||||||
val newProperties = Config()
|
val newProperties = Config()
|
||||||
innerProperties = newProperties
|
properties = newProperties
|
||||||
newProperties.onChange(this) { name, oldItem, newItem ->
|
newProperties.onChange(this) { name, oldItem, newItem ->
|
||||||
if (oldItem != newItem) {
|
if (oldItem != newItem) {
|
||||||
notifyPropertyChanged(name)
|
notifyPropertyChanged(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return innerProperties!!
|
return properties!!
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fast accessor method to get own property (no inheritance or styles
|
* A fast accessor method to get own property (no inheritance or styles
|
||||||
*/
|
*/
|
||||||
override fun getOwnProperty(name: Name): MetaItem<*>? {
|
override fun getOwnProperty(name: Name): MetaItem<*>? {
|
||||||
return innerProperties?.getItem(name)
|
return properties?.getItem(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getProperty(
|
override fun getProperty(
|
||||||
@ -77,10 +74,12 @@ public open class VisionBase : Vision {
|
|||||||
}.merge()
|
}.merge()
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun setProperty(name: Name, item: MetaItem<*>?) {
|
override fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean) {
|
||||||
getOrCreateConfig().setItem(name, item)
|
getOrCreateConfig().setItem(name, item)
|
||||||
|
if(notify) {
|
||||||
notifyPropertyChanged(name)
|
notifyPropertyChanged(name)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor? get() = null
|
override val descriptor: NodeDescriptor? get() = null
|
||||||
|
|
||||||
@ -96,11 +95,11 @@ public open class VisionBase : Vision {
|
|||||||
@Transient
|
@Transient
|
||||||
private val _propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()
|
private val _propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()
|
||||||
|
|
||||||
override val propertyInvalidated: SharedFlow<Name> get() = _propertyInvalidationFlow
|
override val propertyNameFlow: SharedFlow<Name> get() = _propertyInvalidationFlow
|
||||||
|
|
||||||
override fun notifyPropertyChanged(propertyName: Name) {
|
override fun notifyPropertyChanged(propertyName: Name) {
|
||||||
if (propertyName == STYLE_KEY) {
|
if (propertyName == STYLE_KEY) {
|
||||||
updateStyles(properties.getItem(STYLE_KEY)?.stringList ?: emptyList())
|
updateStyles(styles)
|
||||||
}
|
}
|
||||||
|
|
||||||
_propertyInvalidationFlow.tryEmit(propertyName)
|
_propertyInvalidationFlow.tryEmit(propertyName)
|
||||||
|
@ -64,7 +64,7 @@ private fun Vision.isolate(manager: VisionManager): Vision {
|
|||||||
public class VisionChange(
|
public class VisionChange(
|
||||||
public val reset: Boolean = false,
|
public val reset: Boolean = false,
|
||||||
public val vision: Vision? = null,
|
public val vision: Vision? = null,
|
||||||
public val properties: Meta? = null,
|
@Serializable(MetaSerializer::class) public val properties: Meta? = null,
|
||||||
public val children: Map<Name, VisionChange>? = null,
|
public val children: Map<Name, VisionChange>? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ private fun CoroutineScope.collectChange(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
//Collect properties change
|
//Collect properties change
|
||||||
source.propertyInvalidated.onEach { propertyName ->
|
source.propertyNameFlow.onEach { propertyName ->
|
||||||
val newItem = source.getProperty(propertyName, inherit = false, includeStyles = false, includeDefaults = false)
|
val newItem = source.getProperty(propertyName, inherit = false, includeStyles = false, includeDefaults = false)
|
||||||
collector().propertyChanged(name, propertyName, newItem)
|
collector().propertyChanged(name, propertyName, newItem)
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
|
@ -31,16 +31,15 @@ public inline fun <reified E : Enum<E>> NodeDescriptor.enum(key: Name, default:
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
public val Vision.ownProperties: Meta?
|
public val Vision.properties: Config?
|
||||||
get() = (this as? VisionBase)?.ownProperties
|
get() = (this as? VisionBase)?.properties
|
||||||
|
|
||||||
@DFExperimental
|
/**
|
||||||
public val Vision.describedProperties: Meta
|
* Control visibility of the element
|
||||||
get() = Meta {
|
*/
|
||||||
descriptor?.items?.forEach { (key, _) ->
|
public var Vision.visible: Boolean?
|
||||||
key put getProperty(key)
|
get() = getProperty(Vision.VISIBLE_KEY).boolean
|
||||||
}
|
set(value) = setProperty(Vision.VISIBLE_KEY, value?.asValue())
|
||||||
}
|
|
||||||
|
|
||||||
public fun Vision.configure(meta: Meta?): Unit = update(VisionChange(properties = meta))
|
public fun Vision.configure(meta: Meta?): Unit = update(VisionChange(properties = meta))
|
||||||
|
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package hep.dataforge.vision
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.boolean
|
||||||
|
import hep.dataforge.meta.descriptors.ItemDescriptor
|
||||||
|
import hep.dataforge.meta.descriptors.attributes
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.set
|
||||||
|
|
||||||
|
private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited"
|
||||||
|
|
||||||
|
public var ItemDescriptor.inherited: Boolean
|
||||||
|
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
|
||||||
|
set(value) = attributes {
|
||||||
|
set(INHERITED_DESCRIPTOR_ATTRIBUTE, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public val Vision.describedProperties: Meta
|
||||||
|
get() = Meta {
|
||||||
|
descriptor?.items?.forEach { (key, descriptor) ->
|
||||||
|
key put getProperty(key, inherit = descriptor.inherited)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,8 +19,8 @@ class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() {
|
|||||||
constructor(
|
constructor(
|
||||||
item: Vision?,
|
item: Vision?,
|
||||||
descriptor: NodeDescriptor?,
|
descriptor: NodeDescriptor?,
|
||||||
selector: (Vision) -> MutableItemProvider = { it.properties }
|
selector: (Vision) -> MutableItemProvider = { it.allProperties() },
|
||||||
) : this({it.describedProperties}) {
|
) : this({ it.describedProperties }) {
|
||||||
this.item = item
|
this.item = item
|
||||||
this.descriptorProperty.set(descriptor)
|
this.descriptorProperty.set(descriptor)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class FXReferenceFactory(val plugin: FX3DPlugin) : FX3DFactory<SolidReferenceGro
|
|||||||
val prototype = obj.prototype
|
val prototype = obj.prototype
|
||||||
val node = plugin.buildNode(prototype)
|
val node = plugin.buildNode(prototype)
|
||||||
|
|
||||||
obj.propertyInvalidated.onEach { name->
|
obj.propertyNameFlow.onEach { name->
|
||||||
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
|
@ -18,7 +18,7 @@ class VisualObjectFXBinding(val fx: FX3DPlugin, val obj: Vision) {
|
|||||||
private val bindings = HashMap<Name, ObjectBinding<MetaItem<*>?>>()
|
private val bindings = HashMap<Name, ObjectBinding<MetaItem<*>?>>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
obj.propertyInvalidated.onEach { name ->
|
obj.propertyNameFlow.onEach { name ->
|
||||||
bindings.filter { it.key.startsWith(name) }.forEach { entry ->
|
bindings.filter { it.key.startsWith(name) }.forEach { entry ->
|
||||||
Platform.runLater {
|
Platform.runLater {
|
||||||
entry.value.invalidate()
|
entry.value.invalidate()
|
||||||
|
@ -38,7 +38,6 @@ public class GDMLTransformerSettings {
|
|||||||
|
|
||||||
public var solidAction: (GDMLSolid) -> Action = { Action.PROTOTYPE }
|
public var solidAction: (GDMLSolid) -> Action = { Action.PROTOTYPE }
|
||||||
public var volumeAction: (GDMLGroup) -> Action = { Action.PROTOTYPE }
|
public var volumeAction: (GDMLGroup) -> Action = { Action.PROTOTYPE }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GDMLTransformer(val settings: GDMLTransformerSettings) {
|
private class GDMLTransformer(val settings: GDMLTransformerSettings) {
|
||||||
@ -324,7 +323,7 @@ private class GDMLTransformer(val settings: GDMLTransformerSettings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finalize(final: SolidGroup): SolidGroup {
|
private fun finalize(final: SolidGroup): SolidGroup {
|
||||||
//final.prototypes = proto
|
//final.prototypes = proto
|
||||||
final.useStyle("GDML") {
|
final.useStyle("GDML") {
|
||||||
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
|
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
|
||||||
|
@ -3,7 +3,6 @@ package hep.dataforge.vision.gdml
|
|||||||
import hep.dataforge.meta.DFExperimental
|
import hep.dataforge.meta.DFExperimental
|
||||||
import hep.dataforge.meta.sequence
|
import hep.dataforge.meta.sequence
|
||||||
import hep.dataforge.vision.Vision
|
import hep.dataforge.vision.Vision
|
||||||
import hep.dataforge.vision.ownProperties
|
|
||||||
import hep.dataforge.vision.properties
|
import hep.dataforge.vision.properties
|
||||||
import hep.dataforge.vision.solid.*
|
import hep.dataforge.vision.solid.*
|
||||||
|
|
||||||
@ -28,8 +27,8 @@ internal fun Vision.updateFrom(other: Vision): Vision {
|
|||||||
scaleY = scaleY.toDouble() * other.scaleY.toDouble()
|
scaleY = scaleY.toDouble() * other.scaleY.toDouble()
|
||||||
scaleZ = scaleZ.toDouble() * other.scaleZ.toDouble()
|
scaleZ = scaleZ.toDouble() * other.scaleZ.toDouble()
|
||||||
}
|
}
|
||||||
other.ownProperties?.sequence()?.forEach { (name, item) ->
|
other.properties?.sequence()?.forEach { (name, item) ->
|
||||||
if (properties.getItem(name) == null) {
|
if (getProperty(name) == null) {
|
||||||
setProperty(name, item)
|
setProperty(name, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package hep.dataforge.vision.solid
|
package hep.dataforge.vision.solid
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.vision.*
|
import hep.dataforge.vision.*
|
||||||
@ -39,7 +40,7 @@ public inline fun VisionContainerBuilder<Solid>.composite(
|
|||||||
val children = group.children.values.filterIsInstance<Solid>()
|
val children = group.children.values.filterIsInstance<Solid>()
|
||||||
if (children.size != 2) error("Composite requires exactly two children")
|
if (children.size != 2) error("Composite requires exactly two children")
|
||||||
return Composite(type, children[0], children[1]).also {
|
return Composite(type, children[0], children[1]).also {
|
||||||
it.configure { update(group.ownProperties) }
|
it.configure { update(group.properties ?: Meta.EMPTY) }
|
||||||
if (group.position != null) {
|
if (group.position != null) {
|
||||||
it.position = group.position
|
it.position = group.position
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import hep.dataforge.names.asName
|
|||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.vision.VisionBuilder
|
import hep.dataforge.vision.VisionBuilder
|
||||||
import hep.dataforge.vision.VisionContainerBuilder
|
import hep.dataforge.vision.VisionContainerBuilder
|
||||||
import hep.dataforge.vision.props
|
import hep.dataforge.vision.allProperties
|
||||||
import hep.dataforge.vision.set
|
import hep.dataforge.vision.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@ -16,7 +16,7 @@ import kotlinx.serialization.Serializable
|
|||||||
public class PolyLine(public var points: List<Point3D>) : SolidBase(), Solid {
|
public class PolyLine(public var points: List<Point3D>) : SolidBase(), Solid {
|
||||||
|
|
||||||
//var lineType by string()
|
//var lineType by string()
|
||||||
public var thickness: Number by props().number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)
|
public var thickness: Number by allProperties(inherit = false).number(1.0, key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val THICKNESS_KEY: Name = "thickness".asName()
|
public val THICKNESS_KEY: Name = "thickness".asName()
|
||||||
|
@ -81,7 +81,7 @@ public interface Solid : Vision {
|
|||||||
if (first.position != second.position) return false
|
if (first.position != second.position) return false
|
||||||
if (first.rotation != second.rotation) return false
|
if (first.rotation != second.rotation) return false
|
||||||
if (first.scale != second.scale) return false
|
if (first.scale != second.scale) return false
|
||||||
if (first.ownProperties != second.ownProperties) return false
|
if (first.properties != second.properties) return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ public interface Solid : Vision {
|
|||||||
var result = +(solid.position?.hashCode() ?: 0)
|
var result = +(solid.position?.hashCode() ?: 0)
|
||||||
result = 31 * result + (solid.rotation?.hashCode() ?: 0)
|
result = 31 * result + (solid.rotation?.hashCode() ?: 0)
|
||||||
result = 31 * result + (solid.scale?.hashCode() ?: 0)
|
result = 31 * result + (solid.scale?.hashCode() ?: 0)
|
||||||
result = 31 * result + solid.properties.hashCode()
|
result = 31 * result + solid.allProperties().hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ 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() = properties.getItem(LAYER_KEY).int ?: 0
|
get() = allProperties().getItem(LAYER_KEY).int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(LAYER_KEY, value)
|
setProperty(LAYER_KEY, value)
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ internal class Prototypes(
|
|||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): MetaItem<*>? = null
|
): MetaItem<*>? = null
|
||||||
|
|
||||||
override fun setProperty(name: Name, item: MetaItem<*>?) {
|
override fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ public operator fun ColorAccessor?.invoke(webColor: String) {
|
|||||||
* Set color as RGB integer
|
* Set color as RGB integer
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(rgb: Int) {
|
public operator fun ColorAccessor?.invoke(rgb: Int) {
|
||||||
this?.value = rgb.asValue()
|
this?.value = Colors.rgbToString(rgb).asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,7 +112,15 @@ public class SolidMaterial : Scheme() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public val Solid.color: ColorAccessor get() = ColorAccessor(properties, MATERIAL_COLOR_KEY)
|
public val Solid.color: ColorAccessor
|
||||||
|
get() = ColorAccessor(
|
||||||
|
allProperties(
|
||||||
|
inherit = true,
|
||||||
|
includeStyles = true,
|
||||||
|
includeDefaults = true
|
||||||
|
),
|
||||||
|
MATERIAL_COLOR_KEY
|
||||||
|
)
|
||||||
|
|
||||||
public var Solid.material: SolidMaterial?
|
public var Solid.material: SolidMaterial?
|
||||||
get() = getProperty(MATERIAL_KEY).node?.let { SolidMaterial.read(it) }
|
get() = getProperty(MATERIAL_KEY).node?.let { SolidMaterial.read(it) }
|
||||||
@ -120,7 +128,11 @@ public var Solid.material: SolidMaterial?
|
|||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||||
val node = properties.getItem(MATERIAL_KEY).node
|
val node = allProperties(
|
||||||
|
inherit = true,
|
||||||
|
includeStyles = true,
|
||||||
|
includeDefaults = true
|
||||||
|
).getItem(MATERIAL_KEY).node
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
SolidMaterial.update(node, builder)
|
SolidMaterial.update(node, builder)
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,12 +47,12 @@ public class SolidReferenceGroup(
|
|||||||
return getOwnProperty(childPropertyName(childName, propertyName))
|
return getOwnProperty(childPropertyName(childName, propertyName))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setChildProperty(childName: Name, propertyName: Name, item: MetaItem<*>?) {
|
private fun setChildProperty(childName: Name, propertyName: Name, item: MetaItem<*>?, notify: Boolean) {
|
||||||
setProperty(childPropertyName(childName, propertyName), item)
|
setProperty(childPropertyName(childName, propertyName), item, notify)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prototypeFor(name: Name): Solid {
|
private fun prototypeFor(name: Name): Solid {
|
||||||
return if(name.isEmpty()) prototype else {
|
return if (name.isEmpty()) prototype else {
|
||||||
(prototype as? SolidGroup)?.get(name) as? Solid
|
(prototype as? SolidGroup)?.get(name) as? Solid
|
||||||
?: error("Prototype with name $name not found in $this")
|
?: error("Prototype with name $name not found in $this")
|
||||||
}
|
}
|
||||||
@ -98,8 +98,8 @@ public class SolidReferenceGroup(
|
|||||||
|
|
||||||
override fun getOwnProperty(name: Name): MetaItem<*>? = getChildProperty(childName, name)
|
override fun getOwnProperty(name: Name): MetaItem<*>? = getChildProperty(childName, name)
|
||||||
|
|
||||||
override fun setProperty(name: Name, item: MetaItem<*>?) {
|
override fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean) {
|
||||||
setChildProperty(childName, name, item)
|
setChildProperty(childName, name, item, notify)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getProperty(
|
override fun getProperty(
|
||||||
@ -119,16 +119,16 @@ public class SolidReferenceGroup(
|
|||||||
}.merge()
|
}.merge()
|
||||||
|
|
||||||
override var parent: VisionGroup?
|
override var parent: VisionGroup?
|
||||||
get(){
|
get() {
|
||||||
val parentName = childName.cutLast()
|
val parentName = childName.cutLast()
|
||||||
return if( parentName.isEmpty()) this@SolidReferenceGroup else ReferenceChild(parentName)
|
return if (parentName.isEmpty()) this@SolidReferenceGroup else ReferenceChild(parentName)
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
error("Setting a parent for a reference child is not possible")
|
error("Setting a parent for a reference child is not possible")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val propertyInvalidated: Flow<Name>
|
override val propertyNameFlow: Flow<Name>
|
||||||
get() = this@SolidReferenceGroup.propertyInvalidated.filter { name ->
|
get() = this@SolidReferenceGroup.propertyNameFlow.filter { name ->
|
||||||
name.startsWith(childToken(childName))
|
name.startsWith(childToken(childName))
|
||||||
}.map { name ->
|
}.map { name ->
|
||||||
name.cutFirst()
|
name.cutFirst()
|
||||||
|
@ -9,7 +9,7 @@ import hep.dataforge.vision.solid.*
|
|||||||
internal fun mergeChild(parent: VisionGroup, child: Vision): Vision {
|
internal fun mergeChild(parent: VisionGroup, child: Vision): Vision {
|
||||||
return child.apply {
|
return child.apply {
|
||||||
|
|
||||||
configure(parent.ownProperties)
|
configure(parent.properties)
|
||||||
|
|
||||||
//parent.properties?.let { config.update(it) }
|
//parent.properties?.let { config.update(it) }
|
||||||
|
|
||||||
|
@ -2,10 +2,7 @@ package hep.dataforge.vision.solid
|
|||||||
|
|
||||||
import hep.dataforge.meta.int
|
import hep.dataforge.meta.int
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.vision.getProperty
|
import hep.dataforge.vision.*
|
||||||
import hep.dataforge.vision.setProperty
|
|
||||||
import hep.dataforge.vision.styleSheet
|
|
||||||
import hep.dataforge.vision.useStyle
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import hep.dataforge.names.Name
|
|||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vision.MutableVisionGroup
|
import hep.dataforge.vision.MutableVisionGroup
|
||||||
import hep.dataforge.vision.get
|
import hep.dataforge.vision.get
|
||||||
import hep.dataforge.vision.ownProperties
|
import hep.dataforge.vision.properties
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class SerializationTest {
|
|||||||
val string = SolidManager.encodeToString(cube)
|
val string = SolidManager.encodeToString(cube)
|
||||||
println(string)
|
println(string)
|
||||||
val newCube = SolidManager.decodeFromString(string)
|
val newCube = SolidManager.decodeFromString(string)
|
||||||
assertEquals(cube.ownProperties, newCube.ownProperties)
|
assertEquals(cube.properties, newCube.properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -54,7 +54,7 @@ class SerializationTest {
|
|||||||
val string = SolidManager.encodeToString(group)
|
val string = SolidManager.encodeToString(group)
|
||||||
println(string)
|
println(string)
|
||||||
val reconstructed = SolidManager.decodeFromString(string) as SolidGroup
|
val reconstructed = SolidManager.decodeFromString(string) as SolidGroup
|
||||||
assertEquals(group["cube"]?.ownProperties, reconstructed["cube"]?.ownProperties)
|
assertEquals(group["cube"]?.properties, reconstructed["cube"]?.properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -29,7 +29,7 @@ class VisionUpdateTest {
|
|||||||
targetVision.update(dif)
|
targetVision.update(dif)
|
||||||
assertTrue { targetVision["top"] is SolidGroup }
|
assertTrue { targetVision["top"] is SolidGroup }
|
||||||
assertEquals("red", (targetVision["origin"] as Solid).color.string) // Should work
|
assertEquals("red", (targetVision["origin"] as Solid).color.string) // Should work
|
||||||
assertEquals("#00007b", (targetVision["top"] as SolidGroup).color.string) // new item always takes precedence
|
assertEquals("#00007b", (targetVision["top"] as Solid).color.string) // new item always takes precedence
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -45,7 +45,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
}.applyProperties(obj)
|
}.applyProperties(obj)
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.propertyInvalidated.onEach { name ->
|
obj.propertyNameFlow.onEach { name ->
|
||||||
when {
|
when {
|
||||||
name.startsWith(Solid.GEOMETRY_KEY) -> {
|
name.startsWith(Solid.GEOMETRY_KEY) -> {
|
||||||
val oldGeometry = mesh.geometry as BufferGeometry
|
val oldGeometry = mesh.geometry as BufferGeometry
|
||||||
|
@ -27,7 +27,7 @@ public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
|||||||
})
|
})
|
||||||
return Mesh(textGeo, getMaterial(obj, true)).apply {
|
return Mesh(textGeo, getMaterial(obj, true)).apply {
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
obj.propertyInvalidated.onEach { _ ->
|
obj.propertyNameFlow.onEach { _ ->
|
||||||
//TODO
|
//TODO
|
||||||
three.logger.warn{"Label parameter change not implemented"}
|
three.logger.warn{"Label parameter change not implemented"}
|
||||||
}.launchIn(three.updateScope)
|
}.launchIn(three.updateScope)
|
||||||
|
@ -30,7 +30,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
|||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
//layers.enable(obj.layer)
|
//layers.enable(obj.layer)
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.propertyInvalidated.onEach { propertyName ->
|
obj.propertyNameFlow.onEach { propertyName ->
|
||||||
updateProperty(obj, propertyName)
|
updateProperty(obj, propertyName)
|
||||||
}.launchIn(three.updateScope)
|
}.launchIn(three.updateScope)
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
//obj.onChildrenChange()
|
//obj.onChildrenChange()
|
||||||
|
|
||||||
obj.propertyInvalidated.onEach { name ->
|
obj.propertyNameFlow.onEach { name ->
|
||||||
if (
|
if (
|
||||||
name.startsWith(Solid.POSITION_KEY) ||
|
name.startsWith(Solid.POSITION_KEY) ||
|
||||||
name.startsWith(Solid.ROTATION) ||
|
name.startsWith(Solid.ROTATION) ||
|
||||||
|
@ -47,7 +47,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
|
|||||||
|
|
||||||
//TODO apply child properties
|
//TODO apply child properties
|
||||||
|
|
||||||
obj.propertyInvalidated.onEach { name->
|
obj.propertyNameFlow.onEach { name->
|
||||||
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
|
Loading…
Reference in New Issue
Block a user