New properties #34

Merged
altavir merged 19 commits from new-properties into dev 2020-12-29 13:35:01 +03:00
8 changed files with 97 additions and 100 deletions
Showing only changes of commit 6939fba292 - Show all commits

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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())

View File

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

View File

@ -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())
}

View File

@ -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() {

View File

@ -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