Fix getProperty defaults

This commit is contained in:
Alexander Nozik 2020-12-19 15:59:41 +03:00
parent be1d79c229
commit 6939fba292
8 changed files with 97 additions and 100 deletions

View File

@ -1,13 +1,9 @@
package hep.dataforge.vision.bootstrap package hep.dataforge.vision.bootstrap
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.*
import hep.dataforge.vision.allProperties
import hep.dataforge.vision.getStyle
import hep.dataforge.vision.react.metaViewer import hep.dataforge.vision.react.metaViewer
import hep.dataforge.vision.react.propertyEditor import hep.dataforge.vision.react.propertyEditor
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
@ -19,7 +15,8 @@ public fun RBuilder.visionPropertyEditor(
) { ) {
card("Properties") { card("Properties") {
propertyEditor( propertyEditor(
vision.allProperties(), provider = vision.ownProperties,
defaultProvider = vision.allProperties(),
updateFlow = vision.propertyNameFlow, updateFlow = vision.propertyNameFlow,
descriptor = descriptor, descriptor = descriptor,
key = key) key = key)
@ -44,7 +41,6 @@ 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,
): Unit = render(this) { ): Unit = render(this) {
visionPropertyEditor(item, descriptor, default) visionPropertyEditor(item, descriptor = descriptor)
} }

View File

@ -22,17 +22,22 @@ import react.*
import react.dom.render import react.dom.render
import styled.* import styled.*
public external interface PropertyEditorItemProps : RProps { public external interface PropertyEditorProps : RProps {
/** /**
* Root config object - always non null * Root config object - always non null
*/ */
public var provider: MutableItemProvider 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 * Full path to the displayed node in [provider]. Could be empty
*/ */
public var name: Name public var name: Name?
/** /**
* Root descriptor * Root descriptor
@ -40,29 +45,35 @@ public external interface PropertyEditorItemProps : RProps {
public var descriptor: NodeDescriptor? public var descriptor: NodeDescriptor?
/**
* A coroutine scope for updates
*/
public var scope: CoroutineScope? public var scope: CoroutineScope?
/** /**
* * Flow names of updated properties
*/ */
public var updateFlow: Flow<Name>? public var updateFlow: Flow<Name>?
} }
private val PropertyEditorItem: FunctionalComponent<PropertyEditorItemProps> = private val PropertyEditorItem: FunctionalComponent<PropertyEditorProps> =
functionalComponent("ConfigEditorItem") { props -> functionalComponent("ConfigEditorItem") { props ->
propertyEditorItem(props) propertyEditorItem(props)
} }
private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) { private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
var expanded: Boolean by useState { true } var expanded: Boolean by useState { true }
var item: MetaItem<*>? by useState { props.provider.getItem(props.name) } val itemName by useState { props.name ?: Name.EMPTY }
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) var item: MetaItem<*>? by useState { props.provider.getItem(itemName) }
var actualItem: MetaItem<Meta>? by useState { item ?: descriptorItem?.defaultItem() } 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() { fun update() {
item = props.provider.getItem(props.name) item = props.provider.getItem(itemName)
actualItem = item ?: descriptorItem?.defaultItem() actualItem = item ?: descriptorItem?.defaultItem()
} }
@ -83,15 +94,15 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
val valueChanged: (Value?) -> Unit = { val valueChanged: (Value?) -> Unit = {
if (it == null) { if (it == null) {
props.provider.remove(props.name) props.provider.remove(itemName)
} else { } else {
props.provider[props.name] = it props.provider[itemName] = it
} }
update() update()
} }
val removeClick: (Event) -> Unit = { val removeClick: (Event) -> Unit = {
props.provider.remove(props.name) props.provider.remove(itemName)
update() update()
} }
@ -144,7 +155,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
attrs { attrs {
this.key = props.name.toString() this.key = props.name.toString()
this.provider = props.provider this.provider = props.provider
this.name = props.name + token this.name = itemName + token
this.descriptor = props.descriptor this.descriptor = props.descriptor
} }
} }
@ -176,7 +187,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorItemProps) {
+TreeStyles.resizeableInput +TreeStyles.resizeableInput
} }
valueChooser( valueChooser(
props.name, itemName,
actualItem, actualItem,
descriptorItem as? ValueDescriptor, descriptorItem as? ValueDescriptor,
valueChanged 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 @JsExport
public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functionalComponent("ConfigEditor") { props -> public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functionalComponent("PropertyEditor") { props ->
child(PropertyEditorItem) { child(PropertyEditorItem) {
attrs { attrs {
this.key = "" this.key = ""
this.provider = props.provider this.provider = props.provider
this.defaultProvider = props.defaultProvider
this.name = Name.EMPTY this.name = Name.EMPTY
this.descriptor = props.descriptor this.descriptor = props.descriptor
this.scope = props.scope this.scope = props.scope
@ -222,17 +228,19 @@ public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functional
public fun RBuilder.propertyEditor( public fun RBuilder.propertyEditor(
provider: MutableItemProvider, provider: MutableItemProvider,
defaultProvider: ItemProvider?,
updateFlow: Flow<Name>? = null, updateFlow: Flow<Name>? = null,
descriptor: NodeDescriptor? = null, descriptor: NodeDescriptor? = null,
key: Any? = null,
scope: CoroutineScope? = null, scope: CoroutineScope? = null,
key: Any? = null,
) { ) {
child(PropertyEditor) { child(PropertyEditor) {
attrs { attrs {
this.key = key?.toString() ?: ""
this.provider = provider this.provider = provider
this.defaultProvider = defaultProvider
this.updateFlow = updateFlow this.updateFlow = updateFlow
this.descriptor = descriptor this.descriptor = descriptor
this.key = key?.toString() ?: ""
this.scope = scope 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( public fun RBuilder.configEditor(
config: Config, config: Config,
default: ItemProvider? = null,
descriptor: NodeDescriptor? = null, descriptor: NodeDescriptor? = null,
default: Meta? = null,
key: Any? = null, key: Any? = null,
scope: CoroutineScope? = 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( public fun Element.configEditor(
config: Config, config: Config,
@ -271,8 +272,6 @@ public fun Element.configEditor(
default: Meta? = null, default: Meta? = null,
key: Any? = null, key: Any? = null,
scope: CoroutineScope? = null, scope: CoroutineScope? = null,
) { ): Unit = render(this) {
render(this) { configEditor(config, default, descriptor, key, scope)
configEditor(config,descriptor,default, key, scope)
}
} }

View File

@ -4,7 +4,6 @@ import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MutableItemProvider 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
@ -33,13 +32,13 @@ public interface Vision : Described {
/** /**
* Get property. * Get property.
* @param inherit toggles parent node property lookup * @param inherit toggles parent node property lookup. Null means default inheritance.
* @param includeStyles toggles inclusion of * @param includeStyles toggles inclusion of. Null means default style inclusion.
*/ */
public fun getProperty( public fun getProperty(
name: Name, name: Name,
inherit: Boolean = true, inherit: Boolean? = null,
includeStyles: Boolean = true, includeStyles: Boolean? = null,
includeDefaults: Boolean = true, includeDefaults: Boolean = true,
): MetaItem<*>? ): 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. * 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 * @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, includeStyles: Boolean? = null,
includeDefaults: Boolean = true, includeDefaults: Boolean = true,
): MutableItemProvider = object : MutableItemProvider { ): MutableItemProvider = object : MutableItemProvider {
override fun getItem(name: Name): MetaItem<*>? { override fun getItem(name: Name): MetaItem<*>? = getProperty(
val actualInherit = inherit ?: descriptor?.get(name)?.inherited ?: false name,
val actualUseStyles = includeStyles ?: descriptor?.get(name)?.usesStyles ?: true inherit = inherit,
return getProperty( includeStyles = includeStyles,
name, includeDefaults = includeDefaults
inherit = actualInherit, )
includeStyles = actualUseStyles,
includeDefaults = includeDefaults
)
}
override fun setItem(name: Name, item: MetaItem<*>?): Unit = setProperty(name, item) override fun setItem(name: Name, item: MetaItem<*>?): Unit = setProperty(name, item)
} }
@ -104,8 +109,8 @@ public fun Vision.allProperties(
*/ */
public fun Vision.getProperty( public fun Vision.getProperty(
key: String, key: String,
inherit: Boolean = true, inherit: Boolean? = null,
includeStyles: Boolean = true, includeStyles: Boolean? = null,
includeDefaults: Boolean = true, includeDefaults: Boolean = true,
): MetaItem<*>? = getProperty(key.toName(), inherit, includeStyles, includeDefaults) ): MetaItem<*>? = getProperty(key.toName(), inherit, includeStyles, includeDefaults)

View File

@ -59,15 +59,15 @@ public open class VisionBase : Vision {
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean?,
includeStyles: Boolean, includeStyles: Boolean?,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = sequence { ): MetaItem<*>? = sequence {
yield(getOwnProperty(name)) yield(getOwnProperty(name))
if (includeStyles) { if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) {
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
} }
if (inherit) { if (inherit ?: descriptor?.get(name)?.inherited == true) {
yield(parent?.getProperty(name, inherit)) yield(parent?.getProperty(name, inherit))
} }
yield(descriptor?.get(name)?.defaultItem()) yield(descriptor?.get(name)?.defaultItem())

View File

@ -125,8 +125,8 @@ internal class Prototypes(
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean?,
includeStyles: Boolean, includeStyles: Boolean?,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = null ): MetaItem<*>? = null

View File

@ -114,16 +114,12 @@ public class SolidMaterial : Scheme() {
public val Solid.color: ColorAccessor public val Solid.color: ColorAccessor
get() = ColorAccessor( get() = ColorAccessor(
allProperties( allProperties(inherit = true),
inherit = true,
includeStyles = true,
includeDefaults = true
),
MATERIAL_COLOR_KEY 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, inherit = true).node?.let { SolidMaterial.read(it) }
set(value) = setProperty(MATERIAL_KEY, value?.config) set(value) = setProperty(MATERIAL_KEY, value?.config)
@VisionBuilder @VisionBuilder
@ -141,7 +137,7 @@ public fun Solid.material(builder: SolidMaterial.() -> Unit) {
} }
public var Solid.opacity: Number? public var Solid.opacity: Number?
get() = getProperty(MATERIAL_OPACITY_KEY).number get() = getProperty(MATERIAL_OPACITY_KEY, inherit = true).number
set(value) { set(value) {
setProperty(MATERIAL_OPACITY_KEY, value?.asValue()) setProperty(MATERIAL_OPACITY_KEY, value?.asValue())
} }

View File

@ -2,6 +2,7 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.get
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.vision.* import hep.dataforge.vision.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -14,6 +15,24 @@ public interface SolidReference : Vision {
public val prototype: Solid 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 * A reference [Solid] to reuse a template object
*/ */
@ -60,19 +79,10 @@ public class SolidReferenceGroup(
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean?,
includeStyles: Boolean, includeStyles: Boolean?,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = sequence { ): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults)
yield(getOwnProperty(name))
if (includeStyles) {
yieldAll(getStyleItems(name))
}
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
if (inherit) {
yield(parent?.getProperty(name, inherit))
}
}.merge()
override fun attachChildren() { override fun attachChildren() {
//do nothing //do nothing
@ -104,19 +114,10 @@ public class SolidReferenceGroup(
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean?,
includeStyles: Boolean, includeStyles: Boolean?,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = sequence { ): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults)
yield(getOwnProperty(name))
if (includeStyles) {
yieldAll(getStyleItems(name))
}
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
if (inherit) {
yield(parent?.getProperty(name, inherit))
}
}.merge()
override var parent: VisionGroup? override var parent: VisionGroup?
get() { get() {

View File

@ -17,7 +17,7 @@ class PropertyTest {
box = box(100, 100, 100) box = box(100, 100, 100)
} }
} }
assertEquals(22, box?.getProperty("test").int) assertEquals(22, box?.getProperty("test", inherit = true).int)
} }
@Test @Test