0.2.0 #71
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("ru.mipt.npm.gradle.project")
|
id("ru.mipt.npm.gradle.project")
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion by extra("0.5.0-dev-9")
|
val dataforgeVersion by extra("0.5.0-dev-10")
|
||||||
val fxVersion by extra("11")
|
val fxVersion by extra("11")
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
@ -16,7 +16,7 @@ kotlin {
|
|||||||
jvm {
|
jvm {
|
||||||
withJava()
|
withJava()
|
||||||
}
|
}
|
||||||
js{
|
js {
|
||||||
useCommonJs()
|
useCommonJs()
|
||||||
browser {
|
browser {
|
||||||
commonWebpackConfig {
|
commonWebpackConfig {
|
||||||
@ -34,6 +34,7 @@ kotlin {
|
|||||||
jvmMain {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":visionforge-fx"))
|
implementation(project(":visionforge-fx"))
|
||||||
|
implementation("ch.qos.logback:logback-classic:1.2.5")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
@ -53,5 +54,5 @@ application {
|
|||||||
val convertGdmlToJson by tasks.creating(JavaExec::class) {
|
val convertGdmlToJson by tasks.creating(JavaExec::class) {
|
||||||
group = "application"
|
group = "application"
|
||||||
classpath = sourceSets["main"].runtimeClasspath
|
classpath = sourceSets["main"].runtimeClasspath
|
||||||
main = "space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt"
|
mainClass.set("space.kscience.dataforge.vis.spatial.gdml.demo.SaveToJsonKt")
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.visionforge.gdml
|
package space.kscience.visionforge.gdml
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.string
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
|
import space.kscience.dataforge.values.string
|
||||||
import space.kscience.gdml.GdmlShowCase
|
import space.kscience.gdml.GdmlShowCase
|
||||||
import space.kscience.visionforge.setProperty
|
import space.kscience.visionforge.setProperty
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
@ -27,6 +27,6 @@ class GDMLVisionTest {
|
|||||||
val child = vision[Name.of("composite-000","segment-0")]
|
val child = vision[Name.of("composite-000","segment-0")]
|
||||||
assertNotNull(child)
|
assertNotNull(child)
|
||||||
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
child.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
|
||||||
assertEquals("red", child.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
assertEquals("red", child.getPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY)?.string)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ import space.kscience.dataforge.context.Context
|
|||||||
import space.kscience.dataforge.context.fetch
|
import space.kscience.dataforge.context.fetch
|
||||||
import space.kscience.gdml.GdmlShowCase
|
import space.kscience.gdml.GdmlShowCase
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
import space.kscience.visionforge.describedProperties
|
import space.kscience.visionforge.computeProperties
|
||||||
import space.kscience.visionforge.editor.VisionEditorFragment
|
import space.kscience.visionforge.editor.VisionEditorFragment
|
||||||
import space.kscience.visionforge.editor.VisionTreeFragment
|
import space.kscience.visionforge.editor.VisionTreeFragment
|
||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
@ -34,10 +34,10 @@ class GDMLView : View() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val propertyEditor = VisionEditorFragment {
|
private val propertyEditor = VisionEditorFragment {
|
||||||
it.describedProperties
|
it.computeProperties()
|
||||||
}.apply {
|
}.apply {
|
||||||
descriptorProperty.set(SolidMaterial.descriptor)
|
descriptorProperty.set(SolidMaterial.descriptor)
|
||||||
itemProperty.bind(treeFragment.selectedProperty)
|
visionProperty.bind(treeFragment.selectedProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package space.kscience.visionforge.solid.demo
|
package space.kscience.visionforge.solid.demo
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.isActive
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.invoke
|
import space.kscience.dataforge.meta.invoke
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
@ -76,7 +73,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
//override color for this cube
|
//override color for this cube
|
||||||
color(1530)
|
color(1530)
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(500)
|
delay(500)
|
||||||
visible = !(visible ?: false)
|
visible = !(visible ?: false)
|
||||||
@ -85,7 +82,7 @@ fun VisionLayout<Solid>.showcase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
val random = Random(111)
|
val random = Random(111)
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
|
@ -3,6 +3,7 @@ package space.kscience.visionforge.solid.demo
|
|||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.geometries.BoxGeometry
|
import info.laht.threekt.geometries.BoxGeometry
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.dataforge.meta.number
|
import space.kscience.dataforge.meta.number
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
@ -43,13 +44,13 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
|||||||
it.layers.enable(this@VariableBox.layer)
|
it.layers.enable(this@VariableBox.layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mesh.scale.z = getOwnProperty(VALUE).number?.toDouble() ?: 1.0
|
mesh.scale.z = meta[VALUE].number?.toDouble() ?: 1.0
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
onPropertyChange(three.context) { name ->
|
onPropertyChange { name ->
|
||||||
when {
|
when {
|
||||||
name == VALUE -> {
|
name == VALUE -> {
|
||||||
val value = getOwnProperty(VALUE).int ?: 0
|
val value = meta.get(VALUE).int ?: 0
|
||||||
val size = value.toFloat() / 255f * 20f
|
val size = value.toFloat() / 255f * 20f
|
||||||
mesh.scale.z = size.toDouble()
|
mesh.scale.z = size.toDouble()
|
||||||
mesh.position.z = size.toDouble() / 2
|
mesh.position.z = size.toDouble() / 2
|
||||||
@ -69,7 +70,7 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
|||||||
}
|
}
|
||||||
|
|
||||||
var value: Int
|
var value: Int
|
||||||
get() = getOwnProperty(VALUE).int ?: 0
|
get() = meta[VALUE].int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(VALUE, value.asValue())
|
setProperty(VALUE, value.asValue())
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,5 @@ dependencies {
|
|||||||
implementation(npm("file-saver", "2.0.2"))
|
implementation(npm("file-saver", "2.0.2"))
|
||||||
implementation(npm("bootstrap","4.6.0"))
|
implementation(npm("bootstrap","4.6.0"))
|
||||||
implementation(npm("jquery","3.5.1"))
|
implementation(npm("jquery","3.5.1"))
|
||||||
implementation(npm("@popperjs/core","2.9.3"))
|
implementation(npm("popper.js","1.16.1"))
|
||||||
}
|
}
|
@ -4,13 +4,10 @@ import org.w3c.dom.Element
|
|||||||
import react.RBuilder
|
import react.RBuilder
|
||||||
import react.dom.render
|
import react.dom.render
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.getStyle
|
|
||||||
import space.kscience.visionforge.meta
|
|
||||||
import space.kscience.visionforge.react.metaViewer
|
import space.kscience.visionforge.react.metaViewer
|
||||||
import space.kscience.visionforge.react.propertyEditor
|
import space.kscience.visionforge.react.propertyEditor
|
||||||
import space.kscience.visionforge.solid.SolidReference
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
import space.kscience.visionforge.styles
|
|
||||||
|
|
||||||
public fun RBuilder.visionPropertyEditor(
|
public fun RBuilder.visionPropertyEditor(
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
@ -20,8 +17,8 @@ public fun RBuilder.visionPropertyEditor(
|
|||||||
|
|
||||||
card("Properties") {
|
card("Properties") {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.meta(false,false,false),
|
ownProperties = vision.meta,
|
||||||
allProperties = vision.meta(),
|
allProperties = vision.computeProperties(),
|
||||||
updateFlow = vision.propertyChanges,
|
updateFlow = vision.propertyChanges,
|
||||||
descriptor = descriptor,
|
descriptor = descriptor,
|
||||||
key = key
|
key = key
|
||||||
|
@ -14,7 +14,8 @@ import space.kscience.dataforge.names.NameToken
|
|||||||
import space.kscience.dataforge.names.isEmpty
|
import space.kscience.dataforge.names.isEmpty
|
||||||
import space.kscience.dataforge.names.length
|
import space.kscience.dataforge.names.length
|
||||||
import space.kscience.visionforge.VisionGroup
|
import space.kscience.visionforge.VisionGroup
|
||||||
import space.kscience.visionforge.meta
|
import space.kscience.visionforge.computeProperties
|
||||||
|
import space.kscience.visionforge.propertyChanges
|
||||||
import space.kscience.visionforge.react.ThreeCanvasComponent
|
import space.kscience.visionforge.react.ThreeCanvasComponent
|
||||||
import space.kscience.visionforge.react.flexColumn
|
import space.kscience.visionforge.react.flexColumn
|
||||||
import space.kscience.visionforge.react.flexRow
|
import space.kscience.visionforge.react.flexRow
|
||||||
@ -134,8 +135,8 @@ public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsPro
|
|||||||
}
|
}
|
||||||
IslandContent {
|
IslandContent {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.meta(false, false, false),
|
ownProperties = vision.meta,
|
||||||
allProperties = vision.meta(),
|
allProperties = vision.computeProperties(),
|
||||||
updateFlow = vision.propertyChanges,
|
updateFlow = vision.propertyChanges,
|
||||||
descriptor = vision.descriptor,
|
descriptor = vision.descriptor,
|
||||||
key = selected
|
key = selected
|
||||||
|
@ -8,14 +8,11 @@ import ringui.Island
|
|||||||
import ringui.SmartTabs
|
import ringui.SmartTabs
|
||||||
import ringui.Tab
|
import ringui.Tab
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.getStyle
|
|
||||||
import space.kscience.visionforge.meta
|
|
||||||
import space.kscience.visionforge.react.flexColumn
|
import space.kscience.visionforge.react.flexColumn
|
||||||
import space.kscience.visionforge.react.metaViewer
|
import space.kscience.visionforge.react.metaViewer
|
||||||
import space.kscience.visionforge.react.propertyEditor
|
import space.kscience.visionforge.react.propertyEditor
|
||||||
import space.kscience.visionforge.solid.SolidReference
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
import space.kscience.visionforge.styles
|
|
||||||
|
|
||||||
public fun RBuilder.ringPropertyEditor(
|
public fun RBuilder.ringPropertyEditor(
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
@ -31,8 +28,8 @@ public fun RBuilder.ringPropertyEditor(
|
|||||||
flexColumn {
|
flexColumn {
|
||||||
Island("Properties") {
|
Island("Properties") {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.meta(false,false,false),
|
ownProperties = vision.meta,
|
||||||
allProperties = vision.meta(),
|
allProperties = vision.computeProperties(),
|
||||||
updateFlow = vision.propertyChanges,
|
updateFlow = vision.propertyChanges,
|
||||||
descriptor = descriptor,
|
descriptor = descriptor,
|
||||||
key = key
|
key = key
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package space.kscience.visionforge
|
||||||
|
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.plus
|
||||||
|
import space.kscience.dataforge.values.Value
|
||||||
|
|
||||||
|
private class ComputedVisionProperties(
|
||||||
|
public val vision: Vision,
|
||||||
|
public val rootName: Name,
|
||||||
|
public val visionDescriptor: MetaDescriptor
|
||||||
|
) : ObservableMutableMeta by vision.meta {
|
||||||
|
|
||||||
|
public val descriptor: MetaDescriptor? = visionDescriptor[rootName]
|
||||||
|
|
||||||
|
override val items: Map<NameToken, ObservableMutableMeta>
|
||||||
|
get() {
|
||||||
|
val metaKeys = vision.meta.items.keys
|
||||||
|
val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet()
|
||||||
|
return (metaKeys + descriptorKeys).associateWith { getMeta(rootName + it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override var value: Value?
|
||||||
|
get() {
|
||||||
|
val inheritFlag = descriptor?.inherited ?: false
|
||||||
|
val stylesFlag = descriptor?.usesStyles ?: true
|
||||||
|
return vision.getPropertyValue(rootName, inheritFlag, stylesFlag, true)
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
vision.meta.setValue(rootName, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMeta(name: Name): ObservableMutableMeta =
|
||||||
|
ComputedVisionProperties(vision, rootName + name, visionDescriptor)
|
||||||
|
|
||||||
|
override fun getOrCreate(name: Name): ObservableMutableMeta = getMeta(name)
|
||||||
|
|
||||||
|
override fun toMeta(): Meta = this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute property node based on inheritance and style information from the descriptor
|
||||||
|
*/
|
||||||
|
public fun Vision.computeProperties(descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta =
|
||||||
|
if (descriptor == null) meta else ComputedVisionProperties(this, Name.EMPTY, descriptor)
|
||||||
|
|
||||||
|
public fun Vision.computePropertyNode(name: Name, descriptor: MetaDescriptor? = this.descriptor): ObservableMutableMeta? =
|
||||||
|
computeProperties(descriptor)[name]
|
@ -5,6 +5,7 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ import kotlin.jvm.JvmInline
|
|||||||
@JvmInline
|
@JvmInline
|
||||||
public value class StyleSheet(private val owner: VisionGroup) {
|
public value class StyleSheet(private val owner: VisionGroup) {
|
||||||
|
|
||||||
private val styleNode: Meta? get() = owner.getOwnProperty(STYLESHEET_KEY)
|
private val styleNode: Meta? get() = owner.meta[STYLESHEET_KEY]
|
||||||
|
|
||||||
public val items: Map<NameToken, Meta>? get() = styleNode?.items
|
public val items: Map<NameToken, Meta>? get() = styleNode?.items
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ public value class StyleSheet(private val owner: VisionGroup) {
|
|||||||
* Define a style without notifying owner
|
* Define a style without notifying owner
|
||||||
*/
|
*/
|
||||||
public fun define(key: String, style: Meta?) {
|
public fun define(key: String, style: Meta?) {
|
||||||
owner.setPropertyNode(STYLESHEET_KEY + key, style)
|
owner.meta.setMeta(STYLESHEET_KEY + key, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,9 +72,9 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
|||||||
* List of names of styles applied to this object. Order matters. Not inherited.
|
* List of names of styles applied to this object. Order matters. Not inherited.
|
||||||
*/
|
*/
|
||||||
public var Vision.styles: List<String>
|
public var Vision.styles: List<String>
|
||||||
get() = getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()
|
get() = meta.getMeta(Vision.STYLE_KEY)?.stringList ?: emptyList()
|
||||||
set(value) {
|
set(value) {
|
||||||
setPropertyValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
meta.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +87,7 @@ public val VisionGroup.styleSheet: StyleSheet get() = StyleSheet(this)
|
|||||||
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
||||||
*/
|
*/
|
||||||
public fun Vision.useStyle(name: String) {
|
public fun Vision.useStyle(name: String) {
|
||||||
styles = (getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
|
styles = (meta.getMeta(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -94,7 +95,12 @@ public fun Vision.useStyle(name: String) {
|
|||||||
* Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision].
|
* Find a style with given name for given [Vision]. The style is not necessary applied to this [Vision].
|
||||||
*/
|
*/
|
||||||
public tailrec fun Vision.getStyle(name: String): Meta? =
|
public tailrec fun Vision.getStyle(name: String): Meta? =
|
||||||
getOwnProperty(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
|
meta.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a property from all styles
|
||||||
|
*/
|
||||||
|
public fun Vision.getStyleProperty(name: Name): Value? = styles.firstNotNullOfOrNull { getStyle(it)?.get(name)?.value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve an item in all style layers
|
* Resolve an item in all style layers
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
|
||||||
import space.kscience.dataforge.meta.descriptors.Described
|
import space.kscience.dataforge.meta.descriptors.Described
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.update
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
|
import space.kscience.dataforge.values.asValue
|
||||||
|
import space.kscience.dataforge.values.boolean
|
||||||
import space.kscience.visionforge.Vision.Companion.TYPE
|
import space.kscience.visionforge.Vision.Companion.TYPE
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A root type for display hierarchy
|
* A root type for display hierarchy
|
||||||
*/
|
*/
|
||||||
@Type(TYPE)
|
@Type(TYPE)
|
||||||
public interface Vision : Described, CoroutineScope {
|
public interface Vision : Described, Configurable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parent object of this one. If null, this one is a root.
|
* The parent object of this one. If null, this one is a root.
|
||||||
@ -33,47 +33,23 @@ public interface Vision : Described, CoroutineScope {
|
|||||||
*/
|
*/
|
||||||
public val manager: VisionManager? get() = parent?.manager
|
public val manager: VisionManager? get() = parent?.manager
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext
|
/**
|
||||||
get() = manager?.context?.coroutineContext ?: EmptyCoroutineContext
|
* This Vision own properties (ignoring inheritance, styles and defaults
|
||||||
|
*/
|
||||||
|
override val meta: ObservableMutableMeta
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get property.
|
* Get property value with given layer flags.
|
||||||
* @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false.
|
* @param inherit toggles parent node property lookup. Null means inference from descriptor. Default is false.
|
||||||
* @param includeStyles toggles inclusion of. Null means inference from descriptor. Default is true.
|
* @param includeStyles toggles inclusion of properties from styles. default is true
|
||||||
*/
|
*/
|
||||||
public fun getProperty(
|
public fun getPropertyValue(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean = false,
|
inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): Meta?
|
): Value?
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an intrinsic property of this Vision excluding any inheritance or defaults. In most cases should be the same as
|
|
||||||
* `getProperty(name, false, false, false`.
|
|
||||||
*/
|
|
||||||
public fun getOwnProperty(name: Name): Meta? = getProperty(
|
|
||||||
name,
|
|
||||||
inherit = false,
|
|
||||||
includeStyles = false,
|
|
||||||
includeDefaults = false
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the property node. If [node] is null remove node and its descendants
|
|
||||||
*/
|
|
||||||
public fun setPropertyNode(name: Name, node: Meta?, notify: Boolean = true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a value of specific property node
|
|
||||||
*/
|
|
||||||
public fun setPropertyValue(name: Name, value: Value?, notify: Boolean = true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public val propertyChanges: Flow<Name>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify all listeners that a property has been changed and should be invalidated
|
* Notify all listeners that a property has been changed and should be invalidated
|
||||||
@ -83,7 +59,7 @@ public interface Vision : Described, CoroutineScope {
|
|||||||
/**
|
/**
|
||||||
* Update this vision using a dif represented by [VisionChange].
|
* Update this vision using a dif represented by [VisionChange].
|
||||||
*/
|
*/
|
||||||
public fun change(change: VisionChange)
|
public fun update(change: VisionChange)
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor?
|
override val descriptor: MetaDescriptor?
|
||||||
|
|
||||||
@ -96,58 +72,60 @@ public interface Vision : Described, CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
|
* 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.
|
||||||
*/
|
*/
|
||||||
public fun Vision.onPropertyChange(scope: CoroutineScope, callback: suspend (Name) -> Unit) {
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
propertyChanges.onEach(callback).launchIn(scope)
|
@DFExperimental
|
||||||
}
|
public val Vision.propertyChanges: Flow<Name>
|
||||||
|
get() = callbackFlow {
|
||||||
|
meta.onChange(this) { name ->
|
||||||
|
launch {
|
||||||
|
send(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitClose {
|
||||||
|
meta.removeListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Own properties, excluding inheritance, styles and descriptor
|
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
|
||||||
*/
|
*/
|
||||||
public fun Vision.meta(
|
public fun Vision.onPropertyChange(callback: Meta.(Name) -> Unit) {
|
||||||
inherit: Boolean = false,
|
meta.onChange(null, callback)
|
||||||
includeStyles: Boolean = true,
|
|
||||||
includeDefaults: Boolean = true,
|
|
||||||
): MutableMeta = VisionProperties(this, Name.EMPTY, inherit, includeStyles, includeDefaults)
|
|
||||||
|
|
||||||
public fun Vision.configure(target: Name = Name.EMPTY, block: MutableMeta.() -> Unit): Unit {
|
|
||||||
VisionProperties(this, target).apply(block)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Vision.configure(meta: Meta) {
|
|
||||||
configure(Name.EMPTY) {
|
|
||||||
update(meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun Vision.configure(block: MutableMeta.() -> Unit): Unit = configure(Meta(block))
|
|
||||||
|
|
||||||
public fun Vision.getOwnProperty(key: String): Meta? = getOwnProperty(Name.parse(key))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get [Vision] property using key as a String
|
* Get [Vision] property using key as a String
|
||||||
*/
|
*/
|
||||||
public fun Vision.getProperty(
|
public fun Vision.getPropertyValue(
|
||||||
key: String,
|
key: String,
|
||||||
inherit: Boolean = false,
|
inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): Meta? = getProperty(Name.parse(key), inherit, includeStyles, includeDefaults)
|
): Value? = getPropertyValue(Name.parse(key), inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to set property node or value. If Item is null, then node is removed, not a value
|
* A convenience method to set property node or value. If Item is null, then node is removed, not a value
|
||||||
*/
|
*/
|
||||||
public fun Vision.setProperty(name: Name, item: Any?) {
|
public fun Vision.setProperty(name: Name, item: Any?) {
|
||||||
when (item) {
|
when (item) {
|
||||||
null -> setPropertyNode(name, null)
|
null -> meta.remove(name)
|
||||||
is Meta -> setPropertyNode(name, item)
|
is Meta -> meta.setMeta(name, item)
|
||||||
is Value -> setPropertyValue(name, item)
|
is Value -> meta.setValue(name, item)
|
||||||
|
else -> meta.setValue(name, Value.of(item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Vision.setPropertyNode(key: String, item: Any?) {
|
public fun Vision.setPropertyNode(key: String, item: Any?) {
|
||||||
setProperty(Name.parse(key), item)
|
setProperty(Name.parse(key), item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control visibility of the element
|
||||||
|
*/
|
||||||
|
public var Vision.visible: Boolean?
|
||||||
|
get() = getPropertyValue(Vision.VISIBLE_KEY)?.boolean
|
||||||
|
set(value) = meta.setValue(Vision.VISIBLE_KEY, value?.asValue())
|
||||||
|
|
||||||
|
@ -1,24 +1,27 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.defaultNode
|
import space.kscience.dataforge.meta.descriptors.defaultNode
|
||||||
import space.kscience.dataforge.meta.descriptors.value
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.names.asName
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
||||||
import kotlin.jvm.Synchronized
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
|
internal data class MetaListener(
|
||||||
|
val owner: Any? = null,
|
||||||
|
val callback: Meta.(name: Name) -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A full base implementation for a [Vision]
|
* A full base implementation for a [Vision]
|
||||||
* @param properties Object own properties excluding styles and inheritance
|
* @param properties Object own properties excluding styles and inheritance
|
||||||
@ -27,12 +30,9 @@ import kotlin.jvm.Synchronized
|
|||||||
@SerialName("vision")
|
@SerialName("vision")
|
||||||
public open class VisionBase(
|
public open class VisionBase(
|
||||||
@Transient override var parent: VisionGroup? = null,
|
@Transient override var parent: VisionGroup? = null,
|
||||||
@Serializable(MutableMetaSerializer::class)
|
|
||||||
protected var properties: MutableMeta? = null
|
protected var properties: MutableMeta? = null
|
||||||
) : Vision {
|
) : Vision {
|
||||||
|
|
||||||
//protected val observableProperties: ObservableMutableMeta by lazy { properties.asObservable() }
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
protected fun getOrCreateProperties(): MutableMeta {
|
protected fun getOrCreateProperties(): MutableMeta {
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
@ -42,82 +42,105 @@ public open class VisionBase(
|
|||||||
return properties!!
|
return properties!!
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Transient
|
||||||
* A fast accessor method to get own property (no inheritance or styles
|
private val listeners = HashSet<MetaListener>()
|
||||||
*/
|
|
||||||
override fun getOwnProperty(name: Name): Meta? = properties?.getMeta(name)
|
|
||||||
|
|
||||||
override fun getProperty(
|
private inner class VisionBaseProperties(val rootName: Name) : ObservableMutableMeta {
|
||||||
|
|
||||||
|
override val items: Map<NameToken, ObservableMutableMeta>
|
||||||
|
get() = properties?.get(rootName)?.items?.mapValues { entry ->
|
||||||
|
VisionBaseProperties(rootName + entry.key)
|
||||||
|
} ?: emptyMap()
|
||||||
|
|
||||||
|
override var value: Value?
|
||||||
|
get() = properties?.get(rootName)?.value
|
||||||
|
set(value) {
|
||||||
|
getOrCreateProperties().setValue(rootName, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOrCreate(name: Name): ObservableMutableMeta = VisionBaseProperties(this.rootName + name)
|
||||||
|
|
||||||
|
override fun setMeta(name: Name, node: Meta?) {
|
||||||
|
getOrCreateProperties().setMeta(name, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
@DFExperimental
|
||||||
|
override fun attach(name: Name, node: ObservableMutableMeta) {
|
||||||
|
val ownProperties = getOrCreateProperties()
|
||||||
|
if (ownProperties is ObservableMutableMeta) {
|
||||||
|
ownProperties.attach(rootName + name, node)
|
||||||
|
} else {
|
||||||
|
ownProperties.setMeta(rootName + name, node)
|
||||||
|
node.onChange(this) { childName ->
|
||||||
|
ownProperties.setMeta(rootName + name + childName, this[childName])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate(name: Name) {
|
||||||
|
invalidateProperty(rootName + name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
|
||||||
|
if (rootName.isEmpty()) {
|
||||||
|
listeners.add((MetaListener(owner, callback)))
|
||||||
|
} else {
|
||||||
|
listeners.add(MetaListener(owner) { name ->
|
||||||
|
if (name.startsWith(rootName)) {
|
||||||
|
(get(rootName) ?: Meta.EMPTY).callback(name.removeHeadOrNull(rootName)!!)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun removeListener(owner: Any?) {
|
||||||
|
listeners.removeAll { it.owner === owner }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = Meta.toString(this)
|
||||||
|
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
||||||
|
override fun hashCode(): Int = Meta.hashCode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val meta: ObservableMutableMeta get() = VisionBaseProperties(Name.EMPTY)
|
||||||
|
|
||||||
|
override fun getPropertyValue(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): Meta? = if (!inherit && !includeStyles && !includeDefaults) {
|
): Value? {
|
||||||
getOwnProperty(name)
|
properties?.get(name)?.value?.let { return it }
|
||||||
} else {
|
if (includeStyles) {
|
||||||
buildList {
|
getStyleProperty(name)?.let { return it }
|
||||||
add(getOwnProperty(name))
|
|
||||||
if (includeStyles) {
|
|
||||||
addAll(getStyleItems(name))
|
|
||||||
}
|
|
||||||
if (inherit) {
|
|
||||||
add(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
|
||||||
}
|
|
||||||
if (includeDefaults) {
|
|
||||||
add(descriptor?.defaultNode?.get(name))
|
|
||||||
}
|
|
||||||
}.merge()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPropertyNode(name: Name, node: Meta?, notify: Boolean) {
|
|
||||||
val oldItem = properties?.get(name)
|
|
||||||
if (oldItem != node) {
|
|
||||||
getOrCreateProperties().setMeta(name, node)
|
|
||||||
if (notify) {
|
|
||||||
invalidateProperty(name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if (inherit) {
|
||||||
|
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||||
override fun setPropertyValue(name: Name, value: Value?, notify: Boolean) {
|
|
||||||
val oldItem = properties?.get(name)?.value
|
|
||||||
if (oldItem != value) {
|
|
||||||
getOrCreateProperties()[name] = value
|
|
||||||
if (notify) {
|
|
||||||
invalidateProperty(name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (includeDefaults) {
|
||||||
|
descriptor?.defaultNode?.get(name)?.value.let { return it }
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor? get() = null
|
override val descriptor: MetaDescriptor? get() = null
|
||||||
|
|
||||||
private suspend fun updateStyles(names: List<String>) {
|
|
||||||
names.mapNotNull { getStyle(it) }.asSequence()
|
|
||||||
.flatMap { it.items.asSequence() }
|
|
||||||
.distinctBy { it.key }
|
|
||||||
.forEach {
|
|
||||||
invalidateProperty(it.key.asName())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO check memory consumption for the flow
|
|
||||||
@Transient
|
|
||||||
private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()
|
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
override val propertyChanges: Flow<Name>
|
|
||||||
get() = propertyInvalidationFlow
|
|
||||||
|
|
||||||
override fun invalidateProperty(propertyName: Name) {
|
override fun invalidateProperty(propertyName: Name) {
|
||||||
launch {
|
if (propertyName == STYLE_KEY) {
|
||||||
if (propertyName == STYLE_KEY) {
|
styles.mapNotNull { getStyle(it) }.asSequence()
|
||||||
updateStyles(styles)
|
.flatMap { it.items.asSequence() }
|
||||||
}
|
.distinctBy { it.key }
|
||||||
propertyInvalidationFlow.emit(propertyName)
|
.forEach {
|
||||||
|
invalidateProperty(it.key.asName())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
listeners.forEach { it.callback(properties ?: Meta.EMPTY, propertyName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun change(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
change.properties?.let {
|
change.properties?.let {
|
||||||
updateProperties(Name.EMPTY, it)
|
updateProperties(Name.EMPTY, it)
|
||||||
}
|
}
|
||||||
@ -131,7 +154,7 @@ public open class VisionBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun Vision.updateProperties(at: Name, item: Meta) {
|
public fun Vision.updateProperties(at: Name, item: Meta) {
|
||||||
setPropertyValue(at, item.value)
|
meta.setValue(at, item.value)
|
||||||
item.items.forEach { (token, item) ->
|
item.items.forEach { (token, item) ->
|
||||||
updateProperties(at + token, item)
|
updateProperties(at + token, item)
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,8 @@ private fun CoroutineScope.collectChange(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
//Collect properties change
|
//Collect properties change
|
||||||
source.onPropertyChange(this) { propertyName ->
|
source.onPropertyChange { propertyName ->
|
||||||
val newItem = source.getOwnProperty(propertyName)
|
val newItem = source.meta[propertyName]
|
||||||
collector().propertyChanged(name, propertyName, newItem)
|
collector().propertyChanged(name, propertyName, newItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -8,7 +9,6 @@ import kotlinx.serialization.Serializable
|
|||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation of mutable group of [Vision]
|
* Abstract implementation of mutable group of [Vision]
|
||||||
*
|
*
|
||||||
@ -48,7 +48,7 @@ public open class VisionGroupBase(
|
|||||||
* Propagate children change event upwards
|
* Propagate children change event upwards
|
||||||
*/
|
*/
|
||||||
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
|
private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) {
|
||||||
launch {
|
(manager?.context?: GlobalScope).launch {
|
||||||
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
|
_structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,15 +131,15 @@ public open class VisionGroupBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun change(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
change.children?.forEach { (name, change) ->
|
change.children?.forEach { (name, change) ->
|
||||||
when {
|
when {
|
||||||
change.delete -> set(name, null)
|
change.delete -> set(name, null)
|
||||||
change.vision != null -> set(name, change.vision)
|
change.vision != null -> set(name, change.vision)
|
||||||
else -> get(name)?.change(change)
|
else -> get(name)?.update(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.change(change)
|
super.update(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +151,6 @@ internal class RootVisionGroup(override val manager: VisionManager) : VisionGrou
|
|||||||
/**
|
/**
|
||||||
* Designate this [VisionGroup] as a root group and assign a [VisionManager] as its parent
|
* Designate this [VisionGroup] as a root group and assign a [VisionManager] as its parent
|
||||||
*/
|
*/
|
||||||
public fun Vision.root(manager: VisionManager){
|
public fun Vision.root(manager: VisionManager) {
|
||||||
parent = RootVisionGroup(manager)
|
parent = RootVisionGroup(manager)
|
||||||
}
|
}
|
@ -1,38 +0,0 @@
|
|||||||
package space.kscience.visionforge
|
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.dataforge.names.NameToken
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.values.Value
|
|
||||||
|
|
||||||
internal class VisionProperties(
|
|
||||||
val vision: Vision,
|
|
||||||
val rootName: Name,
|
|
||||||
val inherit: Boolean = false,
|
|
||||||
val includeStyles: Boolean = true,
|
|
||||||
val includeDefaults: Boolean = true,
|
|
||||||
) : MutableMeta {
|
|
||||||
|
|
||||||
override val items: Map<NameToken, MutableMeta>
|
|
||||||
get() = vision.getProperty(rootName, inherit, includeStyles, includeDefaults)?.items?.mapValues {
|
|
||||||
VisionProperties(vision, rootName + it.key, inherit, includeStyles, includeDefaults)
|
|
||||||
} ?: emptyMap()
|
|
||||||
|
|
||||||
override var value: Value?
|
|
||||||
get() = vision.getProperty(rootName, inherit, includeStyles, includeDefaults)?.value
|
|
||||||
set(value) {
|
|
||||||
vision.setPropertyValue(rootName, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOrCreate(name: Name): MutableMeta = VisionProperties(vision, rootName + name)
|
|
||||||
|
|
||||||
override fun setMeta(name: Name, node: Meta?) {
|
|
||||||
vision.setPropertyNode(rootName + name, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
|
|
||||||
override fun hashCode(): Int = Meta.hashCode(this)
|
|
||||||
override fun toString(): String = Meta.toString(this)
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Configurable
|
import space.kscience.dataforge.meta.Configurable
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
@ -11,39 +11,24 @@ import space.kscience.dataforge.values.Value
|
|||||||
* Property containers are used to create a symmetric behaviors for vision properties and style builders
|
* Property containers are used to create a symmetric behaviors for vision properties and style builders
|
||||||
*/
|
*/
|
||||||
public interface VisionPropertyContainer<out V : Vision> {
|
public interface VisionPropertyContainer<out V : Vision> {
|
||||||
public fun getProperty(
|
|
||||||
|
public val meta: MutableMeta
|
||||||
|
|
||||||
|
public fun getPropertyValue(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean = false,
|
inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): Meta?
|
): Value?
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the property node. If [node] is null remove node and its descendants
|
|
||||||
*/
|
|
||||||
public fun setPropertyNode(name: Name, node: Meta?, notify: Boolean = true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a value of specific property node
|
|
||||||
*/
|
|
||||||
public fun setPropertyValue(name: Name, value: Value?, notify: Boolean = true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public open class SimpleVisionPropertyContainer<out V : Vision>(
|
public open class SimpleVisionPropertyContainer<out V : Vision>(
|
||||||
override val meta: ObservableMutableMeta,
|
override val meta: ObservableMutableMeta,
|
||||||
) : VisionPropertyContainer<V>, Configurable {
|
) : VisionPropertyContainer<V>, Configurable {
|
||||||
override fun getProperty(
|
override fun getPropertyValue(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean
|
includeDefaults: Boolean
|
||||||
): Meta? = meta[name]
|
): Value? = meta[name]?.value
|
||||||
|
|
||||||
override fun setPropertyNode(name: Name, node: Meta?, notify: Boolean) {
|
|
||||||
this.meta.setMeta(name, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPropertyValue(name: Name, value: Value?, notify: Boolean) {
|
|
||||||
this.meta.setValue(name, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -2,9 +2,7 @@ package space.kscience.visionforge
|
|||||||
|
|
||||||
import space.kscience.dataforge.meta.Laminate
|
import space.kscience.dataforge.meta.Laminate
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.boolean
|
|
||||||
import space.kscience.dataforge.meta.isLeaf
|
import space.kscience.dataforge.meta.isLeaf
|
||||||
import space.kscience.dataforge.values.asValue
|
|
||||||
|
|
||||||
@DslMarker
|
@DslMarker
|
||||||
public annotation class VisionBuilder
|
public annotation class VisionBuilder
|
||||||
@ -17,10 +15,3 @@ public fun List<Meta?>.merge(): Meta? {
|
|||||||
else -> Laminate(filterNotNull()) //merge nodes if first encountered node is meta
|
else -> Laminate(filterNotNull()) //merge nodes if first encountered node is meta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Control visibility of the element
|
|
||||||
*/
|
|
||||||
public var Vision.visible: Boolean?
|
|
||||||
get() = getProperty(Vision.VISIBLE_KEY).boolean
|
|
||||||
set(value) = setPropertyValue(Vision.VISIBLE_KEY, value?.asValue())
|
|
@ -1,66 +0,0 @@
|
|||||||
package space.kscience.visionforge
|
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Scheme
|
|
||||||
import space.kscience.dataforge.meta.SchemeSpec
|
|
||||||
import space.kscience.dataforge.meta.descriptors.Described
|
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder
|
|
||||||
import space.kscience.dataforge.meta.descriptors.item
|
|
||||||
import space.kscience.dataforge.meta.descriptors.value
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.dataforge.values.ValueType
|
|
||||||
import kotlin.reflect.KProperty1
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO to be moved into the core
|
|
||||||
*/
|
|
||||||
public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
|
|
||||||
property: KProperty1<S, T>,
|
|
||||||
noinline block: MetaDescriptorBuilder.() -> Unit = {},
|
|
||||||
) {
|
|
||||||
when (typeOf<T>()) {
|
|
||||||
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
|
|
||||||
value(property.name, ValueType.NUMBER) {
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
typeOf<Number?>(), typeOf<Int?>(), typeOf<Double?>(), typeOf<Short?>(), typeOf<Long?>(), typeOf<Float?>() ->
|
|
||||||
value(property.name, ValueType.NUMBER) {
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
typeOf<Boolean>() -> value(property.name, ValueType.BOOLEAN) {
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
typeOf<List<Number>>(), typeOf<List<Int>>(), typeOf<List<Double>>(), typeOf<List<Short>>(), typeOf<List<Long>>(), typeOf<List<Float>>(),
|
|
||||||
typeOf<IntArray>(), typeOf<DoubleArray>(), typeOf<ShortArray>(), typeOf<LongArray>(), typeOf<FloatArray>(),
|
|
||||||
-> value(property.name, ValueType.NUMBER) {
|
|
||||||
multiple = true
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
typeOf<String>() -> value(property.name, ValueType.STRING) {
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
typeOf<List<String>>(), typeOf<Array<String>>() -> value(property.name, ValueType.STRING) {
|
|
||||||
multiple = true
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
else -> item(property.name, block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun MetaDescriptorBuilder.item(
|
|
||||||
key: String,
|
|
||||||
described: Described,
|
|
||||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
|
||||||
) {
|
|
||||||
described.descriptor?.let {
|
|
||||||
item(Name.parse(key), it, block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(
|
|
||||||
property: KProperty1<S, T>,
|
|
||||||
spec: SchemeSpec<T>,
|
|
||||||
noinline block: MetaDescriptorBuilder.() -> Unit = {},
|
|
||||||
) {
|
|
||||||
item(property.name, spec, block)
|
|
||||||
}
|
|
@ -1,45 +1,43 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.dataforge.values.number
|
import space.kscience.dataforge.values.number
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
public fun Vision.propertyNode(
|
//public fun Vision.propertyNode(
|
||||||
name: Name? = null,
|
// name: Name? = null,
|
||||||
inherit: Boolean = false,
|
// inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
// includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
// includeDefaults: Boolean = true,
|
||||||
): ReadWriteProperty<Any?, Meta?> = object : ReadWriteProperty<Any?, Meta?> {
|
//): ReadWriteProperty<Any?, Meta?> = object : ReadWriteProperty<Any?, Meta?> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? =
|
// override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? =
|
||||||
getProperty(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)
|
// getProperty(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)
|
||||||
|
//
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) {
|
// override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) {
|
||||||
setPropertyNode(name ?: Name.parse(property.name), value)
|
// meta.setMeta(name ?: Name.parse(property.name), value)
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
public fun <T> Vision.propertyNode(
|
//public fun <T> Vision.propertyNode(
|
||||||
converter: MetaConverter<T>,
|
// converter: MetaConverter<T>,
|
||||||
name: Name? = null,
|
// name: Name? = null,
|
||||||
inherit: Boolean = false,
|
// inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
// includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
// includeDefaults: Boolean = true,
|
||||||
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
|
//): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T? = getProperty(
|
// override fun getValue(thisRef: Any?, property: KProperty<*>): T? = getProperty(
|
||||||
name ?: Name.parse(property.name),
|
// name ?: Name.parse(property.name),
|
||||||
inherit,
|
// inherit,
|
||||||
includeStyles,
|
// includeStyles,
|
||||||
includeDefaults
|
// includeDefaults
|
||||||
)?.let(converter::metaToObject)
|
// )?.let(converter::metaToObject)
|
||||||
|
//
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
// override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||||
setPropertyNode(name ?: Name.parse(property.name), value?.let(converter::objectToMeta))
|
// meta.setMeta(name ?: Name.parse(property.name), value?.let(converter::objectToMeta))
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
public fun Vision.propertyValue(
|
public fun Vision.propertyValue(
|
||||||
name: Name? = null,
|
name: Name? = null,
|
||||||
@ -48,10 +46,10 @@ public fun Vision.propertyValue(
|
|||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): ReadWriteProperty<Any?, Value?> = object : ReadWriteProperty<Any?, Value?> {
|
): ReadWriteProperty<Any?, Value?> = object : ReadWriteProperty<Any?, Value?> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
|
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
|
||||||
getProperty(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)?.value
|
getPropertyValue(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
|
||||||
setPropertyValue(name ?: Name.parse(property.name), value)
|
meta.setValue(name ?: Name.parse(property.name), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,15 +61,15 @@ public fun <T> Vision.propertyValue(
|
|||||||
setter: (T) -> Value? = { it?.let(Value::of) },
|
setter: (T) -> Value? = { it?.let(Value::of) },
|
||||||
getter: (Value?) -> T,
|
getter: (Value?) -> T,
|
||||||
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T = getProperty(
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T = getPropertyValue(
|
||||||
name ?: Name.parse(property.name),
|
name ?: Name.parse(property.name),
|
||||||
inherit,
|
inherit,
|
||||||
includeStyles,
|
includeStyles,
|
||||||
includeDefaults
|
includeDefaults
|
||||||
)?.value.let(getter)
|
).let(getter)
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
setPropertyValue(name ?: Name.parse(property.name), value?.let(setter))
|
meta.setValue(name ?: Name.parse(property.name), value?.let(setter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package space.kscience.visionforge
|
|||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.*
|
import space.kscience.dataforge.meta.descriptors.*
|
||||||
import space.kscience.dataforge.names.asName
|
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
|
|
||||||
private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited"
|
private const val INHERITED_DESCRIPTOR_ATTRIBUTE = "inherited"
|
||||||
@ -23,14 +22,6 @@ public var MetaDescriptorBuilder.usesStyles: Boolean
|
|||||||
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
|
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
|
||||||
set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value)
|
set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value)
|
||||||
|
|
||||||
|
|
||||||
public val Vision.describedProperties: Meta
|
|
||||||
get() = Meta {
|
|
||||||
descriptor?.children?.forEach { (key, descriptor) ->
|
|
||||||
this.setMeta(key.asName(), getProperty(key, inherit = descriptor.inherited))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public val MetaDescriptor.widget: Meta
|
public val MetaDescriptor.widget: Meta
|
||||||
get() = attributes["widget"] ?: Meta.EMPTY
|
get() = attributes["widget"] ?: Meta.EMPTY
|
||||||
|
|
||||||
|
@ -5,10 +5,17 @@ import kotlinx.html.stream.createHTML
|
|||||||
import space.kscience.dataforge.context.Global
|
import space.kscience.dataforge.context.Global
|
||||||
import space.kscience.dataforge.context.fetch
|
import space.kscience.dataforge.context.fetch
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.configure
|
||||||
import space.kscience.dataforge.meta.set
|
import space.kscience.dataforge.meta.set
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.VisionBase
|
||||||
|
import space.kscience.visionforge.VisionManager
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
import kotlin.collections.Map
|
||||||
|
import kotlin.collections.forEach
|
||||||
|
import kotlin.collections.set
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
typealias HtmlVisionRenderer = FlowContent.(name: Name, vision: Vision, meta: Meta) -> Unit
|
||||||
@ -57,7 +64,7 @@ class HtmlTagTest {
|
|||||||
div {
|
div {
|
||||||
h2 { +"Properties" }
|
h2 { +"Properties" }
|
||||||
ul {
|
ul {
|
||||||
(vision as? VisionBase)?.meta()?.items?.forEach {
|
(vision as? VisionBase)?.meta?.items?.forEach {
|
||||||
li {
|
li {
|
||||||
a { +it.key.toString() }
|
a { +it.key.toString() }
|
||||||
p { +it.value.toString() }
|
p { +it.value.toString() }
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package space.kscience.visionforge.meta
|
||||||
|
|
||||||
|
import space.kscience.dataforge.meta.*
|
||||||
|
import space.kscience.dataforge.values.asValue
|
||||||
|
import space.kscience.visionforge.VisionBase
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
|
||||||
|
class VisionPropertyTest {
|
||||||
|
@Test
|
||||||
|
fun testPropertyWrite(){
|
||||||
|
val vision = VisionBase()
|
||||||
|
vision.meta["fff"] = 2
|
||||||
|
vision.meta["fff.ddd"] = false
|
||||||
|
|
||||||
|
assertEquals(2, vision.meta["fff"]?.int)
|
||||||
|
assertEquals(false, vision.meta["fff.ddd"]?.boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPropertyEdit(){
|
||||||
|
val vision = VisionBase()
|
||||||
|
vision.meta.getOrCreate("fff.ddd").apply {
|
||||||
|
value = 2.asValue()
|
||||||
|
}
|
||||||
|
assertEquals(2, vision.meta["fff.ddd"]?.int)
|
||||||
|
assertNotEquals(true, vision.meta["fff.ddd"]?.boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TestScheme: Scheme(){
|
||||||
|
var ddd by int()
|
||||||
|
companion object: SchemeSpec<TestScheme>(::TestScheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPropertyUpdate(){
|
||||||
|
val vision = VisionBase()
|
||||||
|
vision.meta.getOrCreate("fff").updateWith(TestScheme){
|
||||||
|
ddd = 2
|
||||||
|
}
|
||||||
|
assertEquals(2, vision.meta["fff.ddd"]?.int)
|
||||||
|
}
|
||||||
|
}
|
@ -92,7 +92,7 @@ public class VisionClient : AbstractPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.debug { "Got update $change for output with name $name" }
|
logger.debug { "Got update $change for output with name $name" }
|
||||||
vision.change(change)
|
vision.update(change)
|
||||||
} else {
|
} else {
|
||||||
console.error("WebSocket message data is not a string")
|
console.error("WebSocket message data is not a string")
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,14 @@ package space.kscience.visionforge.editor
|
|||||||
import javafx.beans.binding.Binding
|
import javafx.beans.binding.Binding
|
||||||
import javafx.beans.binding.BooleanBinding
|
import javafx.beans.binding.BooleanBinding
|
||||||
import javafx.beans.binding.ListBinding
|
import javafx.beans.binding.ListBinding
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.binding.ObjectBinding
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.ObservableMeta
|
||||||
|
import space.kscience.dataforge.meta.boolean
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -22,11 +25,13 @@ public class FXMetaModel<M : Meta>(
|
|||||||
public val title: String = nodeName.lastOrNull()?.toString() ?: "Meta"
|
public val title: String = nodeName.lastOrNull()?.toString() ?: "Meta"
|
||||||
) : Comparable<FXMetaModel<*>> {
|
) : Comparable<FXMetaModel<*>> {
|
||||||
|
|
||||||
private val existingNode = SimpleObjectProperty<Meta>(root[nodeName])
|
private val existingNode = object: ObjectBinding<Meta?>() {
|
||||||
|
override fun computeValue(): Meta? =root[nodeName]
|
||||||
|
}
|
||||||
|
|
||||||
public val children: ListBinding<FXMetaModel<M>> = object : ListBinding<FXMetaModel<M>>() {
|
public val children: ListBinding<FXMetaModel<M>> = object : ListBinding<FXMetaModel<M>>() {
|
||||||
override fun computeValue(): ObservableList<FXMetaModel<M>> {
|
override fun computeValue(): ObservableList<FXMetaModel<M>> {
|
||||||
val nodeKeys = existingNode.get().items.keys
|
val nodeKeys = existingNode.get()?.items?.keys?: emptySet()
|
||||||
val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptySet()
|
val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptySet()
|
||||||
return (nodeKeys + descriptorKeys).map {
|
return (nodeKeys + descriptorKeys).map {
|
||||||
FXMetaModel(
|
FXMetaModel(
|
||||||
@ -43,7 +48,7 @@ public class FXMetaModel<M : Meta>(
|
|||||||
if (root is ObservableMeta) {
|
if (root is ObservableMeta) {
|
||||||
root.onChange(this) { changed ->
|
root.onChange(this) { changed ->
|
||||||
if (changed.startsWith(nodeName)) {
|
if (changed.startsWith(nodeName)) {
|
||||||
if (nodeName.length == changed.length) existingNode.set(root[nodeName])
|
if (nodeName.length == changed.length) existingNode.invalidate()
|
||||||
else if (changed.length == nodeName.length + 1) children.invalidate()
|
else if (changed.length == nodeName.length + 1) children.invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +62,7 @@ public class FXMetaModel<M : Meta>(
|
|||||||
public val exists: Boolean by existsProperty
|
public val exists: Boolean by existsProperty
|
||||||
|
|
||||||
public val valueProperty: Binding<Value?> = existingNode.objectBinding {
|
public val valueProperty: Binding<Value?> = existingNode.objectBinding {
|
||||||
existingNode.get().value ?: descriptor?.defaultValue
|
existingNode.get()?.value ?: descriptor?.defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compareTo(other: FXMetaModel<*>): Int = if (this.exists == other.exists) {
|
override fun compareTo(other: FXMetaModel<*>): Int = if (this.exists == other.exists) {
|
||||||
@ -77,141 +82,4 @@ public class FXMetaModel<M : Meta>(
|
|||||||
rootName: String = "root"
|
rootName: String = "root"
|
||||||
): FXMetaModel<M> = FXMetaModel(node, descriptor, Name.EMPTY, title = rootName)
|
): FXMetaModel<M> = FXMetaModel(node, descriptor, Name.EMPTY, title = rootName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * A descriptor that could be manually set to the node
|
|
||||||
// */
|
|
||||||
// private val innerDescriptorProperty = SimpleObjectProperty(descriptorValue)
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Actual descriptor which holds value inferred from parrent
|
|
||||||
// */
|
|
||||||
// val descriptorProperty: ObjectBinding<MetaDescriptor?> = objectBinding(innerDescriptorProperty) {
|
|
||||||
// value ?: parent?.descriptor?.get(this@FXMeta.name.body)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val descriptor: MetaDescriptor? by descriptorProperty
|
|
||||||
//
|
|
||||||
// private val innerNodeProperty = SimpleObjectProperty(nodeValue)
|
|
||||||
//
|
|
||||||
// val nodeProperty: ObjectBinding<M> = objectBinding(innerNodeProperty) {
|
|
||||||
// value ?: parent?.node?.get(this@FXMeta.name)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val node by nodeProperty
|
|
||||||
//
|
|
||||||
// val hasValue: ObservableBooleanValue = nodeProperty.booleanBinding { it != null }
|
|
||||||
//
|
|
||||||
// private val filter: (FXMeta<M>) -> Boolean = { cfg ->
|
|
||||||
// !(cfg.descriptor?.attributes?.get(MutableMetaEditor.NO_CONFIGURATOR_TAG)?.boolean ?: false)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val children: ListBinding<FXMeta<M>> = object : ListBinding<FXMeta<M>>() {
|
|
||||||
//
|
|
||||||
// init {
|
|
||||||
// bind(nodeProperty, descriptorProperty)
|
|
||||||
//
|
|
||||||
// val listener: Meta.(Name) -> Unit = { name ->
|
|
||||||
// if (name.length == 1) invalidate()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// (node as? ObservableMeta)?.onChange(this, listener)
|
|
||||||
//
|
|
||||||
// nodeProperty.addListener { _, oldValue, newValue ->
|
|
||||||
// if (newValue == null) {
|
|
||||||
// (oldValue as? ObservableMeta)?.removeListener(this)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (newValue is ObservableMeta) {
|
|
||||||
// newValue.onChange(this, listener)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun computeValue(): ObservableList<FXMeta<M>> {
|
|
||||||
// val nodeKeys = node?.items?.keys?.toSet() ?: emptySet()
|
|
||||||
// val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptyList()
|
|
||||||
// val keys: Set<NameToken> = nodeKeys + descriptorKeys
|
|
||||||
//
|
|
||||||
// val items = keys.map { token ->
|
|
||||||
// val actualItem = node?.items?.get(token)
|
|
||||||
// val actualDescriptor = descriptor?.children?.get(token.body)
|
|
||||||
//
|
|
||||||
// if (actualItem is MetaNode) {
|
|
||||||
// FXMetaNode(token, this@FXMetaNode)
|
|
||||||
// } else {
|
|
||||||
// FXMetaValue(token, this@FXMetaNode)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return items.filter(filter).asObservable()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// init {
|
|
||||||
// if (parent != null) {
|
|
||||||
// parent.descriptorProperty.onChange { descriptorProperty.invalidate() }
|
|
||||||
// parent.nodeProperty.onChange { nodeProperty.invalidate() }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//internal fun <M : MutableMeta> FXMeta<M>.remove(name: NameToken) {
|
|
||||||
// node?.remove(name.asName())
|
|
||||||
// children.invalidate()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//private fun <M : MutableMeta> M.createEmptyNode(token: NameToken, append: Boolean): M {
|
|
||||||
// return if (append && token.hasIndex()) {
|
|
||||||
// val name = token.asName()
|
|
||||||
// val index = (getIndexed(name).keys.mapNotNull { it?.toIntOrNull() }.maxOrNull() ?: -1) + 1
|
|
||||||
// val newName = name.withIndex(index.toString())
|
|
||||||
// set(newName, Meta.EMPTY)
|
|
||||||
// get(newName).node
|
|
||||||
// } else {
|
|
||||||
// this.set(token.asName(), Meta.EMPTY)
|
|
||||||
// //FIXME possible concurrency bug
|
|
||||||
// get(token).node
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//internal fun <M : MutableMeta> FXMeta<out M>.getOrCreateNode(): M {
|
|
||||||
// val node = node
|
|
||||||
// return when {
|
|
||||||
// node != null -> node
|
|
||||||
// parent != null -> parent.getOrCreateNode().createEmptyNode(this.name, descriptor?.multiple == true).also {
|
|
||||||
// parent.children.invalidate()
|
|
||||||
// }
|
|
||||||
// else -> kotlin.error("Orphan empty node is not allowed")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
|
||||||
internal fun <M : MutableMeta> FXMetaModel<M>.remove() {
|
|
||||||
root.remove(nodeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//internal fun <M : MutableMeta> FXMeta<M>.addValue(key: String) {
|
|
||||||
// val parent = getOrCreateNode()
|
|
||||||
// if (descriptor?.multiple == true) {
|
|
||||||
// parent.append(key, Null)
|
|
||||||
// } else {
|
|
||||||
// parent[key] = Null
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//internal fun <M : MutableMeta> FXMeta<M>.addNode(key: String) {
|
|
||||||
// val parent = getOrCreateNode()
|
|
||||||
// if (descriptor?.multiple == true) {
|
|
||||||
// parent.append(key, Meta.EMPTY)
|
|
||||||
// } else {
|
|
||||||
// parent[key] = Meta.EMPTY
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
internal fun <M : MutableMeta> FXMetaModel<M>.setValue(value: Value?) {
|
|
||||||
root.setValue(nodeName, value)
|
|
||||||
}
|
}
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package space.kscience.visionforge.editor
|
package space.kscience.visionforge.editor
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import javafx.scene.control.*
|
import javafx.scene.control.*
|
||||||
import javafx.scene.control.cell.TextFieldTreeTableCell
|
import javafx.scene.control.cell.TextFieldTreeTableCell
|
||||||
import javafx.scene.layout.BorderPane
|
import javafx.scene.layout.BorderPane
|
||||||
@ -13,6 +14,7 @@ import javafx.scene.text.Text
|
|||||||
import space.kscience.dataforge.context.Global
|
import space.kscience.dataforge.context.Global
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.remove
|
||||||
import space.kscience.visionforge.dfIconView
|
import space.kscience.visionforge.dfIconView
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
@ -32,8 +34,7 @@ public class MutableMetaEditor(
|
|||||||
MutableMeta: MutableMeta,
|
MutableMeta: MutableMeta,
|
||||||
descriptor: MetaDescriptor?,
|
descriptor: MetaDescriptor?,
|
||||||
title: String = "Configuration editor"
|
title: String = "Configuration editor"
|
||||||
) :
|
) : this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title)
|
||||||
this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title)
|
|
||||||
|
|
||||||
override val root: BorderPane = borderpane {
|
override val root: BorderPane = borderpane {
|
||||||
center = treetableview<FXMetaModel<MutableMeta>> {
|
center = treetableview<FXMetaModel<MutableMeta>> {
|
||||||
@ -64,7 +65,7 @@ public class MutableMetaEditor(
|
|||||||
contextmenu {
|
contextmenu {
|
||||||
item("Remove") {
|
item("Remove") {
|
||||||
action {
|
action {
|
||||||
content.remove()
|
content.root.remove(content.nodeName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ public class MutableMetaEditor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMetaModel<MutableMeta>, String> ->
|
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMetaModel<MutableMeta>, String> ->
|
||||||
(param.value.value.descriptor?.info ?: "").observable()
|
SimpleStringProperty(param.value.value.descriptor?.info ?: "")
|
||||||
}.setCellFactory { param: TreeTableColumn<FXMetaModel<MutableMeta>, String> ->
|
}.setCellFactory { param: TreeTableColumn<FXMetaModel<MutableMeta>, String> ->
|
||||||
val cell = TreeTableCell<FXMetaModel<MutableMeta>, String>()
|
val cell = TreeTableCell<FXMetaModel<MutableMeta>, String>()
|
||||||
val text = Text()
|
val text = Text()
|
||||||
@ -126,51 +127,10 @@ public class MutableMetaEditor(
|
|||||||
Global,
|
Global,
|
||||||
item.valueProperty,
|
item.valueProperty,
|
||||||
item.descriptor
|
item.descriptor
|
||||||
) {
|
) { value ->
|
||||||
item.setValue(it)
|
item.root.setValue(item.nodeName, value)
|
||||||
}
|
}
|
||||||
graphic = chooser.node
|
graphic = chooser.node
|
||||||
// when (item) {
|
|
||||||
// is FXMetaValue<MutableMeta> -> {
|
|
||||||
// text = null
|
|
||||||
// val chooser = ValueChooser.build(
|
|
||||||
// Global,
|
|
||||||
// item.valueProperty,
|
|
||||||
// item.descriptor
|
|
||||||
// ) {
|
|
||||||
// item.set(it)
|
|
||||||
// }
|
|
||||||
// graphic = chooser.node
|
|
||||||
// }
|
|
||||||
// is FXMetaNode<MutableMeta> -> {
|
|
||||||
// if (allowNew) {
|
|
||||||
// text = null
|
|
||||||
// graphic = HBox().apply {
|
|
||||||
// val glyph: Node = FontAwesomeIconView(FontAwesomeIcon.PLUS_CIRCLE)
|
|
||||||
// button("node", graphic = glyph) {
|
|
||||||
// hgrow = Priority.ALWAYS
|
|
||||||
// maxWidth = Double.POSITIVE_INFINITY
|
|
||||||
// action {
|
|
||||||
// showNodeDialog()?.let {
|
|
||||||
// item.addNode(it)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// button("value", graphic = FontAwesomeIconView(FontAwesomeIcon.PLUS_SQUARE)) {
|
|
||||||
// hgrow = Priority.ALWAYS
|
|
||||||
// maxWidth = Double.POSITIVE_INFINITY
|
|
||||||
// action {
|
|
||||||
// showValueDialog()?.let {
|
|
||||||
// item.addValue(it)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// text = ""
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
text = null
|
text = null
|
||||||
|
@ -5,41 +5,22 @@ import javafx.beans.property.SimpleObjectProperty
|
|||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
import javafx.scene.layout.VBox
|
import javafx.scene.layout.VBox
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.computeProperties
|
||||||
|
import space.kscience.visionforge.getStyle
|
||||||
|
import space.kscience.visionforge.styles
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
public class VisionEditorFragment(public val selector: (Vision) -> Meta) : Fragment() {
|
public class VisionEditorFragment(public val selector: (Vision) -> ObservableMutableMeta = {it.computeProperties()}) : Fragment() {
|
||||||
|
|
||||||
public val itemProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>()
|
public val visionProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>()
|
||||||
public var item: Vision? by itemProperty
|
public var vision: Vision? by visionProperty
|
||||||
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
|
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
|
||||||
|
|
||||||
public constructor(
|
private val configProperty: Binding<ObservableMutableMeta?> = visionProperty.objectBinding { vision ->
|
||||||
item: Vision?,
|
vision?.let(selector)
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
selector: (Vision) -> MutableMetaProvider = { it.meta() },
|
|
||||||
) : this({ it.describedProperties }) {
|
|
||||||
this.item = item
|
|
||||||
this.descriptorProperty.set(descriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var currentConfig: ObservableMutableMeta? = null
|
|
||||||
|
|
||||||
private val configProperty: Binding<ObservableMutableMeta?> = itemProperty.objectBinding { vision ->
|
|
||||||
if (vision == null) return@objectBinding null
|
|
||||||
val meta = selector(vision)
|
|
||||||
val config = MutableMeta {
|
|
||||||
update(meta)
|
|
||||||
}
|
|
||||||
config.onChange(this@VisionEditorFragment) { key ->
|
|
||||||
vision.setPropertyNode(key, config[key])
|
|
||||||
}
|
|
||||||
//remember old config reference to cleanup listeners
|
|
||||||
currentConfig?.removeListener(this)
|
|
||||||
currentConfig = config
|
|
||||||
config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
|
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
|
||||||
@ -50,8 +31,8 @@ public class VisionEditorFragment(public val selector: (Vision) -> Meta) : Fragm
|
|||||||
|
|
||||||
private val styleBoxProperty: Binding<Node?> = configProperty.objectBinding() {
|
private val styleBoxProperty: Binding<Node?> = configProperty.objectBinding() {
|
||||||
VBox().apply {
|
VBox().apply {
|
||||||
item?.styles?.forEach { styleName ->
|
vision?.styles?.forEach { styleName ->
|
||||||
val styleMeta = item?.getStyle(styleName)
|
val styleMeta = vision?.getStyle(styleName)
|
||||||
if (styleMeta != null) {
|
if (styleMeta != null) {
|
||||||
titledpane(styleName, node = MetaViewer(styleMeta).root)
|
titledpane(styleName, node = MetaViewer(styleMeta).root)
|
||||||
}
|
}
|
||||||
@ -64,7 +45,7 @@ public class VisionEditorFragment(public val selector: (Vision) -> Meta) : Fragm
|
|||||||
contentProperty().bind(configEditorProperty)
|
contentProperty().bind(configEditorProperty)
|
||||||
}
|
}
|
||||||
titledpane("Styles", collapsible = false) {
|
titledpane("Styles", collapsible = false) {
|
||||||
visibleWhen(itemProperty.booleanBinding { it?.styles?.isNotEmpty() ?: false })
|
visibleWhen(visionProperty.booleanBinding { it?.styles?.isNotEmpty() ?: false })
|
||||||
contentProperty().bind(styleBoxProperty)
|
contentProperty().bind(styleBoxProperty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import space.kscience.dataforge.context.*
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.boolean
|
import space.kscience.dataforge.meta.boolean
|
||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
|
import space.kscience.visionforge.computePropertyNode
|
||||||
import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE
|
import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY
|
||||||
@ -73,7 +74,7 @@ class FX3DPlugin : AbstractPlugin() {
|
|||||||
is PolyLine -> PolyLine3D(
|
is PolyLine -> PolyLine3D(
|
||||||
obj.points.map { Point3D(it.x, it.y, it.z) },
|
obj.points.map { Point3D(it.x, it.y, it.z) },
|
||||||
obj.thickness.toFloat(),
|
obj.thickness.toFloat(),
|
||||||
obj.getProperty(SolidMaterial.MATERIAL_COLOR_KEY, inherit = true)?.color()
|
obj.computePropertyNode(SolidMaterial.MATERIAL_COLOR_KEY)?.color()
|
||||||
).apply {
|
).apply {
|
||||||
this.meshView.cullFace = CullFace.FRONT
|
this.meshView.cullFace = CullFace.FRONT
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,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.onPropertyChange(plugin.context) { name->
|
obj.onPropertyChange { name->
|
||||||
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
|
@ -7,6 +7,7 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.startsWith
|
import space.kscience.dataforge.names.startsWith
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.computePropertyNode
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
|
|||||||
private val bindings = HashMap<Name, ObjectBinding<Meta?>>()
|
private val bindings = HashMap<Name, ObjectBinding<Meta?>>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
obj.onPropertyChange(fx.context) { name ->
|
obj.onPropertyChange { 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()
|
||||||
@ -35,7 +36,7 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
|
|||||||
public operator fun get(key: Name): ObjectBinding<Meta?> {
|
public operator fun get(key: Name): ObjectBinding<Meta?> {
|
||||||
return bindings.getOrPut(key) {
|
return bindings.getOrPut(key) {
|
||||||
object : ObjectBinding<Meta?>() {
|
object : ObjectBinding<Meta?>() {
|
||||||
override fun computeValue(): Meta? = obj.getProperty(key)
|
override fun computeValue(): Meta? = obj.computePropertyNode(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public class VisionOfMarkup(
|
|||||||
//TODO add templates
|
//TODO add templates
|
||||||
|
|
||||||
public var content: String?
|
public var content: String?
|
||||||
get() = getOwnProperty(CONTENT_PROPERTY_KEY).string
|
get() = meta.getMeta(CONTENT_PROPERTY_KEY).string
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(CONTENT_PROPERTY_KEY, value)
|
setProperty(CONTENT_PROPERTY_KEY, value)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@ package space.kscience.visionforge.plotly
|
|||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
|
||||||
import space.kscience.dataforge.meta.asObservable
|
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.plotly.Plot
|
import space.kscience.plotly.Plot
|
||||||
import space.kscience.plotly.Plotly
|
import space.kscience.plotly.Plotly
|
||||||
@ -18,7 +16,7 @@ public class VisionOfPlotly private constructor() : VisionBase() {
|
|||||||
properties = plot.meta
|
properties = plot.meta
|
||||||
}
|
}
|
||||||
|
|
||||||
public val plot: Plot get() = Plot(properties?.asObservable() ?: MutableMeta())
|
public val plot: Plot get() = Plot(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
||||||
|
@ -137,7 +137,7 @@ public class VisionServer internal constructor(
|
|||||||
val change = visionManager.jsonFormat.decodeFromString(
|
val change = visionManager.jsonFormat.decodeFromString(
|
||||||
VisionChange.serializer(), it.data.decodeToString()
|
VisionChange.serializer(), it.data.decodeToString()
|
||||||
)
|
)
|
||||||
vision.change(change)
|
vision.update(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,20 +6,23 @@ import space.kscience.dataforge.values.Value
|
|||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.dataforge.values.string
|
import space.kscience.dataforge.values.string
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionBuilder
|
import space.kscience.visionforge.VisionBuilder
|
||||||
|
import space.kscience.visionforge.VisionPropertyContainer
|
||||||
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public class ColorAccessor(private val parent: MutableMetaProvider, private val colorKey: Name) {
|
public class ColorAccessor(private val colorKey: Name, private val parent: () -> MutableMetaProvider) {
|
||||||
public var value: Value?
|
public var value: Value?
|
||||||
get() = parent.getMeta(colorKey)?.value
|
get() = parent().getMeta(colorKey)?.value
|
||||||
set(value) {
|
set(value) {
|
||||||
parent.setValue(colorKey,value)
|
parent().setValue(colorKey,value)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var item: Meta?
|
public var item: Meta?
|
||||||
get() = parent.getMeta(colorKey)
|
get() = parent().getMeta(colorKey)
|
||||||
set(value) {
|
set(value) {
|
||||||
parent.setMeta(colorKey,value)
|
parent().setMeta(colorKey,value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
|||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import space.kscience.dataforge.meta.configure
|
||||||
import space.kscience.dataforge.meta.update
|
import space.kscience.dataforge.meta.update
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
|
||||||
@ -29,20 +30,20 @@ public inline fun VisionContainerBuilder<Solid>.composite(
|
|||||||
val group = SolidGroup().apply(builder)
|
val group = SolidGroup().apply(builder)
|
||||||
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 { composite ->
|
return Composite(type, children[0], children[1]).apply {
|
||||||
composite.configure {
|
configure {
|
||||||
update(group.meta())
|
update(group.meta)
|
||||||
}
|
}
|
||||||
if (group.position != null) {
|
if (group.position != null) {
|
||||||
composite.position = group.position
|
position = group.position
|
||||||
}
|
}
|
||||||
if (group.rotation != null) {
|
if (group.rotation != null) {
|
||||||
composite.rotation = group.rotation
|
rotation = group.rotation
|
||||||
}
|
}
|
||||||
if (group.scale != null) {
|
if (group.scale != null) {
|
||||||
composite.scale = group.scale
|
scale = group.scale
|
||||||
}
|
}
|
||||||
set(name, composite)
|
set(name, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import kotlinx.serialization.SerialName
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
|
import space.kscience.dataforge.meta.configure
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -106,7 +107,9 @@ public class ExtrudeBuilder(
|
|||||||
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
|
layers.add(Layer(x.toFloat(), y.toFloat(), z.toFloat(), scale.toFloat()))
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun build(): Extruded = Extruded(shape, layers).apply { configure(meta()) }
|
internal fun build(): Extruded = Extruded(shape, layers).apply {
|
||||||
|
configure(this@ExtrudeBuilder.meta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
|
@ -5,8 +5,7 @@ import space.kscience.dataforge.meta.descriptors.*
|
|||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.*
|
||||||
import space.kscience.dataforge.values.asValue
|
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.Vision.Companion.VISIBLE_KEY
|
import space.kscience.visionforge.Vision.Companion.VISIBLE_KEY
|
||||||
import space.kscience.visionforge.solid.Solid.Companion.DETAIL_KEY
|
import space.kscience.visionforge.solid.Solid.Companion.DETAIL_KEY
|
||||||
@ -76,6 +75,8 @@ public interface Solid : Vision {
|
|||||||
default(true)
|
default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node(SolidMaterial.MATERIAL_KEY.toString(), SolidMaterial)
|
||||||
|
|
||||||
//TODO replace by descriptor merge
|
//TODO replace by descriptor merge
|
||||||
value(Vision.STYLE_KEY, ValueType.STRING) {
|
value(Vision.STYLE_KEY, ValueType.STRING) {
|
||||||
multiple = true
|
multiple = true
|
||||||
@ -98,10 +99,6 @@ public interface Solid : Vision {
|
|||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
item(SolidMaterial.MATERIAL_KEY.toString(), SolidMaterial){
|
|
||||||
valueRequirement = ValueRequirement.ABSENT
|
|
||||||
}
|
|
||||||
|
|
||||||
enum(ROTATION_ORDER_KEY, default = RotationOrder.XYZ) {
|
enum(ROTATION_ORDER_KEY, default = RotationOrder.XYZ) {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
@ -114,7 +111,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() = getProperty(LAYER_KEY, inherit = true).int ?: 0
|
get() = getPropertyValue(LAYER_KEY, inherit = true)?.int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(LAYER_KEY, value)
|
setProperty(LAYER_KEY, value)
|
||||||
}
|
}
|
||||||
@ -134,24 +131,24 @@ public enum class RotationOrder {
|
|||||||
* Rotation order
|
* Rotation order
|
||||||
*/
|
*/
|
||||||
public var Solid.rotationOrder: RotationOrder
|
public var Solid.rotationOrder: RotationOrder
|
||||||
get() = getProperty(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
|
get() = getPropertyValue(Solid.ROTATION_ORDER_KEY)?.enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||||
set(value) = setPropertyValue(Solid.ROTATION_ORDER_KEY, value.name.asValue())
|
set(value) = meta.setValue(Solid.ROTATION_ORDER_KEY, value.name.asValue())
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
|
* Preferred number of polygons for displaying the object. If not defined, uses shape or renderer default. Not inherited
|
||||||
*/
|
*/
|
||||||
public var Solid.detail: Int?
|
public var Solid.detail: Int?
|
||||||
get() = getProperty(DETAIL_KEY, false).int
|
get() = getPropertyValue(DETAIL_KEY, false)?.int
|
||||||
set(value) = setPropertyValue(DETAIL_KEY, value?.asValue())
|
set(value) = meta.setValue(DETAIL_KEY, value?.asValue())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this property is true, the object will be ignored on render.
|
* If this property is true, the object will be ignored on render.
|
||||||
* Property is not inherited.
|
* Property is not inherited.
|
||||||
*/
|
*/
|
||||||
public var Vision.ignore: Boolean?
|
public var Vision.ignore: Boolean?
|
||||||
get() = getProperty(IGNORE_KEY, false).boolean
|
get() = getPropertyValue(IGNORE_KEY, false)?.boolean
|
||||||
set(value) = setPropertyValue(IGNORE_KEY, value?.asValue())
|
set(value) = meta.setValue(IGNORE_KEY, value?.asValue())
|
||||||
|
|
||||||
//var VisualObject.selected: Boolean?
|
//var VisualObject.selected: Boolean?
|
||||||
// get() = getProperty(SELECTED_KEY).boolean
|
// get() = getProperty(SELECTED_KEY).boolean
|
||||||
@ -160,7 +157,7 @@ public var Vision.ignore: Boolean?
|
|||||||
internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
|
internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number> =
|
||||||
object : ReadWriteProperty<Solid, Number> {
|
object : ReadWriteProperty<Solid, Number> {
|
||||||
override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
|
override fun getValue(thisRef: Solid, property: KProperty<*>): Number {
|
||||||
return thisRef.getOwnProperty(name)?.number ?: default
|
return thisRef.meta.getMeta(name)?.number ?: default
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Number) {
|
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Number) {
|
||||||
@ -171,7 +168,7 @@ internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number
|
|||||||
internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
|
internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
|
||||||
object : ReadWriteProperty<Solid, Point3D?> {
|
object : ReadWriteProperty<Solid, Point3D?> {
|
||||||
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
|
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
|
||||||
val item = thisRef.getOwnProperty(name) ?: return null
|
val item = thisRef.meta.getMeta(name) ?: return null
|
||||||
return object : Point3D {
|
return object : Point3D {
|
||||||
override val x: Float get() = item[X_KEY]?.float ?: default
|
override val x: Float get() = item[X_KEY]?.float ?: default
|
||||||
override val y: Float get() = item[Y_KEY]?.float ?: default
|
override val y: Float get() = item[Y_KEY]?.float ?: default
|
||||||
@ -181,7 +178,7 @@ internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D
|
|||||||
|
|
||||||
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
|
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
thisRef.setPropertyNode(name, null)
|
thisRef.meta.setMeta(name, null)
|
||||||
} else {
|
} else {
|
||||||
thisRef.setProperty(name + X_KEY, value.x)
|
thisRef.setProperty(name + X_KEY, value.x)
|
||||||
thisRef.setProperty(name + Y_KEY, value.y)
|
thisRef.setProperty(name + Y_KEY, value.y)
|
||||||
|
@ -11,8 +11,8 @@ import space.kscience.visionforge.VisionChange
|
|||||||
public open class SolidBase : VisionBase(), Solid {
|
public open class SolidBase : VisionBase(), Solid {
|
||||||
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
||||||
|
|
||||||
override fun change(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
updatePosition(change.properties)
|
updatePosition(change.properties)
|
||||||
super.change(change)
|
super.update(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,9 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
|
|||||||
|
|
||||||
override fun createGroup(): SolidGroup = SolidGroup()
|
override fun createGroup(): SolidGroup = SolidGroup()
|
||||||
|
|
||||||
override fun change(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
updatePosition(change.properties)
|
updatePosition(change.properties)
|
||||||
super.change(change)
|
super.update(change)
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
@ -8,6 +8,7 @@ import space.kscience.dataforge.names.asName
|
|||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
|
import space.kscience.dataforge.values.number
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
|
||||||
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
|
||||||
@ -19,14 +20,14 @@ public class SolidMaterial : Scheme() {
|
|||||||
/**
|
/**
|
||||||
* Primary web-color for the material
|
* Primary web-color for the material
|
||||||
*/
|
*/
|
||||||
public val color: ColorAccessor = ColorAccessor(this, COLOR_KEY)
|
public val color: ColorAccessor = ColorAccessor(COLOR_KEY) { meta }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specular color for phong material
|
* Specular color for phong material
|
||||||
*/
|
*/
|
||||||
public val specularColor: ColorAccessor = ColorAccessor(this, SPECULAR_COLOR_KEY)
|
public val specularColor: ColorAccessor = ColorAccessor(SPECULAR_COLOR_KEY) { meta }
|
||||||
|
|
||||||
public val emissiveColor: ColorAccessor = ColorAccessor(this, "emissiveColor".asName())
|
public val emissiveColor: ColorAccessor = ColorAccessor("emissiveColor".asName()) { meta }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opacity
|
* Opacity
|
||||||
@ -89,24 +90,19 @@ public class SolidMaterial : Scheme() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val Solid.color: ColorAccessor
|
public val Solid.color: ColorAccessor
|
||||||
get() = ColorAccessor(
|
get() = ColorAccessor(MATERIAL_COLOR_KEY) { computeProperties() }
|
||||||
meta(inherit = true),
|
|
||||||
MATERIAL_COLOR_KEY
|
|
||||||
)
|
|
||||||
|
|
||||||
public var Solid.material: SolidMaterial?
|
public var Solid.material: SolidMaterial?
|
||||||
get() = getProperty(MATERIAL_KEY, inherit = true)?.let { SolidMaterial.read(it) }
|
get() = computePropertyNode(MATERIAL_KEY)?.let { SolidMaterial.read(it) }
|
||||||
set(value) = setPropertyNode(MATERIAL_KEY, value?.meta)
|
set(value) = meta.setMeta(MATERIAL_KEY, value?.meta)
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||||
configure(MATERIAL_KEY){
|
meta.getOrCreate(MATERIAL_KEY).updateWith(SolidMaterial, builder)
|
||||||
updateWith(SolidMaterial,builder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var Solid.opacity: Number?
|
public var Solid.opacity: Number?
|
||||||
get() = getProperty(MATERIAL_OPACITY_KEY, inherit = true).number
|
get() = getPropertyValue(MATERIAL_OPACITY_KEY, inherit = true)?.number
|
||||||
set(value) {
|
set(value) {
|
||||||
setPropertyValue(MATERIAL_OPACITY_KEY, value?.asValue())
|
meta.setValue(MATERIAL_OPACITY_KEY, value?.asValue())
|
||||||
}
|
}
|
@ -1,12 +1,10 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
@ -17,6 +15,18 @@ public interface SolidReference : VisionGroup {
|
|||||||
* The prototype for this reference. Always returns a "real" prototype, not a reference
|
* The prototype for this reference. Always returns a "real" prototype, not a reference
|
||||||
*/
|
*/
|
||||||
public val prototype: Solid
|
public val prototype: Solid
|
||||||
|
|
||||||
|
override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? {
|
||||||
|
meta[name]?.value?.let { return it }
|
||||||
|
if (includeStyles) {
|
||||||
|
getStyleProperty(name)?.let { return it }
|
||||||
|
}
|
||||||
|
prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||||
|
if (inherit) {
|
||||||
|
parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -31,27 +41,6 @@ public val Vision.unref: Solid
|
|||||||
else -> error("This Vision is neither Solid nor SolidReference")
|
else -> error("This Vision is neither Solid nor SolidReference")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun SolidReference.getRefProperty(
|
|
||||||
name: Name,
|
|
||||||
inherit: Boolean,
|
|
||||||
includeStyles: Boolean,
|
|
||||||
includeDefaults: Boolean,
|
|
||||||
): Meta? = if (!inherit && !includeStyles && !includeDefaults) {
|
|
||||||
getOwnProperty(name)
|
|
||||||
} else {
|
|
||||||
buildList {
|
|
||||||
add(getOwnProperty(name))
|
|
||||||
if (includeStyles) {
|
|
||||||
addAll(getStyleItems(name))
|
|
||||||
}
|
|
||||||
add(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
|
||||||
if (inherit) {
|
|
||||||
add(parent?.getProperty(name, inherit))
|
|
||||||
}
|
|
||||||
}.merge()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun childToken(childName: Name): NameToken =
|
private fun childToken(childName: Name): NameToken =
|
||||||
NameToken(SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString())
|
NameToken(SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString())
|
||||||
|
|
||||||
@ -83,12 +72,8 @@ public class SolidReferenceGroup(
|
|||||||
ReferenceChild(this, it.key.asName())
|
ReferenceChild(this, it.key.asName())
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
|
|
||||||
override fun getProperty(
|
override fun getPropertyValue(name: Name, inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean): Value? =
|
||||||
name: Name,
|
super<SolidReference>.getPropertyValue(name, inherit, includeStyles, includeDefaults)
|
||||||
inherit: Boolean,
|
|
||||||
includeStyles: Boolean,
|
|
||||||
includeDefaults: Boolean,
|
|
||||||
): Meta? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||||
|
|
||||||
@ -111,6 +96,10 @@ public class SolidReferenceGroup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val meta: ObservableMutableMeta by lazy {
|
||||||
|
owner.meta.getOrCreate(childToken(refName).asName())
|
||||||
|
}
|
||||||
|
|
||||||
override val children: Map<NameToken, Vision>
|
override val children: Map<NameToken, Vision>
|
||||||
get() = (prototype as? VisionGroup)?.children
|
get() = (prototype as? VisionGroup)?.children
|
||||||
?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
|
?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
|
||||||
@ -118,24 +107,6 @@ public class SolidReferenceGroup(
|
|||||||
ReferenceChild(owner, refName + key.asName())
|
ReferenceChild(owner, refName + key.asName())
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
|
|
||||||
override fun getOwnProperty(name: Name): Meta? =
|
|
||||||
owner.getOwnProperty(childPropertyName(refName, name))
|
|
||||||
|
|
||||||
override fun setPropertyNode(name: Name, node: Meta?, notify: Boolean) {
|
|
||||||
owner.setPropertyNode(childPropertyName(refName, name), node, notify)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setPropertyValue(name: Name, value: Value?, notify: Boolean) {
|
|
||||||
owner.setPropertyValue(childPropertyName(refName, name), value, notify)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getProperty(
|
|
||||||
name: Name,
|
|
||||||
inherit: Boolean,
|
|
||||||
includeStyles: Boolean,
|
|
||||||
includeDefaults: Boolean,
|
|
||||||
): Meta? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
|
||||||
|
|
||||||
override var parent: VisionGroup?
|
override var parent: VisionGroup?
|
||||||
get() {
|
get() {
|
||||||
val parentName = refName.cutLast()
|
val parentName = refName.cutLast()
|
||||||
@ -145,21 +116,11 @@ public class SolidReferenceGroup(
|
|||||||
error("Setting a parent for a reference child is not possible")
|
error("Setting a parent for a reference child is not possible")
|
||||||
}
|
}
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
override val propertyChanges: Flow<Name>
|
|
||||||
get() = owner.propertyChanges.mapNotNull { name ->
|
|
||||||
if (name.startsWith(childToken(refName))) {
|
|
||||||
name.cutFirst()
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidateProperty(propertyName: Name) {
|
override fun invalidateProperty(propertyName: Name) {
|
||||||
owner.invalidateProperty(childPropertyName(refName, propertyName))
|
owner.invalidateProperty(childPropertyName(refName, propertyName))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun change(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
change.properties?.let {
|
change.properties?.let {
|
||||||
updateProperties(Name.EMPTY, it)
|
updateProperties(Name.EMPTY, it)
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ import space.kscience.dataforge.meta.Scheme
|
|||||||
import space.kscience.dataforge.meta.SchemeSpec
|
import space.kscience.dataforge.meta.SchemeSpec
|
||||||
import space.kscience.dataforge.meta.boolean
|
import space.kscience.dataforge.meta.boolean
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.meta.double
|
import space.kscience.dataforge.meta.double
|
||||||
import space.kscience.visionforge.value
|
|
||||||
|
|
||||||
public class Axes : Scheme() {
|
public class Axes : Scheme() {
|
||||||
public var visible: Boolean by boolean(false)
|
public var visible: Boolean by boolean(false)
|
||||||
|
@ -3,9 +3,9 @@ package space.kscience.visionforge.solid.specifications
|
|||||||
import space.kscience.dataforge.meta.Scheme
|
import space.kscience.dataforge.meta.Scheme
|
||||||
import space.kscience.dataforge.meta.SchemeSpec
|
import space.kscience.dataforge.meta.SchemeSpec
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.meta.double
|
import space.kscience.dataforge.meta.double
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.visionforge.value
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
public class Camera : Scheme() {
|
public class Camera : Scheme() {
|
||||||
@ -27,24 +27,24 @@ public class Camera : Scheme() {
|
|||||||
public const val FAR_CLIP: Double = 10000.0
|
public const val FAR_CLIP: Double = 10000.0
|
||||||
public const val FIELD_OF_VIEW: Int = 75
|
public const val FIELD_OF_VIEW: Int = 75
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor by lazy {
|
override val descriptor: MetaDescriptor by lazy {
|
||||||
MetaDescriptor {
|
MetaDescriptor {
|
||||||
value(Camera::fov){
|
value(Camera::fov) {
|
||||||
default(FIELD_OF_VIEW)
|
default(FIELD_OF_VIEW)
|
||||||
}
|
}
|
||||||
value(Camera::nearClip){
|
value(Camera::nearClip) {
|
||||||
default(NEAR_CLIP)
|
default(NEAR_CLIP)
|
||||||
}
|
}
|
||||||
value(Camera::farClip){
|
value(Camera::farClip) {
|
||||||
default(FAR_CLIP)
|
default(FAR_CLIP)
|
||||||
}
|
}
|
||||||
value(Camera::distance){
|
value(Camera::distance) {
|
||||||
default(INITIAL_DISTANCE)
|
default(INITIAL_DISTANCE)
|
||||||
}
|
}
|
||||||
value(Camera::azimuth){
|
value(Camera::azimuth) {
|
||||||
default(INITIAL_AZIMUTH)
|
default(INITIAL_AZIMUTH)
|
||||||
}
|
}
|
||||||
value(Camera::latitude){
|
value(Camera::latitude) {
|
||||||
default(INITIAL_LATITUDE)
|
default(INITIAL_LATITUDE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ package space.kscience.visionforge.solid.specifications
|
|||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.scheme
|
||||||
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.visionforge.hide
|
import space.kscience.visionforge.hide
|
||||||
import space.kscience.visionforge.scheme
|
|
||||||
import space.kscience.visionforge.value
|
|
||||||
import space.kscience.visionforge.widgetType
|
import space.kscience.visionforge.widgetType
|
||||||
|
|
||||||
public class Clipping : Scheme() {
|
public class Clipping : Scheme() {
|
||||||
@ -80,7 +80,19 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
override val descriptor: MetaDescriptor by lazy {
|
override val descriptor: MetaDescriptor by lazy {
|
||||||
MetaDescriptor {
|
MetaDescriptor {
|
||||||
scheme(Canvas3DOptions::axes, Axes)
|
scheme(Canvas3DOptions::axes, Axes)
|
||||||
scheme(Canvas3DOptions::light, Light)
|
|
||||||
|
value(Canvas3DOptions::layers) {
|
||||||
|
multiple = true
|
||||||
|
default(listOf(0))
|
||||||
|
widgetType = "multiSelect"
|
||||||
|
allowedValues(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme(Canvas3DOptions::clipping, Clipping)
|
||||||
|
|
||||||
|
scheme(Canvas3DOptions::light, Light){
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
|
||||||
scheme(Canvas3DOptions::camera, Camera) {
|
scheme(Canvas3DOptions::camera, Camera) {
|
||||||
hide()
|
hide()
|
||||||
@ -93,15 +105,6 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
scheme(Canvas3DOptions::size, CanvasSize) {
|
scheme(Canvas3DOptions::size, CanvasSize) {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
value(Canvas3DOptions::layers) {
|
|
||||||
type(ValueType.NUMBER)
|
|
||||||
multiple = true
|
|
||||||
default(listOf(0))
|
|
||||||
widgetType = "multiSelect"
|
|
||||||
allowedValues(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
|
||||||
}
|
|
||||||
scheme(Canvas3DOptions::clipping, Clipping)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.visionforge.solid.transform
|
package space.kscience.visionforge.solid.transform
|
||||||
|
|
||||||
|
import space.kscience.dataforge.meta.configure
|
||||||
import space.kscience.dataforge.meta.update
|
import space.kscience.dataforge.meta.update
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
@ -22,7 +23,7 @@ internal fun Vision.updateFrom(other: Vision): Vision {
|
|||||||
scaleY *= other.scaleY
|
scaleY *= other.scaleY
|
||||||
scaleZ *= other.scaleZ
|
scaleZ *= other.scaleZ
|
||||||
configure{
|
configure{
|
||||||
update(other.meta())
|
update(other.meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
|
import space.kscience.dataforge.values.int
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
class PropertyTest {
|
class PropertyTest {
|
||||||
|
@Test
|
||||||
|
fun testColorUpdate(){
|
||||||
|
val box = Box(10.0f, 10.0f,10.0f)
|
||||||
|
box.material {
|
||||||
|
//meta["color"] = "pink"
|
||||||
|
color("pink")
|
||||||
|
}
|
||||||
|
assertEquals("pink", box.meta["material.color"]?.string)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testInheritedProperty() {
|
fun testInheritedProperty() {
|
||||||
var box: Box? = null
|
var box: Box? = null
|
||||||
@ -17,7 +28,7 @@ class PropertyTest {
|
|||||||
box = box(100, 100, 100)
|
box = box(100, 100, 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertEquals(22, box?.getProperty("test", inherit = true).int)
|
assertEquals(22, box?.getPropertyValue("test", inherit = true)?.int)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -35,11 +46,11 @@ class PropertyTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertEquals(22, box?.getProperty("test").int)
|
assertEquals(22, box?.getPropertyValue("test")?.int)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testColor() {
|
fun testStyleColor() {
|
||||||
var box: Box? = null
|
var box: Box? = null
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup().apply {
|
||||||
styleSheet {
|
styleSheet {
|
||||||
|
@ -3,7 +3,6 @@ package space.kscience.visionforge.solid
|
|||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.MutableVisionGroup
|
import space.kscience.visionforge.MutableVisionGroup
|
||||||
import space.kscience.visionforge.get
|
import space.kscience.visionforge.get
|
||||||
import space.kscience.visionforge.meta
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ class SerializationTest {
|
|||||||
val string = Solids.encodeToString(cube)
|
val string = Solids.encodeToString(cube)
|
||||||
println(string)
|
println(string)
|
||||||
val newCube = Solids.decodeFromString(string)
|
val newCube = Solids.decodeFromString(string)
|
||||||
assertEquals(cube.meta(), newCube.meta())
|
assertEquals(cube.meta, newCube.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -53,7 +52,7 @@ class SerializationTest {
|
|||||||
val string = Solids.encodeToString(group)
|
val string = Solids.encodeToString(group)
|
||||||
println(string)
|
println(string)
|
||||||
val reconstructed = Solids.decodeFromString(string) as SolidGroup
|
val reconstructed = Solids.decodeFromString(string) as SolidGroup
|
||||||
assertEquals(group["cube"]?.meta(), reconstructed["cube"]?.meta())
|
assertEquals(group["cube"]?.meta, reconstructed["cube"]?.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ class VisionUpdateTest {
|
|||||||
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
}
|
}
|
||||||
targetVision.change(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 Solid).color.string) // new item always takes precedence
|
assertEquals("#00007b", (targetVision["top"] as Solid).color.string) // new item always takes precedence
|
||||||
|
@ -4,12 +4,13 @@ import info.laht.threekt.core.BufferGeometry
|
|||||||
import info.laht.threekt.geometries.EdgesGeometry
|
import info.laht.threekt.geometries.EdgesGeometry
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import space.kscience.dataforge.meta.boolean
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.node
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.dataforge.names.startsWith
|
import space.kscience.dataforge.names.startsWith
|
||||||
|
import space.kscience.dataforge.values.boolean
|
||||||
|
import space.kscience.visionforge.computeProperties
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
@ -40,7 +41,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.onPropertyChange(three.updateScope) { name ->
|
obj.onPropertyChange { 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
|
||||||
@ -83,14 +84,10 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
|
|||||||
public fun Mesh.applyEdges(obj: Solid) {
|
public fun Mesh.applyEdges(obj: Solid) {
|
||||||
val edges = children.find { it.name == "@edges" } as? LineSegments
|
val edges = children.find { it.name == "@edges" } as? LineSegments
|
||||||
//inherited edges definition, enabled by default
|
//inherited edges definition, enabled by default
|
||||||
if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = true, includeStyles = true).boolean != false) {
|
if (obj.getPropertyValue(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = true, includeStyles = true)?.boolean != false) {
|
||||||
val bufferGeometry = geometry as? BufferGeometry ?: return
|
val bufferGeometry = geometry as? BufferGeometry ?: return
|
||||||
val material = ThreeMaterials.getLineMaterial(
|
val material = ThreeMaterials.getLineMaterial(
|
||||||
obj.getProperty(
|
obj.computeProperties().get(MeshThreeFactory.EDGES_MATERIAL_KEY),
|
||||||
MeshThreeFactory.EDGES_MATERIAL_KEY,
|
|
||||||
inherit = true,
|
|
||||||
includeStyles = true
|
|
||||||
),
|
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
if (edges == null) {
|
if (edges == null) {
|
||||||
|
@ -48,7 +48,7 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory
|
|||||||
}.apply {
|
}.apply {
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
applyProperties(obj)
|
applyProperties(obj)
|
||||||
obj.onPropertyChange(three.updateScope) { name ->
|
obj.onPropertyChange { name ->
|
||||||
when {
|
when {
|
||||||
//name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
//name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
||||||
name.startsWith(MeshThreeFactory.EDGES_KEY) -> applyEdges(obj)
|
name.startsWith(MeshThreeFactory.EDGES_KEY) -> applyEdges(obj)
|
||||||
|
@ -40,7 +40,7 @@ public class ThreeGeometryBuilder : GeometryBuilder<BufferGeometry> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
|
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
|
||||||
val actualNormal: Point3D = normal ?: (vertex3 - vertex2) cross (vertex1 - vertex2)
|
val actualNormal: Point3D = normal ?: ((vertex3 - vertex2) cross (vertex1 - vertex2))
|
||||||
indices.add(
|
indices.add(
|
||||||
vertex(vertex1, actualNormal),
|
vertex(vertex1, actualNormal),
|
||||||
vertex(vertex2, actualNormal),
|
vertex(vertex2, actualNormal),
|
||||||
|
@ -27,7 +27,7 @@ public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
|||||||
return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
|
return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
|
||||||
updateMaterial(obj)
|
updateMaterial(obj)
|
||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
obj.onPropertyChange(three.updateScope) { _ ->
|
obj.onPropertyChange { _ ->
|
||||||
//TODO
|
//TODO
|
||||||
three.logger.warn { "Label parameter change not implemented" }
|
three.logger.warn { "Label parameter change not implemented" }
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import info.laht.threekt.core.BufferGeometry
|
|||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.math.Color
|
import info.laht.threekt.math.Color
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
|
import space.kscience.visionforge.computePropertyNode
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.solid.PolyLine
|
import space.kscience.visionforge.solid.PolyLine
|
||||||
import space.kscience.visionforge.solid.color
|
import space.kscience.visionforge.solid.color
|
||||||
@ -20,7 +21,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val material = ThreeMaterials.getLineMaterial(
|
val material = ThreeMaterials.getLineMaterial(
|
||||||
obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY),
|
obj.computePropertyNode(MeshThreeFactory.EDGES_MATERIAL_KEY),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,7 +32,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.onPropertyChange(three.updateScope) { propertyName ->
|
obj.onPropertyChange { propertyName ->
|
||||||
updateProperty(obj, propertyName)
|
updateProperty(obj, propertyName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,10 @@ import info.laht.threekt.math.Color
|
|||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.*
|
||||||
import space.kscience.dataforge.values.int
|
|
||||||
import space.kscience.dataforge.values.string
|
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.meta
|
import space.kscience.visionforge.computePropertyNode
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
|
|
||||||
|
|
||||||
@ -117,8 +115,8 @@ private var Material.cached: Boolean
|
|||||||
|
|
||||||
public fun Mesh.updateMaterial(vision: Vision) {
|
public fun Mesh.updateMaterial(vision: Vision) {
|
||||||
//val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node
|
//val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node
|
||||||
val ownMaterialMeta = vision.meta()[SolidMaterial.MATERIAL_KEY]
|
val ownMaterialMeta = vision.meta.getMeta(SolidMaterial.MATERIAL_KEY)
|
||||||
val parentMaterialMeta = vision.parent?.getProperty(
|
val parentMaterialMeta = vision.parent?.getPropertyValue(
|
||||||
SolidMaterial.MATERIAL_KEY,
|
SolidMaterial.MATERIAL_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
includeStyles = false,
|
includeStyles = false,
|
||||||
@ -128,19 +126,15 @@ public fun Mesh.updateMaterial(vision: Vision) {
|
|||||||
material = when {
|
material = when {
|
||||||
ownMaterialMeta == null && parentMaterialMeta == null -> {
|
ownMaterialMeta == null && parentMaterialMeta == null -> {
|
||||||
//If material is style-based, use cached
|
//If material is style-based, use cached
|
||||||
vision.getProperty(
|
vision.computePropertyNode(
|
||||||
SolidMaterial.MATERIAL_KEY,
|
SolidMaterial.MATERIAL_KEY,
|
||||||
inherit = false,
|
|
||||||
includeStyles = true,
|
|
||||||
includeDefaults = false
|
|
||||||
)?.let {
|
)?.let {
|
||||||
ThreeMaterials.cacheMaterial(it)
|
ThreeMaterials.cacheMaterial(it)
|
||||||
} ?: ThreeMaterials.DEFAULT
|
} ?: ThreeMaterials.DEFAULT
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
vision.getProperty(
|
vision.computePropertyNode(
|
||||||
SolidMaterial.MATERIAL_KEY,
|
SolidMaterial.MATERIAL_KEY,
|
||||||
inherit = true
|
|
||||||
)?.let {
|
)?.let {
|
||||||
ThreeMaterials.buildMaterial(it)
|
ThreeMaterials.buildMaterial(it)
|
||||||
} ?: ThreeMaterials.DEFAULT
|
} ?: ThreeMaterials.DEFAULT
|
||||||
@ -155,32 +149,29 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
|||||||
} else {
|
} else {
|
||||||
when (propertyName) {
|
when (propertyName) {
|
||||||
SolidMaterial.MATERIAL_COLOR_KEY -> {
|
SolidMaterial.MATERIAL_COLOR_KEY -> {
|
||||||
material.asDynamic().color = vision.getProperty(
|
material.asDynamic().color = vision.computePropertyNode(
|
||||||
SolidMaterial.MATERIAL_COLOR_KEY,
|
SolidMaterial.MATERIAL_COLOR_KEY,
|
||||||
inherit = true,
|
|
||||||
includeStyles = true,
|
|
||||||
includeDefaults = false
|
|
||||||
)?.threeColor() ?: ThreeMaterials.DEFAULT_COLOR
|
)?.threeColor() ?: ThreeMaterials.DEFAULT_COLOR
|
||||||
material.needsUpdate = true
|
material.needsUpdate = true
|
||||||
}
|
}
|
||||||
SolidMaterial.MATERIAL_OPACITY_KEY -> {
|
SolidMaterial.MATERIAL_OPACITY_KEY -> {
|
||||||
val opacity = vision.getProperty(
|
val opacity = vision.getPropertyValue(
|
||||||
SolidMaterial.MATERIAL_OPACITY_KEY,
|
SolidMaterial.MATERIAL_OPACITY_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
includeStyles = true,
|
includeStyles = true,
|
||||||
includeDefaults = false
|
includeDefaults = false
|
||||||
).double ?: 1.0
|
)?.double ?: 1.0
|
||||||
material.opacity = opacity
|
material.opacity = opacity
|
||||||
material.transparent = opacity < 1.0
|
material.transparent = opacity < 1.0
|
||||||
material.needsUpdate = true
|
material.needsUpdate = true
|
||||||
}
|
}
|
||||||
SolidMaterial.MATERIAL_WIREFRAME_KEY -> {
|
SolidMaterial.MATERIAL_WIREFRAME_KEY -> {
|
||||||
material.asDynamic().wireframe = vision.getProperty(
|
material.asDynamic().wireframe = vision.getPropertyValue(
|
||||||
SolidMaterial.MATERIAL_WIREFRAME_KEY,
|
SolidMaterial.MATERIAL_WIREFRAME_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
includeStyles = true,
|
includeStyles = true,
|
||||||
includeDefaults = false
|
includeDefaults = false
|
||||||
).boolean ?: false
|
)?.boolean ?: false
|
||||||
material.needsUpdate = true
|
material.needsUpdate = true
|
||||||
}
|
}
|
||||||
else -> console.warn("Unrecognized material property: $propertyName")
|
else -> console.warn("Unrecognized material property: $propertyName")
|
||||||
|
@ -69,7 +69,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
updatePosition(obj)
|
updatePosition(obj)
|
||||||
//obj.onChildrenChange()
|
//obj.onChildrenChange()
|
||||||
|
|
||||||
obj.onPropertyChange(updateScope) { name ->
|
obj.onPropertyChange { name ->
|
||||||
if (
|
if (
|
||||||
name.startsWith(Solid.POSITION_KEY) ||
|
name.startsWith(Solid.POSITION_KEY) ||
|
||||||
name.startsWith(Solid.ROTATION_KEY) ||
|
name.startsWith(Solid.ROTATION_KEY) ||
|
||||||
|
@ -47,7 +47,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
|
|||||||
|
|
||||||
//TODO apply child properties
|
//TODO apply child properties
|
||||||
|
|
||||||
obj.onPropertyChange(three.updateScope) { name->
|
obj.onPropertyChange { name->
|
||||||
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
"OVERRIDING_FINAL_MEMBER",
|
"OVERRIDING_FINAL_MEMBER",
|
||||||
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
||||||
"CONFLICTING_OVERLOADS",
|
"CONFLICTING_OVERLOADS",
|
||||||
"EXTERNAL_DELEGATION"
|
"EXTERNAL_DELEGATION",
|
||||||
|
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING"
|
||||||
)
|
)
|
||||||
|
|
||||||
@file:JsModule("three-csg-ts")
|
@file:JsModule("three-csg-ts")
|
||||||
|
Loading…
Reference in New Issue
Block a user