New properties #34
@ -1,13 +1,9 @@
|
||||
package hep.dataforge.vision.bootstrap
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.vision.Vision
|
||||
import hep.dataforge.vision.allProperties
|
||||
import hep.dataforge.vision.getStyle
|
||||
import hep.dataforge.vision.*
|
||||
import hep.dataforge.vision.react.metaViewer
|
||||
import hep.dataforge.vision.react.propertyEditor
|
||||
import hep.dataforge.vision.styles
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.dom.render
|
||||
@ -19,7 +15,8 @@ public fun RBuilder.visionPropertyEditor(
|
||||
) {
|
||||
card("Properties") {
|
||||
propertyEditor(
|
||||
vision.allProperties(),
|
||||
provider = vision.ownProperties,
|
||||
defaultProvider = vision.allProperties(),
|
||||
updateFlow = vision.propertyNameFlow,
|
||||
descriptor = descriptor,
|
||||
key = key)
|
||||
@ -44,7 +41,6 @@ public fun RBuilder.visionPropertyEditor(
|
||||
public fun Element.visionPropertyEditor(
|
||||
item: Vision,
|
||||
descriptor: NodeDescriptor? = item.descriptor,
|
||||
default: Meta? = null,
|
||||
): Unit = render(this) {
|
||||
visionPropertyEditor(item, descriptor, default)
|
||||
visionPropertyEditor(item, descriptor = descriptor)
|
||||
}
|
@ -22,17 +22,22 @@ import react.*
|
||||
import react.dom.render
|
||||
import styled.*
|
||||
|
||||
public external interface PropertyEditorItemProps : RProps {
|
||||
public external interface PropertyEditorProps : RProps {
|
||||
|
||||
/**
|
||||
* Root config object - always non null
|
||||
*/
|
||||
public var provider: MutableItemProvider
|
||||
|
||||
/**
|
||||
* Provide default item (greyed out if used
|
||||
*/
|
||||
public var defaultProvider: ItemProvider?
|
||||
|
||||
/**
|
||||
* Full path to the displayed node in [provider]. Could be empty
|
||||
*/
|
||||
public var name: Name
|
||||
public var name: Name?
|
||||
|
||||
/**
|
||||
* Root descriptor
|
||||
@ -40,29 +45,35 @@ public external interface PropertyEditorItemProps : RProps {
|
||||
public var descriptor: NodeDescriptor?
|
||||
|
||||
|
||||
/**
|
||||
* A coroutine scope for updates
|
||||
*/
|
||||
public var scope: CoroutineScope?
|
||||
|
||||
/**
|
||||
*
|
||||
* Flow names of updated properties
|
||||
*/
|
||||
public var updateFlow: Flow<Name>?
|
||||
}
|
||||
|
||||
private val PropertyEditorItem: FunctionalComponent<PropertyEditorItemProps> =
|
||||
private val PropertyEditorItem: FunctionalComponent<PropertyEditorProps> =
|
||||
functionalComponent("ConfigEditorItem") { props ->
|
||||
propertyEditorItem(props)
|
||||
}
|
||||
|
||||
private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
|
||||
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
var expanded: Boolean by useState { true }
|
||||
var item: MetaItem<*>? by useState { props.provider.getItem(props.name) }
|
||||
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
|
||||
var actualItem: MetaItem<Meta>? by useState { item ?: descriptorItem?.defaultItem() }
|
||||
val itemName by useState { props.name ?: Name.EMPTY }
|
||||
var item: MetaItem<*>? by useState { props.provider.getItem(itemName) }
|
||||
val descriptorItem: ItemDescriptor? = props.descriptor?.get(itemName)
|
||||
var actualItem: MetaItem<Meta>? by useState {
|
||||
item ?: props.defaultProvider?.getItem(itemName) ?: descriptorItem?.defaultItem()
|
||||
}
|
||||
|
||||
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
||||
val token = itemName.lastOrNull()?.toString() ?: "Properties"
|
||||
|
||||
fun update() {
|
||||
item = props.provider.getItem(props.name)
|
||||
item = props.provider.getItem(itemName)
|
||||
actualItem = item ?: descriptorItem?.defaultItem()
|
||||
}
|
||||
|
||||
@ -83,15 +94,15 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
|
||||
|
||||
val valueChanged: (Value?) -> Unit = {
|
||||
if (it == null) {
|
||||
props.provider.remove(props.name)
|
||||
props.provider.remove(itemName)
|
||||
} else {
|
||||
props.provider[props.name] = it
|
||||
props.provider[itemName] = it
|
||||
}
|
||||
update()
|
||||
}
|
||||
|
||||
val removeClick: (Event) -> Unit = {
|
||||
props.provider.remove(props.name)
|
||||
props.provider.remove(itemName)
|
||||
update()
|
||||
}
|
||||
|
||||
@ -144,7 +155,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
|
||||
attrs {
|
||||
this.key = props.name.toString()
|
||||
this.provider = props.provider
|
||||
this.name = props.name + token
|
||||
this.name = itemName + token
|
||||
this.descriptor = props.descriptor
|
||||
}
|
||||
}
|
||||
@ -176,7 +187,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
|
||||
+TreeStyles.resizeableInput
|
||||
}
|
||||
valueChooser(
|
||||
props.name,
|
||||
itemName,
|
||||
actualItem,
|
||||
descriptorItem as? ValueDescriptor,
|
||||
valueChanged
|
||||
@ -200,19 +211,14 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
|
||||
}
|
||||
}
|
||||
|
||||
public external interface PropertyEditorProps : RProps {
|
||||
public var provider: MutableItemProvider
|
||||
public var updateFlow: Flow<Name>?
|
||||
public var descriptor: NodeDescriptor?
|
||||
public var scope: CoroutineScope?
|
||||
}
|
||||
|
||||
@JsExport
|
||||
public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functionalComponent("ConfigEditor") { props ->
|
||||
public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functionalComponent("PropertyEditor") { props ->
|
||||
child(PropertyEditorItem) {
|
||||
attrs {
|
||||
this.key = ""
|
||||
this.provider = props.provider
|
||||
this.defaultProvider = props.defaultProvider
|
||||
this.name = Name.EMPTY
|
||||
this.descriptor = props.descriptor
|
||||
this.scope = props.scope
|
||||
@ -222,17 +228,19 @@ public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functional
|
||||
|
||||
public fun RBuilder.propertyEditor(
|
||||
provider: MutableItemProvider,
|
||||
defaultProvider: ItemProvider?,
|
||||
updateFlow: Flow<Name>? = null,
|
||||
descriptor: NodeDescriptor? = null,
|
||||
key: Any? = null,
|
||||
scope: CoroutineScope? = null,
|
||||
key: Any? = null,
|
||||
) {
|
||||
child(PropertyEditor) {
|
||||
attrs {
|
||||
this.key = key?.toString() ?: ""
|
||||
this.provider = provider
|
||||
this.defaultProvider = defaultProvider
|
||||
this.updateFlow = updateFlow
|
||||
this.descriptor = descriptor
|
||||
this.key = key?.toString() ?: ""
|
||||
this.scope = scope
|
||||
}
|
||||
}
|
||||
@ -249,21 +257,14 @@ private fun Config.flowUpdates(): Flow<Name> = callbackFlow {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
default: ItemProvider? = null,
|
||||
descriptor: NodeDescriptor? = null,
|
||||
default: Meta? = null,
|
||||
key: Any? = null,
|
||||
scope: CoroutineScope? = null,
|
||||
) = propertyEditor(config.withDefault(default ?: ItemProvider.EMPTY), config.flowUpdates(), descriptor, key, scope)
|
||||
): Unit = propertyEditor(config, default, config.flowUpdates(), descriptor, scope, key = key)
|
||||
|
||||
public fun Element.configEditor(
|
||||
config: Config,
|
||||
@ -271,8 +272,6 @@ public fun Element.configEditor(
|
||||
default: Meta? = null,
|
||||
key: Any? = null,
|
||||
scope: CoroutineScope? = null,
|
||||
) {
|
||||
render(this) {
|
||||
configEditor(config,descriptor,default, key, scope)
|
||||
}
|
||||
): Unit = render(this) {
|
||||
configEditor(config, default, descriptor, key, scope)
|
||||
}
|
@ -4,7 +4,6 @@ import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.meta.MutableItemProvider
|
||||
import hep.dataforge.meta.descriptors.Described
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.meta.descriptors.get
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.toName
|
||||
@ -33,13 +32,13 @@ public interface Vision : Described {
|
||||
|
||||
/**
|
||||
* Get property.
|
||||
* @param inherit toggles parent node property lookup
|
||||
* @param includeStyles toggles inclusion of
|
||||
* @param inherit toggles parent node property lookup. Null means default inheritance.
|
||||
* @param includeStyles toggles inclusion of. Null means default style inclusion.
|
||||
*/
|
||||
public fun getProperty(
|
||||
name: Name,
|
||||
inherit: Boolean = true,
|
||||
includeStyles: Boolean = true,
|
||||
inherit: Boolean? = null,
|
||||
includeStyles: Boolean? = null,
|
||||
includeDefaults: Boolean = true,
|
||||
): MetaItem<*>?
|
||||
|
||||
@ -76,6 +75,16 @@ public interface Vision : Described {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Own properties, excluding inheritance, styles and descriptor
|
||||
*/
|
||||
public val Vision.ownProperties: MutableItemProvider
|
||||
get() = object : MutableItemProvider {
|
||||
override fun getItem(name: Name): MetaItem<*>? = getOwnProperty(name)
|
||||
override fun setItem(name: Name, item: MetaItem<*>?): Unit = setProperty(name, item)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -85,16 +94,12 @@ public fun Vision.allProperties(
|
||||
includeStyles: Boolean? = null,
|
||||
includeDefaults: Boolean = true,
|
||||
): MutableItemProvider = object : MutableItemProvider {
|
||||
override fun getItem(name: Name): MetaItem<*>? {
|
||||
val actualInherit = inherit ?: descriptor?.get(name)?.inherited ?: false
|
||||
val actualUseStyles = includeStyles ?: descriptor?.get(name)?.usesStyles ?: true
|
||||
return getProperty(
|
||||
name,
|
||||
inherit = actualInherit,
|
||||
includeStyles = actualUseStyles,
|
||||
includeDefaults = includeDefaults
|
||||
)
|
||||
}
|
||||
override fun getItem(name: Name): MetaItem<*>? = getProperty(
|
||||
name,
|
||||
inherit = inherit,
|
||||
includeStyles = includeStyles,
|
||||
includeDefaults = includeDefaults
|
||||
)
|
||||
|
||||
override fun setItem(name: Name, item: MetaItem<*>?): Unit = setProperty(name, item)
|
||||
}
|
||||
@ -104,8 +109,8 @@ public fun Vision.allProperties(
|
||||
*/
|
||||
public fun Vision.getProperty(
|
||||
key: String,
|
||||
inherit: Boolean = true,
|
||||
includeStyles: Boolean = true,
|
||||
inherit: Boolean? = null,
|
||||
includeStyles: Boolean? = null,
|
||||
includeDefaults: Boolean = true,
|
||||
): MetaItem<*>? = getProperty(key.toName(), inherit, includeStyles, includeDefaults)
|
||||
|
||||
|
@ -59,15 +59,15 @@ public open class VisionBase : Vision {
|
||||
|
||||
override fun getProperty(
|
||||
name: Name,
|
||||
inherit: Boolean,
|
||||
includeStyles: Boolean,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem<*>? = sequence {
|
||||
yield(getOwnProperty(name))
|
||||
if (includeStyles) {
|
||||
if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) {
|
||||
yieldAll(getStyleItems(name))
|
||||
}
|
||||
if (inherit) {
|
||||
if (inherit ?: descriptor?.get(name)?.inherited == true) {
|
||||
yield(parent?.getProperty(name, inherit))
|
||||
}
|
||||
yield(descriptor?.get(name)?.defaultItem())
|
||||
|
@ -125,8 +125,8 @@ internal class Prototypes(
|
||||
|
||||
override fun getProperty(
|
||||
name: Name,
|
||||
inherit: Boolean,
|
||||
includeStyles: Boolean,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem<*>? = null
|
||||
|
||||
|
@ -114,16 +114,12 @@ public class SolidMaterial : Scheme() {
|
||||
|
||||
public val Solid.color: ColorAccessor
|
||||
get() = ColorAccessor(
|
||||
allProperties(
|
||||
inherit = true,
|
||||
includeStyles = true,
|
||||
includeDefaults = true
|
||||
),
|
||||
allProperties(inherit = true),
|
||||
MATERIAL_COLOR_KEY
|
||||
)
|
||||
|
||||
public var Solid.material: SolidMaterial?
|
||||
get() = getProperty(MATERIAL_KEY).node?.let { SolidMaterial.read(it) }
|
||||
get() = getProperty(MATERIAL_KEY, inherit = true).node?.let { SolidMaterial.read(it) }
|
||||
set(value) = setProperty(MATERIAL_KEY, value?.config)
|
||||
|
||||
@VisionBuilder
|
||||
@ -141,7 +137,7 @@ public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||
}
|
||||
|
||||
public var Solid.opacity: Number?
|
||||
get() = getProperty(MATERIAL_OPACITY_KEY).number
|
||||
get() = getProperty(MATERIAL_OPACITY_KEY, inherit = true).number
|
||||
set(value) {
|
||||
setProperty(MATERIAL_OPACITY_KEY, value?.asValue())
|
||||
}
|
@ -2,6 +2,7 @@ package hep.dataforge.vision.solid
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.meta.descriptors.get
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.vision.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -14,6 +15,24 @@ public interface SolidReference : Vision {
|
||||
public val prototype: Solid
|
||||
}
|
||||
|
||||
private fun SolidReference.getRefProperty(
|
||||
name: Name,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem<*>? {
|
||||
return sequence {
|
||||
yield(getOwnProperty(name))
|
||||
if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) {
|
||||
yieldAll(getStyleItems(name))
|
||||
}
|
||||
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||
if (inherit ?: descriptor?.get(name)?.inherited == true) {
|
||||
yield(parent?.getProperty(name, inherit))
|
||||
}
|
||||
}.merge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference [Solid] to reuse a template object
|
||||
*/
|
||||
@ -60,19 +79,10 @@ public class SolidReferenceGroup(
|
||||
|
||||
override fun getProperty(
|
||||
name: Name,
|
||||
inherit: Boolean,
|
||||
includeStyles: Boolean,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem<*>? = sequence {
|
||||
yield(getOwnProperty(name))
|
||||
if (includeStyles) {
|
||||
yieldAll(getStyleItems(name))
|
||||
}
|
||||
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||
if (inherit) {
|
||||
yield(parent?.getProperty(name, inherit))
|
||||
}
|
||||
}.merge()
|
||||
): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
||||
|
||||
override fun attachChildren() {
|
||||
//do nothing
|
||||
@ -104,19 +114,10 @@ public class SolidReferenceGroup(
|
||||
|
||||
override fun getProperty(
|
||||
name: Name,
|
||||
inherit: Boolean,
|
||||
includeStyles: Boolean,
|
||||
inherit: Boolean?,
|
||||
includeStyles: Boolean?,
|
||||
includeDefaults: Boolean,
|
||||
): MetaItem<*>? = sequence {
|
||||
yield(getOwnProperty(name))
|
||||
if (includeStyles) {
|
||||
yieldAll(getStyleItems(name))
|
||||
}
|
||||
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||
if (inherit) {
|
||||
yield(parent?.getProperty(name, inherit))
|
||||
}
|
||||
}.merge()
|
||||
): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
||||
|
||||
override var parent: VisionGroup?
|
||||
get() {
|
||||
|
@ -17,7 +17,7 @@ class PropertyTest {
|
||||
box = box(100, 100, 100)
|
||||
}
|
||||
}
|
||||
assertEquals(22, box?.getProperty("test").int)
|
||||
assertEquals(22, box?.getProperty("test", inherit = true).int)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user