forked from kscience/visionforge
Adjust property editors
This commit is contained in:
parent
787c841a51
commit
8d21d3cd74
@ -1,18 +1,13 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.project")
|
id("ru.mipt.npm.gradle.project")
|
||||||
|
|
||||||
//Override kotlin version
|
|
||||||
// val kotlinVersion = "1.5.20-RC"
|
|
||||||
// kotlin("multiplatform") version(kotlinVersion) apply false
|
|
||||||
// kotlin("jvm") version(kotlinVersion) apply false
|
|
||||||
// kotlin("js") version(kotlinVersion) apply false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion by extra("0.5.0-dev-2")
|
val dataforgeVersion by extra("0.5.0-dev-9")
|
||||||
val fxVersion by extra("11")
|
val fxVersion by extra("11")
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
jcenter()
|
jcenter()
|
||||||
maven("https://repo.kotlin.link")
|
maven("https://repo.kotlin.link")
|
||||||
@ -29,7 +24,7 @@ subprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ksciencePublish{
|
ksciencePublish {
|
||||||
github("visionforge")
|
github("visionforge")
|
||||||
space()
|
space()
|
||||||
sonatype()
|
sonatype()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package space.kscience.visionforge.gdml
|
package space.kscience.visionforge.gdml
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.gdml.GdmlShowCase
|
import space.kscience.gdml.GdmlShowCase
|
||||||
import space.kscience.visionforge.setProperty
|
import space.kscience.visionforge.setProperty
|
||||||
@ -24,7 +24,7 @@ class GDMLVisionTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testPrototypeProperty() {
|
fun testPrototypeProperty() {
|
||||||
val vision = GdmlShowCase.cubes().toVision()
|
val vision = GdmlShowCase.cubes().toVision()
|
||||||
val child = vision["composite-000.segment-0".toName()]
|
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.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||||
|
@ -8,8 +8,8 @@ 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.describedProperties
|
||||||
import space.kscience.visionforge.editor.VisualObjectEditorFragment
|
import space.kscience.visionforge.editor.VisionEditorFragment
|
||||||
import space.kscience.visionforge.editor.VisualObjectTreeFragment
|
import space.kscience.visionforge.editor.VisionTreeFragment
|
||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
import space.kscience.visionforge.solid.FX3DPlugin
|
import space.kscience.visionforge.solid.FX3DPlugin
|
||||||
import space.kscience.visionforge.solid.FXCanvas3D
|
import space.kscience.visionforge.solid.FXCanvas3D
|
||||||
@ -29,25 +29,24 @@ class GDMLView : View() {
|
|||||||
private val visionManager = context.fetch(VisionManager)
|
private val visionManager = context.fetch(VisionManager)
|
||||||
private val canvas = FXCanvas3D(fx3d)
|
private val canvas = FXCanvas3D(fx3d)
|
||||||
|
|
||||||
private val treeFragment = VisualObjectTreeFragment().apply {
|
private val treeFragment = VisionTreeFragment().apply {
|
||||||
this.itemProperty.bind(canvas.rootObjectProperty)
|
this.itemProperty.bind(canvas.rootObjectProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val propertyEditor = VisualObjectEditorFragment {
|
private val propertyEditor = VisionEditorFragment {
|
||||||
it.describedProperties
|
it.describedProperties
|
||||||
}.apply {
|
}.apply {
|
||||||
descriptorProperty.set(SolidMaterial.descriptor)
|
descriptorProperty.set(SolidMaterial.descriptor)
|
||||||
itemProperty.bind(treeFragment.selectedProperty)
|
itemProperty.bind(treeFragment.selectedProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
top {
|
top {
|
||||||
buttonbar {
|
buttonbar {
|
||||||
button("Load GDML/json") {
|
button("Load GDML/json") {
|
||||||
action {
|
action {
|
||||||
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
|
val file = chooseFile("Select a GDML/json file", filters = fileNameFilter).firstOrNull()
|
||||||
if(file!= null) {
|
if (file != null) {
|
||||||
runAsync {
|
runAsync {
|
||||||
visionManager.readFile(file) as Solid
|
visionManager.readFile(file) as Solid
|
||||||
} ui {
|
} ui {
|
||||||
|
@ -6,6 +6,7 @@ import ru.mipt.npm.muon.monitor.Monitor.UPPER_LAYER_Z
|
|||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
import space.kscience.visionforge.removeAll
|
import space.kscience.visionforge.removeAll
|
||||||
import space.kscience.visionforge.root
|
import space.kscience.visionforge.root
|
||||||
|
import space.kscience.visionforge.setProperty
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ kotlin {
|
|||||||
val jvmMain by getting{
|
val jvmMain by getting{
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":visionforge-server"))
|
api(project(":visionforge-server"))
|
||||||
|
api(project(":visionforge-markdown"))
|
||||||
api("ch.qos.logback:logback-classic:1.2.3")
|
api("ch.qos.logback:logback-classic:1.2.3")
|
||||||
implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
||||||
}
|
}
|
||||||
|
91
demo/playground/src/jvmMain/kotlin/markdownDemo.kt
Normal file
91
demo/playground/src/jvmMain/kotlin/markdownDemo.kt
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package space.kscience.visionforge.examples
|
||||||
|
|
||||||
|
import kotlinx.html.div
|
||||||
|
import kotlinx.html.h1
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
|
import space.kscience.plotly.layout
|
||||||
|
import space.kscience.plotly.models.ScatterMode
|
||||||
|
import space.kscience.plotly.models.TextPosition
|
||||||
|
import space.kscience.plotly.scatter
|
||||||
|
import space.kscience.visionforge.html.ResourceLocation
|
||||||
|
import space.kscience.visionforge.markup.markdown
|
||||||
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
|
import space.kscience.visionforge.plotly.plotly
|
||||||
|
import space.kscience.visionforge.solid.*
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val context = Context {
|
||||||
|
plugin(Solids)
|
||||||
|
plugin(PlotlyPlugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) {
|
||||||
|
markdown {
|
||||||
|
//language=markdown
|
||||||
|
"""
|
||||||
|
# Section
|
||||||
|
|
||||||
|
**TBD**
|
||||||
|
|
||||||
|
## Subsection
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
h1 { +"Canvas" }
|
||||||
|
vision("canvas") {
|
||||||
|
solid {
|
||||||
|
box(100, 100, 100)
|
||||||
|
material {
|
||||||
|
emissiveColor("red")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vision("plot") {
|
||||||
|
plotly {
|
||||||
|
scatter {
|
||||||
|
x(1, 2, 3, 4)
|
||||||
|
y(10, 15, 13, 17)
|
||||||
|
mode = ScatterMode.markers
|
||||||
|
name = "Team A"
|
||||||
|
text("A-1", "A-2", "A-3", "A-4", "A-5")
|
||||||
|
textposition = TextPosition.`top center`
|
||||||
|
textfont {
|
||||||
|
family = "Raleway, sans-serif"
|
||||||
|
}
|
||||||
|
marker { size = 12 }
|
||||||
|
}
|
||||||
|
|
||||||
|
scatter {
|
||||||
|
x(2, 3, 4, 5)
|
||||||
|
y(10, 15, 13, 17)
|
||||||
|
mode = ScatterMode.lines
|
||||||
|
name = "Team B"
|
||||||
|
text("B-a", "B-b", "B-c", "B-d", "B-e")
|
||||||
|
textposition = TextPosition.`bottom center`
|
||||||
|
textfont {
|
||||||
|
family = "Times New Roman"
|
||||||
|
}
|
||||||
|
marker { size = 12 }
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
title = "Data Labels Hover"
|
||||||
|
xaxis {
|
||||||
|
range(0.75..5.25)
|
||||||
|
}
|
||||||
|
legend {
|
||||||
|
y = 0.5
|
||||||
|
font {
|
||||||
|
family = "Arial, sans-serif"
|
||||||
|
size = 20
|
||||||
|
color("grey")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ public fun Context.makeVisionFile(
|
|||||||
content: VisionTagConsumer<*>.() -> Unit
|
content: VisionTagConsumer<*>.() -> Unit
|
||||||
): Unit {
|
): Unit {
|
||||||
val actualPath = page(title, content = content).makeFile(path) { actualPath ->
|
val actualPath = page(title, content = content).makeFile(path) { actualPath ->
|
||||||
mapOf("threeJs" to scriptHeader("js/visionforge-playground.js", resourceLocation, actualPath))
|
mapOf("playground" to scriptHeader("js/visionforge-playground.js", resourceLocation, actualPath))
|
||||||
}
|
}
|
||||||
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
|
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,7 @@ package space.kscience.visionforge.examples
|
|||||||
|
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.visionforge.html.ResourceLocation
|
import space.kscience.visionforge.html.ResourceLocation
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.box
|
|
||||||
import space.kscience.visionforge.solid.solid
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val context = Context {
|
val context = Context {
|
||||||
@ -15,6 +13,9 @@ fun main() {
|
|||||||
vision("canvas") {
|
vision("canvas") {
|
||||||
solid {
|
solid {
|
||||||
box(100, 100, 100)
|
box(100, 100, 100)
|
||||||
|
material {
|
||||||
|
emissiveColor("red")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.html.div
|
import kotlinx.html.div
|
||||||
import kotlinx.html.h1
|
import kotlinx.html.h1
|
||||||
import space.kscience.dataforge.context.Global
|
import space.kscience.dataforge.context.Global
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.three.server.*
|
import space.kscience.visionforge.three.server.*
|
||||||
import space.kscience.visionforge.visionManager
|
import space.kscience.visionforge.visionManager
|
||||||
@ -42,7 +42,7 @@ fun main() {
|
|||||||
val randomLayer = Random.nextInt(1, 11)
|
val randomLayer = Random.nextInt(1, 11)
|
||||||
val randomI = Random.nextInt(1, 4)
|
val randomI = Random.nextInt(1, 4)
|
||||||
val randomJ = Random.nextInt(1, 4)
|
val randomJ = Random.nextInt(1, 4)
|
||||||
val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName()
|
val target = Name.parse("layer[$randomLayer].segment[$randomI,$randomJ]")
|
||||||
val targetVision = sat[target] as Solid
|
val targetVision = sat[target] as Solid
|
||||||
targetVision.color("red")
|
targetVision.color("red")
|
||||||
delay(1000)
|
delay(1000)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge.solid.demo
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
|
||||||
public interface VisionLayout<in V: Vision> {
|
public interface VisionLayout<in V: Vision> {
|
||||||
public fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
|
public fun render(name: Name, vision: V, meta: Meta = Meta.EMPTY)
|
@ -6,9 +6,8 @@ import kotlinx.coroutines.isActive
|
|||||||
import kotlinx.coroutines.launch
|
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.toName
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.VisionLayout
|
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import space.kscience.visionforge.visible
|
import space.kscience.visionforge.visible
|
||||||
@ -23,7 +22,7 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
|
|||||||
"title" put title
|
"title" put title
|
||||||
}
|
}
|
||||||
val vision = SolidGroup(block)
|
val vision = SolidGroup(block)
|
||||||
render(name.toName(), vision)
|
render(Name.parse(name), vision)
|
||||||
}
|
}
|
||||||
|
|
||||||
val canvasOptions = Canvas3DOptions {
|
val canvasOptions = Canvas3DOptions {
|
||||||
|
@ -15,7 +15,6 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.VisionLayout
|
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
import space.kscience.visionforge.solid.three.ThreeCanvas
|
import space.kscience.visionforge.solid.three.ThreeCanvas
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
@ -7,7 +7,6 @@ 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.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.VisionLayout
|
|
||||||
import space.kscience.visionforge.solid.FX3DPlugin
|
import space.kscience.visionforge.solid.FX3DPlugin
|
||||||
import space.kscience.visionforge.solid.FXCanvas3D
|
import space.kscience.visionforge.solid.FXCanvas3D
|
||||||
import space.kscience.visionforge.solid.Solid
|
import space.kscience.visionforge.solid.Solid
|
||||||
|
@ -2,12 +2,14 @@ package space.kscience.visionforge.demo
|
|||||||
|
|
||||||
import javafx.geometry.Orientation
|
import javafx.geometry.Orientation
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.asConfig
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.node
|
||||||
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.visionforge.editor.ConfigEditor
|
import space.kscience.visionforge.editor.FXMetaModel
|
||||||
import space.kscience.visionforge.editor.FXMeta
|
|
||||||
import space.kscience.visionforge.editor.MetaViewer
|
import space.kscience.visionforge.editor.MetaViewer
|
||||||
|
import space.kscience.visionforge.editor.MutableMetaEditor
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ class MetaEditorDemoApp : App(MetaEditorDemo::class)
|
|||||||
|
|
||||||
class MetaEditorDemo : View("Meta editor demo") {
|
class MetaEditorDemo : View("Meta editor demo") {
|
||||||
|
|
||||||
val meta = Meta {
|
val meta = MutableMeta {
|
||||||
"aNode" put {
|
"aNode" put {
|
||||||
"innerNode" put {
|
"innerNode" put {
|
||||||
"innerValue" put true
|
"innerValue" put true
|
||||||
@ -23,18 +25,16 @@ class MetaEditorDemo : View("Meta editor demo") {
|
|||||||
"b" put 223
|
"b" put 223
|
||||||
"c" put "StringValue"
|
"c" put "StringValue"
|
||||||
}
|
}
|
||||||
}.asConfig()
|
}
|
||||||
|
|
||||||
val descriptor = NodeDescriptor {
|
val descriptor = MetaDescriptor {
|
||||||
node("aNode") {
|
node("aNode") {
|
||||||
info = "A root demo node"
|
info = "A root demo node"
|
||||||
value("b") {
|
value("b", ValueType.NUMBER) {
|
||||||
info = "b number value"
|
info = "b number value"
|
||||||
type(ValueType.NUMBER)
|
|
||||||
}
|
}
|
||||||
node("otherNode") {
|
node("otherNode") {
|
||||||
value("otherValue") {
|
value("otherValue", ValueType.BOOLEAN) {
|
||||||
type(ValueType.BOOLEAN)
|
|
||||||
default(false)
|
default(false)
|
||||||
info = "default value"
|
info = "default value"
|
||||||
}
|
}
|
||||||
@ -46,12 +46,13 @@ class MetaEditorDemo : View("Meta editor demo") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val rootNode = FXMeta.root(meta, descriptor)
|
private val rootNode = FXMetaModel.root(meta, descriptor)
|
||||||
|
|
||||||
override val root =
|
override val root = splitpane(
|
||||||
splitpane(Orientation.HORIZONTAL, MetaViewer(rootNode).root, ConfigEditor(
|
Orientation.HORIZONTAL,
|
||||||
rootNode
|
MetaViewer(rootNode as Meta).root,
|
||||||
).root)
|
MutableMetaEditor(rootNode as FXMetaModel<MutableMeta>).root
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
## Library design
|
## Library design
|
||||||
The central point of the library design is the `Vision` interface. The `Vision` stores an optional reference to its parent and is able to store a number of mutable or read-only properties. Each property is represented by its `Name`, and a `MetaItem` value-tree, both following DataForge library specification (discussed in the [Appendix](appendix.md)). The `Vision` objects are organized in a tree using `VisionGroup` as nodes. `VisionGroup` additionally to all `Vision` properties holds a `children` container that holds named references to its direct children `Vision`s. Thus, `Vision`s form a doubly linked tree (a parent stores references to all its children and children store a reference to the parent).
|
The central point of the library design is the `Vision` interface. The `Vision` stores an optional reference to its parent and is able to store a number of mutable or read-only properties. Each property is represented by its `Name`, and a `Meta` value-tree, both following DataForge library specification (discussed in the [Appendix](appendix.md)). The `Vision` objects are organized in a tree using `VisionGroup` as nodes. `VisionGroup` additionally to all `Vision` properties holds a `children` container that holds named references to its direct children `Vision`s. Thus, `Vision`s form a doubly linked tree (a parent stores references to all its children and children store a reference to the parent).
|
||||||
|
|
||||||
An important concept using in the VisionForge is the property layering mechanism. It means that if the property with a given name is not found in the `Vision` it is requested from, it could be requested from the parent `Vision`, form the style declaration, the prototype for the vision or any other place defined by the component author. For example, let's take a `color` attribute used in 3D visualization. When one draws a group of objects, he usually wants to make the color of all objects in the group to be defined by a single handle in the group common ancestor. So when the parent color changes, all children color must follow suite, but we also want to change children color individually without changing the parent. In this case two property layers are defined:
|
An important concept using in the VisionForge is the property layering mechanism. It means that if the property with a given name is not found in the `Vision` it is requested from, it could be requested from the parent `Vision`, form the style declaration, the prototype for the vision or any other place defined by the component author. For example, let's take a `color` attribute used in 3D visualization. When one draws a group of objects, he usually wants to make the color of all objects in the group to be defined by a single handle in the group common ancestor. So when the parent color changes, all children color must follow suite, but we also want to change children color individually without changing the parent. In this case two property layers are defined:
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
interface Vision{
|
interface Vision{
|
||||||
val parent: Vision?
|
val parent: Vision?
|
||||||
fun getProperty(name): MetaItem?
|
fun getProperty(name): Meta?
|
||||||
fun setProperty(name, value)
|
fun setProperty(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
|
|
||||||
val toolsVersion = "0.10.0"
|
val toolsVersion = "0.10.2"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://repo.kotlin.link")
|
maven("https://repo.kotlin.link")
|
||||||
|
@ -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("popper.js","1.16.1"))
|
implementation(npm("@popperjs/core","2.9.3"))
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ import org.w3c.files.BlobPropertyBag
|
|||||||
import react.*
|
import react.*
|
||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import react.dom.button
|
import react.dom.button
|
||||||
|
import space.kscience.dataforge.meta.descriptors.defaultNode
|
||||||
import space.kscience.dataforge.meta.withDefault
|
import space.kscience.dataforge.meta.withDefault
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.react.flexColumn
|
import space.kscience.visionforge.react.flexColumn
|
||||||
@ -43,7 +44,7 @@ public external interface CanvasControlsProps : RProps {
|
|||||||
public var vision: Vision?
|
public var vision: Vision?
|
||||||
}
|
}
|
||||||
|
|
||||||
public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
|
public val CanvasControls: FunctionComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
|
||||||
flexColumn {
|
flexColumn {
|
||||||
flexRow {
|
flexRow {
|
||||||
css {
|
css {
|
||||||
@ -66,7 +67,7 @@ public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functional
|
|||||||
}
|
}
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = props.canvasOptions,
|
ownProperties = props.canvasOptions,
|
||||||
allProperties = props.canvasOptions.withDefault(Canvas3DOptions.descriptor.defaultMeta),
|
allProperties = props.canvasOptions.meta.withDefault(Canvas3DOptions.descriptor.defaultNode),
|
||||||
descriptor = Canvas3DOptions.descriptor,
|
descriptor = Canvas3DOptions.descriptor,
|
||||||
expanded = false
|
expanded = false
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ public external class TabProps : RProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val Tab: FunctionalComponent<TabProps> = functionalComponent { props ->
|
public val Tab: FunctionComponent<TabProps> = functionalComponent { props ->
|
||||||
props.children()
|
props.children()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ public external class TabPaneProps : RProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val TabPane: FunctionalComponent<TabPaneProps> = functionalComponent("TabPane") { props ->
|
public val TabPane: FunctionComponent<TabPaneProps> = functionalComponent("TabPane") { props ->
|
||||||
var activeTab: String? by useState(props.activeTab)
|
var activeTab: String? by useState(props.activeTab)
|
||||||
|
|
||||||
val children: Array<out ReactElement?> = Children.map(props.children) {
|
val children: Array<out ReactElement?> = Children.map(props.children) {
|
||||||
|
@ -3,22 +3,25 @@ package space.kscience.visionforge.bootstrap
|
|||||||
import org.w3c.dom.Element
|
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.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.Vision
|
||||||
|
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,
|
||||||
descriptor: NodeDescriptor? = vision.descriptor,
|
descriptor: MetaDescriptor? = vision.descriptor,
|
||||||
key: Any? = null,
|
key: Any? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
card("Properties") {
|
card("Properties") {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.ownProperties,
|
ownProperties = vision.meta(false,false,false),
|
||||||
allProperties = vision.allProperties(),
|
allProperties = vision.meta(),
|
||||||
updateFlow = vision.propertyChanges,
|
updateFlow = vision.propertyChanges,
|
||||||
descriptor = descriptor,
|
descriptor = descriptor,
|
||||||
key = key
|
key = key
|
||||||
@ -47,7 +50,7 @@ public fun RBuilder.visionPropertyEditor(
|
|||||||
|
|
||||||
public fun Element.visionPropertyEditor(
|
public fun Element.visionPropertyEditor(
|
||||||
item: Vision,
|
item: Vision,
|
||||||
descriptor: NodeDescriptor? = item.descriptor,
|
descriptor: MetaDescriptor? = item.descriptor,
|
||||||
): Unit = render(this) {
|
): Unit = render(this) {
|
||||||
visionPropertyEditor(item, descriptor = descriptor)
|
visionPropertyEditor(item, descriptor = descriptor)
|
||||||
}
|
}
|
@ -8,12 +8,11 @@ import react.*
|
|||||||
import react.dom.a
|
import react.dom.a
|
||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaItemNode
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.MetaItemValue
|
import space.kscience.dataforge.meta.descriptors.defaultNode
|
||||||
import space.kscience.dataforge.meta.descriptors.ItemDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.isLeaf
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.dataforge.names.lastOrNull
|
import space.kscience.dataforge.names.lastOrNull
|
||||||
@ -41,18 +40,19 @@ public external interface MetaViewerProps : RProps {
|
|||||||
/**
|
/**
|
||||||
* Root descriptor
|
* Root descriptor
|
||||||
*/
|
*/
|
||||||
public var descriptor: NodeDescriptor?
|
public var descriptor: MetaDescriptor?
|
||||||
}
|
}
|
||||||
|
|
||||||
private val MetaViewerItem: FunctionalComponent<MetaViewerProps> = functionalComponent("MetaViewerItem") { props ->
|
private val MetaViewerItem: FunctionComponent<MetaViewerProps> = functionalComponent("MetaViewerItem") { props ->
|
||||||
metaViewerItem(props)
|
metaViewerItem(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
|
private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
|
||||||
var expanded: Boolean by useState { true }
|
var expanded: Boolean by useState { true }
|
||||||
val item = props.root[props.name]
|
val item = props.root[props.name]
|
||||||
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
|
val descriptorItem: MetaDescriptor? = props.descriptor?.get(props.name)
|
||||||
val actualItem = item ?: descriptorItem?.defaultValue
|
val actualValue = item?.value ?: descriptorItem?.defaultValue
|
||||||
|
val actualMeta = item ?: descriptorItem?.defaultNode
|
||||||
|
|
||||||
val token = props.name.lastOrNull()?.toString() ?: props.rootName ?: ""
|
val token = props.name.lastOrNull()?.toString() ?: props.rootName ?: ""
|
||||||
|
|
||||||
@ -60,90 +60,75 @@ private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
|
|||||||
expanded = !expanded
|
expanded = !expanded
|
||||||
}
|
}
|
||||||
|
|
||||||
when (actualItem) {
|
flexRow {
|
||||||
is MetaItemNode -> {
|
css {
|
||||||
flexRow {
|
alignItems = Align.center
|
||||||
|
}
|
||||||
|
if (actualMeta?.isLeaf == false) {
|
||||||
|
styledSpan {
|
||||||
css {
|
css {
|
||||||
alignItems = Align.center
|
+TreeStyles.treeCaret
|
||||||
}
|
if (expanded) {
|
||||||
styledSpan {
|
+TreeStyles.treeCaredDown
|
||||||
css {
|
|
||||||
+TreeStyles.treeCaret
|
|
||||||
if (expanded) {
|
|
||||||
+TreeStyles.treeCaredDown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attrs {
|
|
||||||
onClickFunction = expanderClick
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styledSpan {
|
attrs {
|
||||||
css {
|
onClickFunction = expanderClick
|
||||||
+TreeStyles.treeLabel
|
|
||||||
if (item == null) {
|
|
||||||
+TreeStyles.treeLabelInactive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (expanded) {
|
|
||||||
flexColumn {
|
|
||||||
css {
|
|
||||||
+TreeStyles.tree
|
|
||||||
}
|
|
||||||
val keys = buildSet {
|
|
||||||
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
|
|
||||||
add(NameToken(it))
|
|
||||||
}
|
|
||||||
actualItem.node.items.keys.let { addAll(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.filter { !it.body.startsWith("@") }.forEach { token ->
|
|
||||||
styledDiv {
|
|
||||||
css {
|
|
||||||
+TreeStyles.treeItem
|
|
||||||
}
|
|
||||||
child(MetaViewerItem) {
|
|
||||||
attrs {
|
|
||||||
this.key = props.name.toString()
|
|
||||||
this.root = props.root
|
|
||||||
this.name = props.name + token
|
|
||||||
this.descriptor = props.descriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is MetaItemValue -> {
|
|
||||||
flexRow {
|
styledSpan {
|
||||||
css {
|
css {
|
||||||
alignItems = Align.center
|
+TreeStyles.treeLabel
|
||||||
|
if (item == null) {
|
||||||
|
+TreeStyles.treeLabelInactive
|
||||||
}
|
}
|
||||||
styledSpan {
|
}
|
||||||
|
+token
|
||||||
|
}
|
||||||
|
styledDiv {
|
||||||
|
a {
|
||||||
|
+actualValue.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expanded) {
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
+TreeStyles.tree
|
||||||
|
}
|
||||||
|
val keys = buildSet {
|
||||||
|
descriptorItem?.children?.keys?.forEach {
|
||||||
|
add(NameToken(it))
|
||||||
|
}
|
||||||
|
actualMeta!!.items.keys.let { addAll(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.filter { !it.body.startsWith("@") }.forEach { token ->
|
||||||
|
styledDiv {
|
||||||
css {
|
css {
|
||||||
+TreeStyles.treeLabel
|
+TreeStyles.treeItem
|
||||||
if (item == null) {
|
}
|
||||||
+TreeStyles.treeLabelInactive
|
child(MetaViewerItem) {
|
||||||
|
attrs {
|
||||||
|
this.key = props.name.toString()
|
||||||
|
this.root = props.root
|
||||||
|
this.name = props.name + token
|
||||||
|
this.descriptor = props.descriptor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+token
|
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
||||||
}
|
|
||||||
styledDiv {
|
|
||||||
a {
|
|
||||||
+actualItem.value.toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val MetaViewer: FunctionalComponent<MetaViewerProps> =
|
public val MetaViewer: FunctionComponent<MetaViewerProps> =
|
||||||
functionalComponent<MetaViewerProps>("MetaViewer") { props ->
|
functionalComponent<MetaViewerProps>("MetaViewer") { props ->
|
||||||
child(MetaViewerItem) {
|
child(MetaViewerItem) {
|
||||||
attrs {
|
attrs {
|
||||||
@ -155,7 +140,7 @@ public val MetaViewer: FunctionalComponent<MetaViewerProps> =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun RBuilder.metaViewer(meta: Meta, descriptor: NodeDescriptor? = null, key: Any? = null) {
|
public fun RBuilder.metaViewer(meta: Meta, descriptor: MetaDescriptor? = null, key: Any? = null) {
|
||||||
child(MetaViewer) {
|
child(MetaViewer) {
|
||||||
attrs {
|
attrs {
|
||||||
this.key = key?.toString() ?: ""
|
this.key = key?.toString() ?: ""
|
||||||
|
@ -5,23 +5,23 @@ import org.w3c.dom.HTMLOptionElement
|
|||||||
import org.w3c.dom.HTMLSelectElement
|
import org.w3c.dom.HTMLSelectElement
|
||||||
import org.w3c.dom.asList
|
import org.w3c.dom.asList
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import react.FunctionalComponent
|
import react.FunctionComponent
|
||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import react.dom.option
|
import react.dom.option
|
||||||
import react.dom.select
|
import react.dom.select
|
||||||
import react.functionalComponent
|
import react.functionalComponent
|
||||||
import react.useState
|
import react.useState
|
||||||
import space.kscience.dataforge.meta.value
|
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.dataforge.values.string
|
import space.kscience.dataforge.values.string
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val MultiSelectChooser: FunctionalComponent<ValueChooserProps> =
|
public val MultiSelectChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("MultiSelectChooser") { props ->
|
functionalComponent("MultiSelectChooser") { props ->
|
||||||
var selectedItems by useState { props.item.value?.list ?: emptyList() }
|
var selectedItems by useState { props.item?.value?.list ?: emptyList() }
|
||||||
|
|
||||||
val onChange: (Event) -> Unit = { event: Event ->
|
val onChange: (Event) -> Unit = { event: Event ->
|
||||||
val newSelected= (event.target as HTMLSelectElement).selectedOptions.asList()
|
val newSelected = (event.target as HTMLSelectElement).selectedOptions.asList()
|
||||||
.map { (it as HTMLOptionElement).value.asValue() }
|
.map { (it as HTMLOptionElement).value.asValue() }
|
||||||
props.valueChanged?.invoke(newSelected.asValue())
|
props.valueChanged?.invoke(newSelected.asValue())
|
||||||
selectedItems = newSelected
|
selectedItems = newSelected
|
||||||
|
@ -18,14 +18,10 @@ import react.*
|
|||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import react.dom.render
|
import react.dom.render
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.ItemDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.ValueRequirement
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.dataforge.names.NameToken
|
|
||||||
import space.kscience.dataforge.names.lastOrNull
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.hidden
|
import space.kscience.visionforge.hidden
|
||||||
import styled.css
|
import styled.css
|
||||||
@ -38,12 +34,12 @@ public external interface PropertyEditorProps : RProps {
|
|||||||
/**
|
/**
|
||||||
* Root config object - always non null
|
* Root config object - always non null
|
||||||
*/
|
*/
|
||||||
public var ownProperties: MutableItemProvider
|
public var ownProperties: MutableMetaProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide default item (greyed out if used)
|
* Provide default item (greyed out if used)
|
||||||
*/
|
*/
|
||||||
public var allProperties: ItemProvider?
|
public var allProperties: MetaProvider?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full path to the displayed node in [ownProperties]. Could be empty
|
* Full path to the displayed node in [ownProperties]. Could be empty
|
||||||
@ -53,7 +49,7 @@ public external interface PropertyEditorProps : RProps {
|
|||||||
/**
|
/**
|
||||||
* Root descriptor
|
* Root descriptor
|
||||||
*/
|
*/
|
||||||
public var descriptor: NodeDescriptor?
|
public var descriptor: MetaDescriptor?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A coroutine scope for updates
|
* A coroutine scope for updates
|
||||||
@ -71,21 +67,21 @@ public external interface PropertyEditorProps : RProps {
|
|||||||
public var expanded: Boolean?
|
public var expanded: Boolean?
|
||||||
}
|
}
|
||||||
|
|
||||||
private val PropertyEditorItem: FunctionalComponent<PropertyEditorProps> =
|
private val PropertyEditorItem: FunctionComponent<PropertyEditorProps> =
|
||||||
functionalComponent("ConfigEditorItem") { props ->
|
functionalComponent("ConfigEditorItem") { props ->
|
||||||
propertyEditorItem(props)
|
propertyEditorItem(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||||
var expanded: Boolean by useState { props.expanded ?: true }
|
var expanded: Boolean by useState { props.expanded ?: true }
|
||||||
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
|
val descriptor: MetaDescriptor? = props.descriptor?.get(props.name)
|
||||||
var ownProperty: MetaItem? by useState { props.ownProperties.getItem(props.name) }
|
var ownProperty: Meta? by useState { props.ownProperties.getMeta(props.name) }
|
||||||
val actualItem: MetaItem? = props.allProperties?.getItem(props.name)
|
val actualMeta = props.allProperties?.getMeta(props.name)
|
||||||
|
|
||||||
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
||||||
|
|
||||||
fun update() {
|
fun update() {
|
||||||
ownProperty = props.ownProperties.getItem(props.name)
|
ownProperty = props.ownProperties.getMeta(props.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.updateFlow != null) {
|
if (props.updateFlow != null) {
|
||||||
@ -109,7 +105,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
if (it == null) {
|
if (it == null) {
|
||||||
props.ownProperties.remove(props.name)
|
props.ownProperties.remove(props.name)
|
||||||
} else {
|
} else {
|
||||||
props.ownProperties[props.name] = it
|
props.ownProperties.setValue(props.name, it)
|
||||||
}
|
}
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
@ -119,19 +115,20 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualItem is MetaItemNode) {
|
val keys = buildSet {
|
||||||
val keys = buildSet {
|
descriptor?.children?.filterNot {
|
||||||
(descriptorItem as? NodeDescriptor)?.items?.filterNot {
|
it.key.startsWith("@") || it.value.hidden
|
||||||
it.key.startsWith("@") || it.value.hidden
|
}?.forEach {
|
||||||
}?.forEach {
|
add(NameToken(it.key))
|
||||||
add(NameToken(it.key))
|
|
||||||
}
|
|
||||||
ownProperty?.node?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) }
|
|
||||||
}
|
}
|
||||||
// Do not show nodes without visible children
|
ownProperty?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) }
|
||||||
if (keys.isEmpty()) return
|
}
|
||||||
|
|
||||||
flexRow {
|
flexRow {
|
||||||
|
css {
|
||||||
|
alignItems = Align.center
|
||||||
|
}
|
||||||
|
if(keys.isNotEmpty()) {
|
||||||
styledSpan {
|
styledSpan {
|
||||||
css {
|
css {
|
||||||
+TreeStyles.treeCaret
|
+TreeStyles.treeCaret
|
||||||
@ -143,55 +140,17 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
onClickFunction = expanderClick
|
onClickFunction = expanderClick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styledSpan {
|
|
||||||
css {
|
|
||||||
+TreeStyles.treeLabel
|
|
||||||
if (ownProperty == null) {
|
|
||||||
+TreeStyles.treeLabelInactive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+token
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (expanded) {
|
styledSpan {
|
||||||
flexColumn {
|
|
||||||
css {
|
|
||||||
+TreeStyles.tree
|
|
||||||
}
|
|
||||||
keys.forEach { token ->
|
|
||||||
styledDiv {
|
|
||||||
css {
|
|
||||||
+TreeStyles.treeItem
|
|
||||||
}
|
|
||||||
child(PropertyEditorItem) {
|
|
||||||
attrs {
|
|
||||||
this.key = props.name.toString()
|
|
||||||
this.ownProperties = props.ownProperties
|
|
||||||
this.allProperties = props.allProperties
|
|
||||||
this.name = props.name + token
|
|
||||||
this.descriptor = props.descriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flexRow {
|
|
||||||
css {
|
css {
|
||||||
alignItems = Align.center
|
+TreeStyles.treeLabel
|
||||||
}
|
if (ownProperty == null) {
|
||||||
styledSpan {
|
+TreeStyles.treeLabelInactive
|
||||||
css {
|
|
||||||
+TreeStyles.treeLabel
|
|
||||||
if (ownProperty == null) {
|
|
||||||
+TreeStyles.treeLabelInactive
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+token
|
|
||||||
}
|
}
|
||||||
|
+token
|
||||||
|
}
|
||||||
|
if(!props.name.isEmpty() && descriptor?.valueRequirement != ValueRequirement.ABSENT) {
|
||||||
styledDiv {
|
styledDiv {
|
||||||
css {
|
css {
|
||||||
//+TreeStyles.resizeableInput
|
//+TreeStyles.resizeableInput
|
||||||
@ -200,8 +159,8 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
}
|
}
|
||||||
valueChooser(
|
valueChooser(
|
||||||
props.name,
|
props.name,
|
||||||
actualItem,
|
actualMeta,
|
||||||
descriptorItem as? ValueDescriptor,
|
descriptor,
|
||||||
valueChanged
|
valueChanged
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -232,14 +191,38 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (expanded) {
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
+TreeStyles.tree
|
||||||
|
}
|
||||||
|
keys.forEach { token ->
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeItem
|
||||||
|
}
|
||||||
|
child(PropertyEditorItem) {
|
||||||
|
attrs {
|
||||||
|
this.key = props.name.toString()
|
||||||
|
this.ownProperties = props.ownProperties
|
||||||
|
this.allProperties = props.allProperties
|
||||||
|
this.name = props.name + token
|
||||||
|
this.descriptor = props.descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functionalComponent("PropertyEditor") { props ->
|
public val PropertyEditor: FunctionComponent<PropertyEditorProps> = functionalComponent("PropertyEditor") { props ->
|
||||||
child(PropertyEditorItem) {
|
child(PropertyEditorItem) {
|
||||||
attrs {
|
attrs {
|
||||||
this.key = ""
|
this.key = ""
|
||||||
@ -254,10 +237,10 @@ public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functional
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun RBuilder.propertyEditor(
|
public fun RBuilder.propertyEditor(
|
||||||
ownProperties: MutableItemProvider,
|
ownProperties: MutableMetaProvider,
|
||||||
allProperties: ItemProvider? = ownProperties,
|
allProperties: MetaProvider? = ownProperties,
|
||||||
updateFlow: Flow<Name>? = null,
|
updateFlow: Flow<Name>? = null,
|
||||||
descriptor: NodeDescriptor? = null,
|
descriptor: MetaDescriptor? = null,
|
||||||
scope: CoroutineScope? = null,
|
scope: CoroutineScope? = null,
|
||||||
key: Any? = null,
|
key: Any? = null,
|
||||||
expanded: Boolean? = null
|
expanded: Boolean? = null
|
||||||
@ -276,8 +259,8 @@ public fun RBuilder.propertyEditor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
private fun Config.flowUpdates(): Flow<Name> = callbackFlow {
|
private fun ObservableMutableMeta.flowUpdates(): Flow<Name> = callbackFlow {
|
||||||
onChange(this) { name, _, _ ->
|
onChange(this) { name ->
|
||||||
launch {
|
launch {
|
||||||
send(name)
|
send(name)
|
||||||
}
|
}
|
||||||
@ -289,16 +272,16 @@ private fun Config.flowUpdates(): Flow<Name> = callbackFlow {
|
|||||||
|
|
||||||
|
|
||||||
public fun RBuilder.configEditor(
|
public fun RBuilder.configEditor(
|
||||||
config: Config,
|
config: ObservableMutableMeta,
|
||||||
default: ItemProvider? = null,
|
default: MetaProvider? = null,
|
||||||
descriptor: NodeDescriptor? = null,
|
descriptor: MetaDescriptor? = null,
|
||||||
key: Any? = null,
|
key: Any? = null,
|
||||||
scope: CoroutineScope? = null,
|
scope: CoroutineScope? = null,
|
||||||
): Unit = propertyEditor(config, default, config.flowUpdates(), descriptor, scope, key = key)
|
): Unit = propertyEditor(config, default, config.flowUpdates(), descriptor, scope, key = key)
|
||||||
|
|
||||||
public fun Element.configEditor(
|
public fun Element.configEditor(
|
||||||
config: Config,
|
config: ObservableMutableMeta,
|
||||||
descriptor: NodeDescriptor? = null,
|
descriptor: MetaDescriptor? = null,
|
||||||
default: Meta? = null,
|
default: Meta? = null,
|
||||||
key: Any? = null,
|
key: Any? = null,
|
||||||
scope: CoroutineScope? = null,
|
scope: CoroutineScope? = null,
|
||||||
|
@ -6,7 +6,7 @@ import kotlinx.html.InputType
|
|||||||
import kotlinx.html.js.onChangeFunction
|
import kotlinx.html.js.onChangeFunction
|
||||||
import org.w3c.dom.HTMLInputElement
|
import org.w3c.dom.HTMLInputElement
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import react.FunctionalComponent
|
import react.FunctionComponent
|
||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import react.functionalComponent
|
import react.functionalComponent
|
||||||
import react.useState
|
import react.useState
|
||||||
@ -18,7 +18,7 @@ import styled.css
|
|||||||
import styled.styledInput
|
import styled.styledInput
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val RangeValueChooser: FunctionalComponent<ValueChooserProps> =
|
public val RangeValueChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("RangeValueChooser") { props ->
|
functionalComponent("RangeValueChooser") { props ->
|
||||||
var innerValue by useState(props.item.double)
|
var innerValue by useState(props.item.double)
|
||||||
var rangeDisabled: Boolean by useState(props.item == null)
|
var rangeDisabled: Boolean by useState(props.item == null)
|
||||||
|
@ -21,7 +21,7 @@ public external interface ThreeCanvasProps : RProps {
|
|||||||
public var selected: Name?
|
public var selected: Name?
|
||||||
}
|
}
|
||||||
|
|
||||||
public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functionalComponent(
|
public val ThreeCanvasComponent: FunctionComponent<ThreeCanvasProps> = functionalComponent(
|
||||||
"ThreeCanvasComponent"
|
"ThreeCanvasComponent"
|
||||||
) { props ->
|
) { props ->
|
||||||
val elementRef = useRef<Element>(null)
|
val elementRef = useRef<Element>(null)
|
||||||
|
@ -107,7 +107,7 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ObjectTree: FunctionalComponent<ObjectTreeProps> = functionalComponent("ObjectTree") { props ->
|
public val ObjectTree: FunctionComponent<ObjectTreeProps> = functionalComponent("ObjectTree") { props ->
|
||||||
visionTree(props)
|
visionTree(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,12 @@ import org.w3c.dom.events.Event
|
|||||||
import react.*
|
import react.*
|
||||||
import react.dom.attrs
|
import react.dom.attrs
|
||||||
import react.dom.option
|
import react.dom.option
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
import space.kscience.dataforge.meta.boolean
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.*
|
import space.kscience.dataforge.values.*
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
@ -24,14 +28,15 @@ import styled.styledInput
|
|||||||
import styled.styledSelect
|
import styled.styledSelect
|
||||||
|
|
||||||
public external interface ValueChooserProps : RProps {
|
public external interface ValueChooserProps : RProps {
|
||||||
public var item: MetaItem?
|
public var item: Meta?
|
||||||
public var descriptor: ValueDescriptor?
|
public var descriptor: MetaDescriptor?
|
||||||
|
|
||||||
//public var nullable: Boolean?
|
//public var nullable: Boolean?
|
||||||
public var valueChanged: ((Value?) -> Unit)?
|
public var valueChanged: ((Value?) -> Unit)?
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val StringValueChooser: FunctionalComponent<ValueChooserProps> =
|
public val StringValueChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("StringValueChooser") { props ->
|
functionalComponent("StringValueChooser") { props ->
|
||||||
var value by useState(props.item.string ?: "")
|
var value by useState(props.item.string ?: "")
|
||||||
val keyDown: (Event) -> Unit = { event ->
|
val keyDown: (Event) -> Unit = { event ->
|
||||||
@ -46,7 +51,7 @@ public val StringValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
value = (it.target as HTMLInputElement).value
|
value = (it.target as HTMLInputElement).value
|
||||||
}
|
}
|
||||||
styledInput(type = InputType.text) {
|
styledInput(type = InputType.text) {
|
||||||
css{
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
}
|
}
|
||||||
attrs {
|
attrs {
|
||||||
@ -58,14 +63,14 @@ public val StringValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val BooleanValueChooser: FunctionalComponent<ValueChooserProps> =
|
public val BooleanValueChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("BooleanValueChooser") { props ->
|
functionalComponent("BooleanValueChooser") { props ->
|
||||||
val handleChange: (Event) -> Unit = {
|
val handleChange: (Event) -> Unit = {
|
||||||
val newValue = (it.target as HTMLInputElement).checked
|
val newValue = (it.target as HTMLInputElement).checked
|
||||||
props.valueChanged?.invoke(newValue.asValue())
|
props.valueChanged?.invoke(newValue.asValue())
|
||||||
}
|
}
|
||||||
styledInput(type = InputType.checkBox) {
|
styledInput(type = InputType.checkBox) {
|
||||||
css{
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
}
|
}
|
||||||
attrs {
|
attrs {
|
||||||
@ -77,7 +82,7 @@ public val BooleanValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val NumberValueChooser: FunctionalComponent<ValueChooserProps> =
|
public val NumberValueChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("NumberValueChooser") { props ->
|
functionalComponent("NumberValueChooser") { props ->
|
||||||
var innerValue by useState(props.item.string ?: "")
|
var innerValue by useState(props.item.string ?: "")
|
||||||
val keyDown: (Event) -> Unit = { event ->
|
val keyDown: (Event) -> Unit = { event ->
|
||||||
@ -95,7 +100,7 @@ public val NumberValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
innerValue = (it.target as HTMLInputElement).value
|
innerValue = (it.target as HTMLInputElement).value
|
||||||
}
|
}
|
||||||
styledInput(type = InputType.number) {
|
styledInput(type = InputType.number) {
|
||||||
css{
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
}
|
}
|
||||||
attrs {
|
attrs {
|
||||||
@ -116,7 +121,7 @@ public val NumberValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ComboValueChooser: FunctionalComponent<ValueChooserProps> =
|
public val ComboValueChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("ComboValueChooser") { props ->
|
functionalComponent("ComboValueChooser") { props ->
|
||||||
var selected by useState(props.item.string ?: "")
|
var selected by useState(props.item.string ?: "")
|
||||||
val handleChange: (Event) -> Unit = {
|
val handleChange: (Event) -> Unit = {
|
||||||
@ -124,7 +129,7 @@ public val ComboValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
props.valueChanged?.invoke(selected.asValue())
|
props.valueChanged?.invoke(selected.asValue())
|
||||||
}
|
}
|
||||||
styledSelect {
|
styledSelect {
|
||||||
css{
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
}
|
}
|
||||||
props.descriptor?.allowedValues?.forEach {
|
props.descriptor?.allowedValues?.forEach {
|
||||||
@ -141,10 +146,10 @@ public val ComboValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ColorValueChooser: FunctionalComponent<ValueChooserProps> =
|
public val ColorValueChooser: FunctionComponent<ValueChooserProps> =
|
||||||
functionalComponent("ColorValueChooser") { props ->
|
functionalComponent("ColorValueChooser") { props ->
|
||||||
var value by useState(
|
var value by useState(
|
||||||
props.item.value?.let { value ->
|
props.item?.value?.let { value ->
|
||||||
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
||||||
else value.string
|
else value.string
|
||||||
} ?: "#000000"
|
} ?: "#000000"
|
||||||
@ -154,7 +159,7 @@ public val ColorValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
props.valueChanged?.invoke(value.asValue())
|
props.valueChanged?.invoke(value.asValue())
|
||||||
}
|
}
|
||||||
styledInput(type = InputType.color) {
|
styledInput(type = InputType.color) {
|
||||||
css{
|
css {
|
||||||
width = 100.pct
|
width = 100.pct
|
||||||
margin(0.px)
|
margin(0.px)
|
||||||
}
|
}
|
||||||
@ -166,11 +171,11 @@ public val ColorValueChooser: FunctionalComponent<ValueChooserProps> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ValueChooser: FunctionalComponent<ValueChooserProps> = functionalComponent("ValueChooser") { props ->
|
public val ValueChooser: FunctionComponent<ValueChooserProps> = functionalComponent("ValueChooser") { props ->
|
||||||
val rawInput by useState(false)
|
val rawInput by useState(false)
|
||||||
|
|
||||||
val descriptor = props.descriptor
|
val descriptor = props.descriptor
|
||||||
val type = descriptor?.type?.firstOrNull()
|
val type = descriptor?.valueTypes?.firstOrNull()
|
||||||
|
|
||||||
when {
|
when {
|
||||||
rawInput -> child(StringValueChooser, props)
|
rawInput -> child(StringValueChooser, props)
|
||||||
@ -187,8 +192,8 @@ public val ValueChooser: FunctionalComponent<ValueChooserProps> = functionalComp
|
|||||||
|
|
||||||
internal fun RBuilder.valueChooser(
|
internal fun RBuilder.valueChooser(
|
||||||
name: Name,
|
name: Name,
|
||||||
item: MetaItem?,
|
item: Meta?,
|
||||||
descriptor: ValueDescriptor? = null,
|
descriptor: MetaDescriptor? = null,
|
||||||
callback: (Value?) -> Unit,
|
callback: (Value?) -> Unit,
|
||||||
) {
|
) {
|
||||||
child(ValueChooser) {
|
child(ValueChooser) {
|
||||||
|
@ -17,14 +17,13 @@ kotlin{
|
|||||||
|
|
||||||
dependencies{
|
dependencies{
|
||||||
api(project(":ui:react"))
|
api(project(":ui:react"))
|
||||||
//TODO replace by kotlin-wrappers
|
//api("ru.mipt.npm:ring-ui:0.1.0")
|
||||||
api("ru.mipt.npm:ring-ui:0.1.0")
|
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
|
||||||
|
|
||||||
implementation(npm("@jetbrains/icons", "3.14.1"))
|
implementation(npm("@jetbrains/icons", "3.14.1"))
|
||||||
implementation(npm("@jetbrains/ring-ui", "4.0.7"))
|
implementation(npm("@jetbrains/ring-ui", "4.0.7"))
|
||||||
implementation(npm("core-js","3.12.1"))
|
implementation(npm("core-js","3.12.1"))
|
||||||
implementation(npm("file-saver", "2.0.2"))
|
implementation(npm("file-saver", "2.0.2"))
|
||||||
compileOnly(npm("url-loader","4.1.1"))
|
// compileOnly(npm("url-loader","4.1.1"))
|
||||||
compileOnly(npm("postcss-loader","5.2.0"))
|
// compileOnly(npm("postcss-loader","5.2.0"))
|
||||||
compileOnly(npm("source-map-loader","2.0.1"))
|
|
||||||
}
|
}
|
@ -14,8 +14,7 @@ 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.allProperties
|
import space.kscience.visionforge.meta
|
||||||
import space.kscience.visionforge.ownProperties
|
|
||||||
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
|
||||||
@ -70,7 +69,7 @@ public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): ReactElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ThreeCanvasWithControls: FunctionalComponent<ThreeCanvasWithControlsProps> =
|
public val ThreeCanvasWithControls: FunctionComponent<ThreeCanvasWithControlsProps> =
|
||||||
functionalComponent("ThreeViewWithControls") { props ->
|
functionalComponent("ThreeViewWithControls") { props ->
|
||||||
var selected by useState { props.selected }
|
var selected by useState { props.selected }
|
||||||
|
|
||||||
@ -120,23 +119,23 @@ public val ThreeCanvasWithControls: FunctionalComponent<ThreeCanvasWithControlsP
|
|||||||
|
|
||||||
selectedVision?.let { vision ->
|
selectedVision?.let { vision ->
|
||||||
styledDiv {
|
styledDiv {
|
||||||
css{
|
css {
|
||||||
position = Position.absolute
|
position = Position.absolute
|
||||||
top = 5.px
|
top = 5.px
|
||||||
right = 5.px
|
right = 5.px
|
||||||
width = 450.px
|
width = 450.px
|
||||||
}
|
}
|
||||||
Island{
|
Island {
|
||||||
IslandHeader{
|
IslandHeader {
|
||||||
attrs {
|
attrs {
|
||||||
border = true
|
border = true
|
||||||
}
|
}
|
||||||
nameCrumbs(selected) { selected = it }
|
nameCrumbs(selected) { selected = it }
|
||||||
}
|
}
|
||||||
IslandContent{
|
IslandContent {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.ownProperties,
|
ownProperties = vision.meta(false, false, false),
|
||||||
allProperties = vision.allProperties(),
|
allProperties = vision.meta(),
|
||||||
updateFlow = vision.propertyChanges,
|
updateFlow = vision.propertyChanges,
|
||||||
descriptor = vision.descriptor,
|
descriptor = vision.descriptor,
|
||||||
key = selected
|
key = selected
|
||||||
|
@ -7,16 +7,19 @@ import react.dom.render
|
|||||||
import ringui.Island
|
import ringui.Island
|
||||||
import ringui.SmartTabs
|
import ringui.SmartTabs
|
||||||
import ringui.Tab
|
import ringui.Tab
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.Vision
|
||||||
|
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,
|
||||||
descriptor: NodeDescriptor? = vision.descriptor,
|
descriptor: MetaDescriptor? = vision.descriptor,
|
||||||
key: Any? = null,
|
key: Any? = null,
|
||||||
) {
|
) {
|
||||||
val styles = if (vision is SolidReference) {
|
val styles = if (vision is SolidReference) {
|
||||||
@ -28,8 +31,8 @@ public fun RBuilder.ringPropertyEditor(
|
|||||||
flexColumn {
|
flexColumn {
|
||||||
Island("Properties") {
|
Island("Properties") {
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = vision.ownProperties,
|
ownProperties = vision.meta(false,false,false),
|
||||||
allProperties = vision.allProperties(),
|
allProperties = vision.meta(),
|
||||||
updateFlow = vision.propertyChanges,
|
updateFlow = vision.propertyChanges,
|
||||||
descriptor = descriptor,
|
descriptor = descriptor,
|
||||||
key = key
|
key = key
|
||||||
@ -69,7 +72,7 @@ public fun RBuilder.ringPropertyEditor(
|
|||||||
|
|
||||||
public fun Element.ringPropertyEditor(
|
public fun Element.ringPropertyEditor(
|
||||||
item: Vision,
|
item: Vision,
|
||||||
descriptor: NodeDescriptor? = item.descriptor,
|
descriptor: MetaDescriptor? = item.descriptor,
|
||||||
): Unit = render(this) {
|
): Unit = render(this) {
|
||||||
ringPropertyEditor(item, descriptor = descriptor)
|
ringPropertyEditor(item, descriptor = descriptor)
|
||||||
}
|
}
|
@ -15,6 +15,7 @@ import react.dom.button
|
|||||||
import ringui.Island
|
import ringui.Island
|
||||||
import ringui.SmartTabs
|
import ringui.SmartTabs
|
||||||
import ringui.Tab
|
import ringui.Tab
|
||||||
|
import space.kscience.dataforge.meta.descriptors.defaultNode
|
||||||
import space.kscience.dataforge.meta.withDefault
|
import space.kscience.dataforge.meta.withDefault
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
@ -49,7 +50,7 @@ internal external interface CanvasControlsProps : RProps {
|
|||||||
public var vision: Vision?
|
public var vision: Vision?
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
|
internal val CanvasControls: FunctionComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
|
||||||
flexColumn {
|
flexColumn {
|
||||||
flexRow {
|
flexRow {
|
||||||
css {
|
css {
|
||||||
@ -73,7 +74,7 @@ internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = function
|
|||||||
}
|
}
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = props.options,
|
ownProperties = props.options,
|
||||||
allProperties = props.options.withDefault(Canvas3DOptions.descriptor.defaultMeta),
|
allProperties = props.options.meta.withDefault(Canvas3DOptions.descriptor.defaultNode),
|
||||||
descriptor = Canvas3DOptions.descriptor,
|
descriptor = Canvas3DOptions.descriptor,
|
||||||
expanded = false
|
expanded = false
|
||||||
)
|
)
|
||||||
@ -91,7 +92,7 @@ public external interface ThreeControlsProps : RProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props ->
|
public val ThreeControls: FunctionComponent<ThreeControlsProps> = functionalComponent { props ->
|
||||||
SmartTabs("Tree") {
|
SmartTabs("Tree") {
|
||||||
props.vision?.let {
|
props.vision?.let {
|
||||||
Tab("Tree") {
|
Tab("Tree") {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.number
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.dataforge.values.int
|
import space.kscience.dataforge.values.int
|
||||||
import space.kscience.dataforge.values.string
|
import space.kscience.dataforge.values.string
|
||||||
@ -190,25 +192,18 @@ public object Colors {
|
|||||||
/**
|
/**
|
||||||
* Convert color represented as Meta to string of format #rrggbb
|
* Convert color represented as Meta to string of format #rrggbb
|
||||||
*/
|
*/
|
||||||
fun fromMeta(item: MetaItem): String {
|
fun fromMeta(meta: Meta): String = meta.value?.let { value ->
|
||||||
return when (item) {
|
//if value is present, use it
|
||||||
is MetaItemNode -> {
|
if (value.type == ValueType.NUMBER) {
|
||||||
val node = item.node
|
rgbToString(value.int)
|
||||||
rgbToString(
|
} else {
|
||||||
node[RED_KEY].number?.toByte()?.toUByte() ?: 0u,
|
value.string
|
||||||
node[GREEN_KEY].number?.toByte()?.toUByte() ?: 0u,
|
|
||||||
node[BLUE_KEY].number?.toByte()?.toUByte() ?: 0u
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is MetaItemValue -> {
|
|
||||||
if (item.value.type == ValueType.NUMBER) {
|
|
||||||
rgbToString(item.value.int)
|
|
||||||
} else {
|
|
||||||
item.value.string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} ?: rgbToString(
|
||||||
|
meta[RED_KEY].number?.toByte()?.toUByte() ?: 0u,
|
||||||
|
meta[GREEN_KEY].number?.toByte()?.toUByte() ?: 0u,
|
||||||
|
meta[BLUE_KEY].number?.toByte()?.toUByte() ?: 0u
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Int color to string of format #rrggbb
|
* Convert Int color to string of format #rrggbb
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaBuilder
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.Scheme
|
import space.kscience.dataforge.meta.Scheme
|
||||||
import space.kscience.dataforge.meta.Specification
|
import space.kscience.dataforge.meta.Specification
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
@ -27,7 +27,7 @@ public fun Vision.useStyle(reference: StyleReference) {
|
|||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun VisionGroup.style(
|
public fun VisionGroup.style(
|
||||||
styleKey: String? = null,
|
styleKey: String? = null,
|
||||||
builder: MetaBuilder.() -> Unit,
|
builder: MutableMeta.() -> Unit,
|
||||||
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
): ReadOnlyProperty<Any?, StyleReference> = ReadOnlyProperty { _, property ->
|
||||||
val styleName = styleKey ?: property.name
|
val styleName = styleKey ?: property.name
|
||||||
styleSheet.define(styleName, Meta(builder))
|
styleSheet.define(styleName, Meta(builder))
|
||||||
|
@ -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.asValue
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,9 +14,9 @@ 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 get() = owner.ownProperties[STYLESHEET_KEY].node
|
private val styleNode: Meta? get() = owner.getOwnProperty(STYLESHEET_KEY)
|
||||||
|
|
||||||
public val items: Map<NameToken, Meta>? get() = styleNode?.items?.mapValues { it.value.node ?: Meta.EMPTY }
|
public val items: Map<NameToken, Meta>? get() = styleNode?.items
|
||||||
|
|
||||||
public operator fun get(key: String): Meta? = owner.getStyle(key)
|
public operator fun get(key: String): Meta? = owner.getStyle(key)
|
||||||
|
|
||||||
@ -23,7 +24,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.setProperty(STYLESHEET_KEY + key, style)
|
owner.setPropertyNode(STYLESHEET_KEY + key, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,7 +41,7 @@ public value class StyleSheet(private val owner: VisionGroup) {
|
|||||||
/**
|
/**
|
||||||
* Create and set a style
|
* Create and set a style
|
||||||
*/
|
*/
|
||||||
public operator fun set(key: String, builder: MetaBuilder.() -> Unit) {
|
public operator fun set(key: String, builder: MutableMeta.() -> Unit) {
|
||||||
val newStyle = get(key)?.toMutableMeta()?.apply(builder) ?: Meta(builder)
|
val newStyle = get(key)?.toMutableMeta()?.apply(builder) ?: Meta(builder)
|
||||||
set(key, newStyle.seal())
|
set(key, newStyle.seal())
|
||||||
}
|
}
|
||||||
@ -70,9 +71,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() = ownProperties[Vision.STYLE_KEY]?.stringList ?: emptyList()
|
get() = getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(Vision.STYLE_KEY, value)
|
setPropertyValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,7 +86,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 = (ownProperties[Vision.STYLE_KEY]?.stringList ?: emptyList()) + name
|
styles = (getOwnProperty(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -93,13 +94,13 @@ 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? =
|
||||||
ownProperties[StyleSheet.STYLESHEET_KEY + name].node ?: parent?.getStyle(name)
|
getOwnProperty(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve an item in all style layers
|
* Resolve an item in all style layers
|
||||||
*/
|
*/
|
||||||
public fun Vision.getStyleItems(name: Name): List<MetaItem> = styles.mapNotNull {
|
public fun Vision.getStyleItems(name: Name): List<Meta> = styles.mapNotNull {
|
||||||
getStyle(it)[name]
|
getStyle(it)?.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,14 +4,15 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.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.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
import space.kscience.dataforge.meta.update
|
||||||
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.names.toName
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.Vision.Companion.TYPE
|
import space.kscience.visionforge.Vision.Companion.TYPE
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
@ -45,13 +46,13 @@ public interface Vision : Described, CoroutineScope {
|
|||||||
inherit: Boolean = false,
|
inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): MetaItem?
|
): Meta?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an intrinsic property of this Vision excluding any inheritance or defaults. In most cases should be the same as
|
* 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`.
|
* `getProperty(name, false, false, false`.
|
||||||
*/
|
*/
|
||||||
public fun getOwnProperty(name: Name): MetaItem? = getProperty(
|
public fun getOwnProperty(name: Name): Meta? = getProperty(
|
||||||
name,
|
name,
|
||||||
inherit = false,
|
inherit = false,
|
||||||
includeStyles = false,
|
includeStyles = false,
|
||||||
@ -59,9 +60,14 @@ public interface Vision : Described, CoroutineScope {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the property value
|
* Replace the property node. If [node] is null remove node and its descendants
|
||||||
*/
|
*/
|
||||||
public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true)
|
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
|
* Flow of property invalidation events. It does not contain property values after invalidation since it is not clear
|
||||||
@ -77,9 +83,9 @@ 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 update(change: VisionChange)
|
public fun change(change: VisionChange)
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor?
|
override val descriptor: MetaDescriptor?
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public const val TYPE: String = "vision"
|
public const val TYPE: String = "vision"
|
||||||
@ -89,11 +95,6 @@ public interface Vision : Described, CoroutineScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Root property node
|
|
||||||
*/
|
|
||||||
public val Vision.meta: Meta get() = ownProperties[Name.EMPTY]?.node ?: Meta.EMPTY
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
|
* Subscribe on property updates. The subscription is bound to the given [scope] and canceled when the scope is canceled
|
||||||
*/
|
*/
|
||||||
@ -105,31 +106,26 @@ public fun Vision.onPropertyChange(scope: CoroutineScope, callback: suspend (Nam
|
|||||||
/**
|
/**
|
||||||
* Own properties, excluding inheritance, styles and descriptor
|
* Own properties, excluding inheritance, styles and descriptor
|
||||||
*/
|
*/
|
||||||
public val Vision.ownProperties: MutableItemProvider
|
public fun Vision.meta(
|
||||||
get() = object : MutableItemProvider {
|
inherit: Boolean = false,
|
||||||
override fun getItem(name: Name): MetaItem? = getOwnProperty(name)
|
includeStyles: Boolean = true,
|
||||||
override fun setItem(name: Name, item: MetaItem?): Unit = setProperty(name, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenient accessor for all properties of a vision.
|
|
||||||
* @param inherit - inherit property value from the parent by default. If null, inheritance is inferred from descriptor
|
|
||||||
*/
|
|
||||||
public fun Vision.allProperties(
|
|
||||||
inherit: Boolean? = null,
|
|
||||||
includeStyles: Boolean? = null,
|
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): MutableItemProvider = object : MutableItemProvider {
|
): MutableMeta = VisionProperties(this, Name.EMPTY, inherit, includeStyles, includeDefaults)
|
||||||
override fun getItem(name: Name): MetaItem? = getProperty(
|
|
||||||
name,
|
|
||||||
inherit = inherit ?: (descriptor?.get(name)?.inherited == true),
|
|
||||||
includeStyles = includeStyles ?: (descriptor?.get(name)?.usesStyles != false),
|
|
||||||
includeDefaults = includeDefaults
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun setItem(name: Name, item: MetaItem?): Unit = setProperty(name, item)
|
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
|
||||||
*/
|
*/
|
||||||
@ -138,18 +134,20 @@ public fun Vision.getProperty(
|
|||||||
inherit: Boolean = false,
|
inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): MetaItem? = getProperty(key.toName(), inherit, includeStyles, includeDefaults)
|
): Meta? = getProperty(Name.parse(key), inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to pair [getProperty]
|
* A convenience method to set property node or value. If Item is null, then node is removed, not a value
|
||||||
*/
|
*/
|
||||||
public fun Vision.setProperty(key: Name, item: Any?) {
|
public fun Vision.setProperty(name: Name, item: Any?) {
|
||||||
setProperty(key, MetaItem.of(item))
|
when (item) {
|
||||||
|
null -> setPropertyNode(name, null)
|
||||||
|
is Meta -> setPropertyNode(name, item)
|
||||||
|
is Value -> setPropertyValue(name, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public fun Vision.setPropertyNode(key: String, item: Any?) {
|
||||||
* A convenience method to pair [getProperty]
|
setProperty(Name.parse(key), item)
|
||||||
*/
|
|
||||||
public fun Vision.setProperty(key: String, item: Any?) {
|
|
||||||
setProperty(key.toName(), MetaItem.of(item))
|
|
||||||
}
|
}
|
||||||
|
@ -7,21 +7,18 @@ 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.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.defaultNode
|
||||||
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
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.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.Null
|
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 PropertyListener(
|
|
||||||
val owner: Any? = null,
|
|
||||||
val action: (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
|
||||||
@ -29,14 +26,17 @@ internal data class PropertyListener(
|
|||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("vision")
|
@SerialName("vision")
|
||||||
public open class VisionBase(
|
public open class VisionBase(
|
||||||
override @Transient var parent: VisionGroup? = null,
|
@Transient override var parent: VisionGroup? = null,
|
||||||
protected var properties: MutableItemProvider? = null
|
@Serializable(MutableMetaSerializer::class)
|
||||||
|
protected var properties: MutableMeta? = null
|
||||||
) : Vision {
|
) : Vision {
|
||||||
|
|
||||||
|
//protected val observableProperties: ObservableMutableMeta by lazy { properties.asObservable() }
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
protected fun getOrCreateProperties(): MutableItemProvider {
|
protected fun getOrCreateProperties(): MutableMeta {
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
val newProperties = MetaBuilder()
|
val newProperties = MutableMeta()
|
||||||
properties = newProperties
|
properties = newProperties
|
||||||
}
|
}
|
||||||
return properties!!
|
return properties!!
|
||||||
@ -45,18 +45,14 @@ public open class VisionBase(
|
|||||||
/**
|
/**
|
||||||
* A fast accessor method to get own property (no inheritance or styles
|
* A fast accessor method to get own property (no inheritance or styles
|
||||||
*/
|
*/
|
||||||
override fun getOwnProperty(name: Name): MetaItem? = if (name == Name.EMPTY) {
|
override fun getOwnProperty(name: Name): Meta? = properties?.getMeta(name)
|
||||||
properties?.rootItem
|
|
||||||
} else {
|
|
||||||
properties?.getItem(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getProperty(
|
override fun getProperty(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
|
): Meta? = if (!inherit && !includeStyles && !includeDefaults) {
|
||||||
getOwnProperty(name)
|
getOwnProperty(name)
|
||||||
} else {
|
} else {
|
||||||
buildList {
|
buildList {
|
||||||
@ -68,22 +64,32 @@ public open class VisionBase(
|
|||||||
add(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
add(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||||
}
|
}
|
||||||
if (includeDefaults) {
|
if (includeDefaults) {
|
||||||
add(descriptor?.defaultMeta?.get(name))
|
add(descriptor?.defaultNode?.get(name))
|
||||||
}
|
}
|
||||||
}.merge()
|
}.merge()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
override fun setPropertyNode(name: Name, node: Meta?, notify: Boolean) {
|
||||||
val oldItem = properties?.getItem(name)
|
val oldItem = properties?.get(name)
|
||||||
if(oldItem!= item) {
|
if (oldItem != node) {
|
||||||
getOrCreateProperties().setItem(name, item)
|
getOrCreateProperties().setMeta(name, node)
|
||||||
if (notify) {
|
if (notify) {
|
||||||
invalidateProperty(name)
|
invalidateProperty(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor? get() = null
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptor: MetaDescriptor? get() = null
|
||||||
|
|
||||||
private suspend fun updateStyles(names: List<String>) {
|
private suspend fun updateStyles(names: List<String>) {
|
||||||
names.mapNotNull { getStyle(it) }.asSequence()
|
names.mapNotNull { getStyle(it) }.asSequence()
|
||||||
@ -111,31 +117,23 @@ public open class VisionBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
override fun change(change: VisionChange) {
|
||||||
change.properties?.let {
|
change.properties?.let {
|
||||||
updateProperties(Name.EMPTY, it.asMetaItem())
|
updateProperties(Name.EMPTY, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val descriptor: NodeDescriptor = NodeDescriptor {
|
public val descriptor: MetaDescriptor = MetaDescriptor {
|
||||||
value(STYLE_KEY) {
|
value(STYLE_KEY, ValueType.STRING) {
|
||||||
type(ValueType.STRING)
|
|
||||||
multiple = true
|
multiple = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Vision.updateProperties(at: Name, item: MetaItem) {
|
public fun Vision.updateProperties(at: Name, item: Meta) {
|
||||||
when (item) {
|
setPropertyValue(at, item.value)
|
||||||
is MetaItemValue -> {
|
item.items.forEach { (token, item) ->
|
||||||
if (item.value == Null) {
|
updateProperties(at + token, item)
|
||||||
setProperty(at, null)
|
|
||||||
} else
|
|
||||||
setProperty(at, item)
|
|
||||||
}
|
|
||||||
is MetaItemNode -> item.node.items.forEach { (token, childItem) ->
|
|
||||||
updateProperties(at + token, childItem)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
|
|||||||
|
|
||||||
private var reset: Boolean = false
|
private var reset: Boolean = false
|
||||||
private var vision: Vision? = null
|
private var vision: Vision? = null
|
||||||
private val propertyChange = MetaBuilder()
|
private val propertyChange = MutableMeta()
|
||||||
private val children: HashMap<Name, VisionChangeBuilder> = HashMap()
|
private val children: HashMap<Name, VisionChangeBuilder> = HashMap()
|
||||||
|
|
||||||
public fun isEmpty(): Boolean = propertyChange.isEmpty() && propertyChange.isEmpty() && children.isEmpty()
|
public fun isEmpty(): Boolean = propertyChange.isEmpty() && propertyChange.isEmpty() && children.isEmpty()
|
||||||
@ -30,17 +30,17 @@ public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
|
|||||||
private fun getOrPutChild(visionName: Name): VisionChangeBuilder =
|
private fun getOrPutChild(visionName: Name): VisionChangeBuilder =
|
||||||
children.getOrPut(visionName) { VisionChangeBuilder() }
|
children.getOrPut(visionName) { VisionChangeBuilder() }
|
||||||
|
|
||||||
public fun propertyChanged(visionName: Name, propertyName: Name, item: MetaItem?) {
|
public fun propertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
|
||||||
if (visionName == Name.EMPTY) {
|
if (visionName == Name.EMPTY) {
|
||||||
//Write property removal as [Null]
|
//Write property removal as [Null]
|
||||||
propertyChange[propertyName] = (item ?: Null.asMetaItem())
|
propertyChange[propertyName] = (item ?: Meta(Null))
|
||||||
} else {
|
} else {
|
||||||
getOrPutChild(visionName).propertyChanged(Name.EMPTY, propertyName, item)
|
getOrPutChild(visionName).propertyChanged(Name.EMPTY, propertyName, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun set(name: Name?, child: Vision?) {
|
override fun set(name: Name?, child: Vision?) {
|
||||||
if(name == null) error("Static children are not allowed in VisionChange")
|
if (name == null) error("Static children are not allowed in VisionChange")
|
||||||
getOrPutChild(name).apply {
|
getOrPutChild(name).apply {
|
||||||
vision = child
|
vision = child
|
||||||
reset = vision == null
|
reset = vision == null
|
||||||
@ -90,7 +90,7 @@ private fun CoroutineScope.collectChange(
|
|||||||
|
|
||||||
//Collect properties change
|
//Collect properties change
|
||||||
source.onPropertyChange(this) { propertyName ->
|
source.onPropertyChange(this) { propertyName ->
|
||||||
val newItem = source.ownProperties[propertyName]
|
val newItem = source.getOwnProperty(propertyName)
|
||||||
collector().propertyChanged(name, propertyName, newItem)
|
collector().propertyChanged(name, propertyName, newItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +75,12 @@ public interface MutableVisionGroup : VisionGroup, VisionContainerBuilder<Vision
|
|||||||
public val structureChanges: Flow<StructureChange>
|
public val structureChanges: Flow<StructureChange>
|
||||||
}
|
}
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(str.toName())
|
public operator fun <V : Vision> VisionContainer<V>.get(str: String): V? = get(Name.parse(str))
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
public operator fun <V : Vision> VisionContainerBuilder<V>.set(token: NameToken, child: V?): Unit =
|
||||||
set(token.asName(), child)
|
set(token.asName(), child)
|
||||||
|
|
||||||
public operator fun <V : Vision> VisionContainerBuilder<V>.set(key: String?, child: V?): Unit =
|
public operator fun <V : Vision> VisionContainerBuilder<V>.set(key: String?, child: V?): Unit =
|
||||||
set(key?.toName(), child)
|
set(key?.let(Name::parse), child)
|
||||||
|
|
||||||
public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null }
|
public fun MutableVisionGroup.removeAll(): Unit = children.keys.map { it.asName() }.forEach { this[it] = null }
|
@ -131,15 +131,15 @@ public open class VisionGroupBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
override fun change(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)?.update(change)
|
else -> get(name)?.change(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.update(change)
|
super.change(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,10 @@ import kotlinx.serialization.modules.polymorphic
|
|||||||
import kotlinx.serialization.modules.subclass
|
import kotlinx.serialization.modules.subclass
|
||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.node
|
|
||||||
import space.kscience.dataforge.meta.toJson
|
import space.kscience.dataforge.meta.toJson
|
||||||
import space.kscience.dataforge.meta.toMetaItem
|
import space.kscience.dataforge.meta.toMeta
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.toName
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
||||||
@ -48,12 +46,11 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
jsonFormat.encodeToJsonElement(visionSerializer, vision)
|
jsonFormat.encodeToJsonElement(visionSerializer, vision)
|
||||||
|
|
||||||
//TODO remove double transformation with dedicated Meta serial format
|
//TODO remove double transformation with dedicated Meta serial format
|
||||||
public fun decodeFromMeta(meta: Meta, descriptor: NodeDescriptor? = null): Vision =
|
public fun decodeFromMeta(meta: Meta, descriptor: MetaDescriptor? = null): Vision =
|
||||||
decodeFromJson(meta.toJson(descriptor))
|
decodeFromJson(meta.toJson(descriptor))
|
||||||
|
|
||||||
public fun encodeToMeta(vision: Vision, descriptor: NodeDescriptor? = null): Meta =
|
public fun encodeToMeta(vision: Vision, descriptor: MetaDescriptor? = null): Meta =
|
||||||
encodeToJsonElement(vision).toMetaItem(descriptor).node
|
encodeToJsonElement(vision).toMeta(descriptor)
|
||||||
?: error("Expected node, but value found. Check your serializer!")
|
|
||||||
|
|
||||||
public companion object : PluginFactory<VisionManager> {
|
public companion object : PluginFactory<VisionManager> {
|
||||||
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag(name = "vision", group = PluginTag.DATAFORGE_GROUP)
|
||||||
@ -89,7 +86,7 @@ public abstract class VisionPlugin(meta: Meta = Meta.EMPTY) : AbstractPlugin(met
|
|||||||
protected abstract val visionSerializersModule: SerializersModule
|
protected abstract val visionSerializersModule: SerializersModule
|
||||||
|
|
||||||
override fun content(target: String): Map<Name, Any> = when (target) {
|
override fun content(target: String): Map<Name, Any> = when (target) {
|
||||||
VisionManager.VISION_SERIALIZER_MODULE_TARGET -> mapOf(tag.toString().toName() to visionSerializersModule)
|
VisionManager.VISION_SERIALIZER_MODULE_TARGET -> mapOf(Name.parse(tag.toString()) to visionSerializersModule)
|
||||||
else -> super.content(target)
|
else -> super.content(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
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,32 +1,49 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Configurable
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
|
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 fun getProperty(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean = false,
|
inherit: Boolean = false,
|
||||||
includeStyles: Boolean = true,
|
includeStyles: Boolean = true,
|
||||||
includeDefaults: Boolean = true,
|
includeDefaults: Boolean = true,
|
||||||
): MetaItem?
|
): Meta?
|
||||||
|
|
||||||
public fun setProperty(name: Name, item: MetaItem?, notify: Boolean = true)
|
/**
|
||||||
|
* 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>(protected val config: ObservableMeta): VisionPropertyContainer<V>{
|
public open class SimpleVisionPropertyContainer<out V : Vision>(
|
||||||
|
override val meta: ObservableMutableMeta,
|
||||||
|
) : VisionPropertyContainer<V>, Configurable {
|
||||||
override fun getProperty(
|
override fun getProperty(
|
||||||
name: Name,
|
name: Name,
|
||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean
|
includeDefaults: Boolean
|
||||||
): MetaItem? = config[name]
|
): Meta? = meta[name]
|
||||||
|
|
||||||
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
override fun setPropertyNode(name: Name, node: Meta?, notify: Boolean) {
|
||||||
config[name] = item
|
this.meta.setMeta(name, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setPropertyValue(name: Name, value: Value?, notify: Boolean) {
|
||||||
|
this.meta.setValue(name, value)
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,12 +2,13 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaBuilder
|
|
||||||
import space.kscience.dataforge.meta.MetaSerializer
|
import space.kscience.dataforge.meta.MetaSerializer
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
import space.kscience.dataforge.meta.isEmpty
|
import space.kscience.dataforge.meta.isEmpty
|
||||||
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.dataforge.names.toName
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
@ -25,7 +26,7 @@ public class VisionOutput @PublishedApi internal constructor(public val manager:
|
|||||||
|
|
||||||
//TODO expose a way to define required plugins.
|
//TODO expose a way to define required plugins.
|
||||||
|
|
||||||
public inline fun meta(block: MetaBuilder.() -> Unit) {
|
public inline fun meta(block: MutableMeta.() -> Unit) {
|
||||||
this.meta = Meta(block)
|
this.meta = Meta(block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,7 +37,7 @@ public class VisionOutput @PublishedApi internal constructor(public val manager:
|
|||||||
@VisionDSL
|
@VisionDSL
|
||||||
public abstract class VisionTagConsumer<R>(
|
public abstract class VisionTagConsumer<R>(
|
||||||
private val root: TagConsumer<R>,
|
private val root: TagConsumer<R>,
|
||||||
public val manager:VisionManager,
|
public val manager: VisionManager,
|
||||||
private val idPrefix: String? = null,
|
private val idPrefix: String? = null,
|
||||||
) : TagConsumer<R> by root {
|
) : TagConsumer<R> by root {
|
||||||
|
|
||||||
@ -94,11 +95,11 @@ public abstract class VisionTagConsumer<R>(
|
|||||||
public inline fun <T> TagConsumer<T>.vision(
|
public inline fun <T> TagConsumer<T>.vision(
|
||||||
name: String = DEFAULT_VISION_NAME,
|
name: String = DEFAULT_VISION_NAME,
|
||||||
visionProvider: VisionOutput.() -> Vision,
|
visionProvider: VisionOutput.() -> Vision,
|
||||||
): T = vision(name.toName(), visionProvider)
|
): T = vision(Name.parse(name), visionProvider)
|
||||||
|
|
||||||
public fun <T> TagConsumer<T>.vision(
|
public fun <T> TagConsumer<T>.vision(
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
): T = vision("vision[${vision.hashCode()}]".toName(), vision)
|
): T = vision(NameToken("vision", vision.hashCode().toString()).asName(), vision)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the resulting object produced by [TagConsumer]
|
* Process the resulting object produced by [TagConsumer]
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
package space.kscience.visionforge
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Laminate
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.boolean
|
||||||
|
import space.kscience.dataforge.meta.isLeaf
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
|
|
||||||
@DslMarker
|
@DslMarker
|
||||||
public annotation class VisionBuilder
|
public annotation class VisionBuilder
|
||||||
|
|
||||||
public fun List<MetaItem?>.merge(): MetaItem? = when (val first = firstOrNull { it != null }) {
|
public fun List<Meta?>.merge(): Meta? {
|
||||||
null -> null
|
val first = firstOrNull { it != null }
|
||||||
is MetaItemValue -> first //fast search for first entry if it is value
|
return when {
|
||||||
is MetaItemNode -> {
|
first == null -> null
|
||||||
//merge nodes if first encountered node is meta
|
first.isLeaf -> first //fast search for first entry if it is value
|
||||||
val laminate: Laminate = Laminate(mapNotNull { it.node })
|
else -> Laminate(filterNotNull()) //merge nodes if first encountered node is meta
|
||||||
MetaItemNode(laminate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,8 +23,4 @@ public fun List<MetaItem?>.merge(): MetaItem? = when (val first = firstOrNull {
|
|||||||
*/
|
*/
|
||||||
public var Vision.visible: Boolean?
|
public var Vision.visible: Boolean?
|
||||||
get() = getProperty(Vision.VISIBLE_KEY).boolean
|
get() = getProperty(Vision.VISIBLE_KEY).boolean
|
||||||
set(value) = setProperty(Vision.VISIBLE_KEY, value?.asValue())
|
set(value) = setPropertyValue(Vision.VISIBLE_KEY, value?.asValue())
|
||||||
|
|
||||||
public fun Vision.configure(meta: Meta?): Unit = update(VisionChange(properties = meta))
|
|
||||||
|
|
||||||
public fun Vision.configure(block: MetaBuilder.() -> Unit): Unit = configure(Meta(block))
|
|
@ -2,11 +2,11 @@ package space.kscience.visionforge
|
|||||||
|
|
||||||
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.asObservable
|
import space.kscience.dataforge.meta.descriptors.Described
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptorBuilder
|
import space.kscience.dataforge.meta.descriptors.item
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptorBuilder
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.meta.toMutableMeta
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
@ -14,55 +14,53 @@ import kotlin.reflect.typeOf
|
|||||||
/**
|
/**
|
||||||
* TODO to be moved into the core
|
* TODO to be moved into the core
|
||||||
*/
|
*/
|
||||||
public inline fun <S : Scheme, reified T> NodeDescriptorBuilder.value(
|
public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
|
||||||
property: KProperty1<S, T>,
|
property: KProperty1<S, T>,
|
||||||
noinline block: ValueDescriptorBuilder.() -> Unit = {},
|
noinline block: MetaDescriptorBuilder.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
when (typeOf<T>()) {
|
when (typeOf<T>()) {
|
||||||
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
|
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
|
||||||
value(property.name) {
|
value(property.name, ValueType.NUMBER) {
|
||||||
type(ValueType.NUMBER)
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
typeOf<Number?>(), typeOf<Int?>(), typeOf<Double?>(), typeOf<Short?>(), typeOf<Long?>(), typeOf<Float?>() ->
|
typeOf<Number?>(), typeOf<Int?>(), typeOf<Double?>(), typeOf<Short?>(), typeOf<Long?>(), typeOf<Float?>() ->
|
||||||
value(property.name) {
|
value(property.name, ValueType.NUMBER) {
|
||||||
type(ValueType.NUMBER)
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
typeOf<Boolean>() -> value(property.name) {
|
typeOf<Boolean>() -> value(property.name, ValueType.BOOLEAN) {
|
||||||
type(ValueType.BOOLEAN)
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
typeOf<List<Number>>(), typeOf<List<Int>>(), typeOf<List<Double>>(), typeOf<List<Short>>(), typeOf<List<Long>>(), typeOf<List<Float>>(),
|
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>(),
|
typeOf<IntArray>(), typeOf<DoubleArray>(), typeOf<ShortArray>(), typeOf<LongArray>(), typeOf<FloatArray>(),
|
||||||
-> value(property.name) {
|
-> value(property.name, ValueType.NUMBER) {
|
||||||
type(ValueType.NUMBER)
|
|
||||||
multiple = true
|
multiple = true
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
typeOf<String>() -> value(property.name) {
|
typeOf<String>() -> value(property.name, ValueType.STRING) {
|
||||||
type(ValueType.STRING)
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
typeOf<List<String>>(), typeOf<Array<String>>() -> value(property.name) {
|
typeOf<List<String>>(), typeOf<Array<String>>() -> value(property.name, ValueType.STRING) {
|
||||||
type(ValueType.STRING)
|
|
||||||
multiple = true
|
multiple = true
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
else -> value(property.name, block)
|
else -> item(property.name, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun NodeDescriptor.copy(block: NodeDescriptorBuilder.() -> Unit = {}): NodeDescriptor {
|
public fun MetaDescriptorBuilder.item(
|
||||||
return NodeDescriptorBuilder(toMeta().toMutableMeta().asObservable()).apply(block)
|
key: String,
|
||||||
|
described: Described,
|
||||||
|
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||||
|
) {
|
||||||
|
described.descriptor?.let {
|
||||||
|
item(Name.parse(key), it, block)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <S : Scheme, reified T : Scheme> NodeDescriptorBuilder.scheme(
|
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(
|
||||||
property: KProperty1<S, T>,
|
property: KProperty1<S, T>,
|
||||||
spec: SchemeSpec<T>,
|
spec: SchemeSpec<T>,
|
||||||
noinline block: NodeDescriptorBuilder.() -> Unit = {},
|
noinline block: MetaDescriptorBuilder.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
spec.descriptor?.let { descriptor ->
|
item(property.name, spec, block)
|
||||||
item(property.name, descriptor.copy(block))
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
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.values.Value
|
||||||
|
import space.kscience.dataforge.values.number
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
public fun Vision.propertyNode(
|
||||||
|
name: Name? = null,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
): ReadWriteProperty<Any?, Meta?> = object : ReadWriteProperty<Any?, Meta?> {
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? =
|
||||||
|
getProperty(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) {
|
||||||
|
setPropertyNode(name ?: Name.parse(property.name), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T> Vision.propertyNode(
|
||||||
|
converter: MetaConverter<T>,
|
||||||
|
name: Name? = null,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T? = getProperty(
|
||||||
|
name ?: Name.parse(property.name),
|
||||||
|
inherit,
|
||||||
|
includeStyles,
|
||||||
|
includeDefaults
|
||||||
|
)?.let(converter::metaToObject)
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||||
|
setPropertyNode(name ?: Name.parse(property.name), value?.let(converter::objectToMeta))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Vision.propertyValue(
|
||||||
|
name: Name? = null,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
): ReadWriteProperty<Any?, Value?> = object : ReadWriteProperty<Any?, Value?> {
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
|
||||||
|
getProperty(name ?: Name.parse(property.name), inherit, includeStyles, includeDefaults)?.value
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
|
||||||
|
setPropertyValue(name ?: Name.parse(property.name), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T> Vision.propertyValue(
|
||||||
|
name: Name? = null,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
setter: (T) -> Value? = { it?.let(Value::of) },
|
||||||
|
getter: (Value?) -> T,
|
||||||
|
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T = getProperty(
|
||||||
|
name ?: Name.parse(property.name),
|
||||||
|
inherit,
|
||||||
|
includeStyles,
|
||||||
|
includeDefaults
|
||||||
|
)?.value.let(getter)
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
|
setPropertyValue(name ?: Name.parse(property.name), value?.let(setter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Vision.numberProperty(
|
||||||
|
name: Name? = null,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true
|
||||||
|
): ReadWriteProperty<Any?, Number?> = propertyValue(name, inherit, includeStyles, includeDefaults) { it?.number }
|
||||||
|
|
||||||
|
public fun Vision.numberProperty(
|
||||||
|
name: Name? = null,
|
||||||
|
inherit: Boolean = false,
|
||||||
|
includeStyles: Boolean = true,
|
||||||
|
includeDefaults: Boolean = true,
|
||||||
|
default: () -> Number
|
||||||
|
): ReadWriteProperty<Any?, Number> = propertyValue(name, inherit, includeStyles, includeDefaults) {
|
||||||
|
it?.number ?: default()
|
||||||
|
}
|
@ -2,87 +2,63 @@ 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.Name
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.values.ValueType
|
|
||||||
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"
|
||||||
private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles"
|
private const val STYLE_DESCRIPTOR_ATTRIBUTE = "useStyles"
|
||||||
|
|
||||||
public val ItemDescriptor.inherited: Boolean
|
public val MetaDescriptor.inherited: Boolean
|
||||||
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
|
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
|
||||||
|
|
||||||
public var ItemDescriptorBuilder.inherited: Boolean
|
public var MetaDescriptorBuilder.inherited: Boolean
|
||||||
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
|
get() = attributes[INHERITED_DESCRIPTOR_ATTRIBUTE].boolean ?: false
|
||||||
set(value) = attributes {
|
set(value) = attributes.set(INHERITED_DESCRIPTOR_ATTRIBUTE, value)
|
||||||
set(INHERITED_DESCRIPTOR_ATTRIBUTE, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
public val ItemDescriptor.usesStyles: Boolean
|
|
||||||
|
public val MetaDescriptor.usesStyles: Boolean
|
||||||
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
|
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
|
||||||
|
|
||||||
public var ItemDescriptorBuilder.usesStyles: Boolean
|
public var MetaDescriptorBuilder.usesStyles: Boolean
|
||||||
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
|
get() = attributes[STYLE_DESCRIPTOR_ATTRIBUTE].boolean ?: true
|
||||||
set(value) = attributes {
|
set(value) = attributes.set(STYLE_DESCRIPTOR_ATTRIBUTE, value)
|
||||||
set(STYLE_DESCRIPTOR_ATTRIBUTE, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public val Vision.describedProperties: Meta
|
public val Vision.describedProperties: Meta
|
||||||
get() = Meta {
|
get() = Meta {
|
||||||
descriptor?.items?.forEach { (key, descriptor) ->
|
descriptor?.children?.forEach { (key, descriptor) ->
|
||||||
key put getProperty(key, inherit = descriptor.inherited)
|
this.setMeta(key.asName(), getProperty(key, inherit = descriptor.inherited))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public val ValueDescriptor.widget: Meta
|
public val MetaDescriptor.widget: Meta
|
||||||
get() = attributes["widget"].node ?: Meta.EMPTY
|
get() = attributes["widget"] ?: Meta.EMPTY
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension property to access the "widget" key of [ValueDescriptor]
|
* Extension property to access the "widget" key of [ValueDescriptor]
|
||||||
*/
|
*/
|
||||||
public var ValueDescriptorBuilder.widget: Meta
|
public var MetaDescriptorBuilder.widget: Meta
|
||||||
get() = attributes["widget"].node ?: Meta.EMPTY
|
get() = attributes["widget"] ?: Meta.EMPTY
|
||||||
set(value) {
|
set(value) {
|
||||||
attributes {
|
attributes["widget"] = value
|
||||||
set("widget", value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public val ValueDescriptor.widgetType: String?
|
public val MetaDescriptor.widgetType: String?
|
||||||
get() = attributes["widget.type"].string
|
get() = attributes["widget.type"].string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension property to access the "widget.type" key of [ValueDescriptor]
|
* Extension property to access the "widget.type" key of [ValueDescriptor]
|
||||||
*/
|
*/
|
||||||
public var ValueDescriptorBuilder.widgetType: String?
|
public var MetaDescriptorBuilder.widgetType: String?
|
||||||
get() = attributes["widget.type"].string
|
get() = attributes["widget.type"].string
|
||||||
set(value) {
|
set(value) {
|
||||||
attributes {
|
attributes["widget.type"] = value?.asValue()
|
||||||
set("widget.type", value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, this item is hidden in property editor. Default is false
|
* If true, this item is hidden in property editor. Default is false
|
||||||
*/
|
*/
|
||||||
public val ItemDescriptor.hidden: Boolean
|
public val MetaDescriptor.hidden: Boolean
|
||||||
get() = attributes["widget.hide"].boolean ?: false
|
get() = attributes["widget.hide"].boolean ?: false
|
||||||
|
|
||||||
public fun ItemDescriptorBuilder.hide(): Unit = attributes {
|
public fun MetaDescriptorBuilder.hide(): Unit = attributes.set("widget.hide", true)
|
||||||
set("widget.hide", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public inline fun <reified E : Enum<E>> NodeDescriptorBuilder.enum(
|
|
||||||
key: Name,
|
|
||||||
default: E?,
|
|
||||||
crossinline modifier: ValueDescriptorBuilder.() -> Unit = {},
|
|
||||||
): Unit = value(key) {
|
|
||||||
type(ValueType.STRING)
|
|
||||||
default?.let {
|
|
||||||
default(default)
|
|
||||||
}
|
|
||||||
allowedValues = enumValues<E>().map { it.asValue() }
|
|
||||||
modifier()
|
|
||||||
}
|
|
@ -57,7 +57,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() }
|
||||||
|
@ -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.update(change)
|
vision.change(change)
|
||||||
} else {
|
} else {
|
||||||
console.error("WebSocket message data is not a string")
|
console.error("WebSocket message data is not a string")
|
||||||
}
|
}
|
||||||
|
@ -115,5 +115,5 @@ public class ApplicationSurrogate : App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun Context.display(width: Double = 800.0, height: Double = 600.0, component: () -> UIComponent) {
|
public fun Context.display(width: Double = 800.0, height: Double = 600.0, component: () -> UIComponent) {
|
||||||
plugins.fetch(FXPlugin).display(component(), width, height)
|
fetch(FXPlugin).display(component(), width, height)
|
||||||
}
|
}
|
@ -9,8 +9,8 @@ import javafx.collections.FXCollections
|
|||||||
import javafx.scene.control.ComboBox
|
import javafx.scene.control.ComboBox
|
||||||
import javafx.util.StringConverter
|
import javafx.util.StringConverter
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.value
|
|
||||||
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
|
||||||
@ -56,7 +56,7 @@ public class ComboBoxValueChooser(public val values: Collection<Value>? = null)
|
|||||||
override val name: Name = "combo".asName()
|
override val name: Name = "combo".asName()
|
||||||
|
|
||||||
override fun invoke(meta: Meta): ValueChooser =
|
override fun invoke(meta: Meta): ValueChooser =
|
||||||
ComboBoxValueChooser(meta["values"].value?.list)
|
ComboBoxValueChooser(meta["values"]?.value?.list)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,189 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package space.kscience.visionforge.editor
|
|
||||||
|
|
||||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
|
|
||||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
|
|
||||||
import javafx.scene.Node
|
|
||||||
import javafx.scene.control.*
|
|
||||||
import javafx.scene.control.cell.TextFieldTreeTableCell
|
|
||||||
import javafx.scene.layout.BorderPane
|
|
||||||
import javafx.scene.layout.HBox
|
|
||||||
import javafx.scene.layout.Priority
|
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import javafx.scene.text.Text
|
|
||||||
import space.kscience.dataforge.context.Global
|
|
||||||
import space.kscience.dataforge.meta.Config
|
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import space.kscience.dataforge.names.NameToken
|
|
||||||
import space.kscience.visionforge.dfIconView
|
|
||||||
import tornadofx.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A configuration editor fragment
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public class ConfigEditor(
|
|
||||||
public val rootNode: FXMetaNode<Config>,
|
|
||||||
public val allowNew: Boolean = true,
|
|
||||||
title: String = "Configuration editor"
|
|
||||||
) : Fragment(title = title, icon = dfIconView) {
|
|
||||||
//TODO replace parameters by properties
|
|
||||||
|
|
||||||
public constructor(config: Config, descriptor: NodeDescriptor?, title: String = "Configuration editor") :
|
|
||||||
this(FXMeta.root(config, descriptor = descriptor), title = title)
|
|
||||||
|
|
||||||
override val root: BorderPane = borderpane {
|
|
||||||
center = treetableview<FXMeta<Config>> {
|
|
||||||
root = TreeItem(rootNode)
|
|
||||||
root.isExpanded = true
|
|
||||||
sortMode = TreeSortMode.ALL_DESCENDANTS
|
|
||||||
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
|
||||||
populate {
|
|
||||||
when (val fxMeta = it.value) {
|
|
||||||
is FXMetaNode -> {
|
|
||||||
fxMeta.children
|
|
||||||
}
|
|
||||||
is FXMetaValue -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
column("Name", FXMeta<Config>::name) {
|
|
||||||
setCellFactory {
|
|
||||||
object : TextFieldTreeTableCell<FXMeta<Config>, NameToken>() {
|
|
||||||
override fun updateItem(item: NameToken?, empty: Boolean) {
|
|
||||||
super.updateItem(item, empty)
|
|
||||||
contextMenu?.items?.removeIf { it.text == "Remove" }
|
|
||||||
if (!empty) {
|
|
||||||
if (treeTableRow.item != null) {
|
|
||||||
textFillProperty().bind(treeTableRow.item.hasValue.objectBinding {
|
|
||||||
if (it == true) {
|
|
||||||
Color.BLACK
|
|
||||||
} else {
|
|
||||||
Color.GRAY
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (treeTableRow.treeItem.value.parent != null && treeTableRow.treeItem.value.hasValue.get()) {
|
|
||||||
contextmenu {
|
|
||||||
item("Remove") {
|
|
||||||
action {
|
|
||||||
treeTableRow.item.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
column("Value") { param: TreeTableColumn.CellDataFeatures<FXMeta<Config>, FXMeta<Config>> ->
|
|
||||||
param.value.valueProperty()
|
|
||||||
}.setCellFactory {
|
|
||||||
ValueCell()
|
|
||||||
}
|
|
||||||
|
|
||||||
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMeta<Config>, String> -> param.value.value.descriptionProperty }
|
|
||||||
.setCellFactory { param: TreeTableColumn<FXMeta<Config>, String> ->
|
|
||||||
val cell = TreeTableCell<FXMeta<Config>, String>()
|
|
||||||
val text = Text()
|
|
||||||
cell.graphic = text
|
|
||||||
cell.prefHeight = Control.USE_COMPUTED_SIZE
|
|
||||||
text.wrappingWidthProperty().bind(param.widthProperty())
|
|
||||||
text.textProperty().bind(cell.itemProperty())
|
|
||||||
cell
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showNodeDialog(): String? {
|
|
||||||
val dialog = TextInputDialog()
|
|
||||||
dialog.title = "Node name selection"
|
|
||||||
dialog.contentText = "Enter a name for new node: "
|
|
||||||
dialog.headerText = null
|
|
||||||
|
|
||||||
val result = dialog.showAndWait()
|
|
||||||
return result.orElse(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showValueDialog(): String? {
|
|
||||||
val dialog = TextInputDialog()
|
|
||||||
dialog.title = "Value name selection"
|
|
||||||
dialog.contentText = "Enter a name for new value: "
|
|
||||||
dialog.headerText = null
|
|
||||||
|
|
||||||
val result = dialog.showAndWait()
|
|
||||||
return result.orElse(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class ValueCell : TreeTableCell<FXMeta<Config>, FXMeta<Config>?>() {
|
|
||||||
|
|
||||||
public override fun updateItem(item: FXMeta<Config>?, empty: Boolean) {
|
|
||||||
if (!empty) {
|
|
||||||
if (item != null) {
|
|
||||||
when (item) {
|
|
||||||
is FXMetaValue<Config> -> {
|
|
||||||
text = null
|
|
||||||
val chooser = ValueChooser.build(
|
|
||||||
Global,
|
|
||||||
item.valueProperty,
|
|
||||||
item.descriptor
|
|
||||||
) {
|
|
||||||
item.set(it)
|
|
||||||
}
|
|
||||||
graphic = chooser.node
|
|
||||||
}
|
|
||||||
is FXMetaNode<Config> -> {
|
|
||||||
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 {
|
|
||||||
text = null
|
|
||||||
graphic = null
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
text = null
|
|
||||||
graphic = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* The tag not to display node or value in configurator
|
|
||||||
*/
|
|
||||||
const val NO_CONFIGURATOR_TAG = "nocfg"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,223 +0,0 @@
|
|||||||
package space.kscience.visionforge.editor
|
|
||||||
|
|
||||||
import javafx.beans.binding.ListBinding
|
|
||||||
import javafx.beans.binding.ObjectBinding
|
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
|
||||||
import javafx.beans.value.ObservableBooleanValue
|
|
||||||
import javafx.beans.value.ObservableStringValue
|
|
||||||
import javafx.collections.ObservableList
|
|
||||||
import space.kscience.dataforge.meta.*
|
|
||||||
import space.kscience.dataforge.meta.descriptors.ItemDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
|
||||||
import space.kscience.dataforge.names.*
|
|
||||||
import space.kscience.dataforge.values.Null
|
|
||||||
import space.kscience.dataforge.values.Value
|
|
||||||
import tornadofx.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A display for meta and descriptor
|
|
||||||
*/
|
|
||||||
sealed class FXMeta<M : TypedMeta<M>> : Comparable<FXMeta<*>> {
|
|
||||||
abstract val name: NameToken
|
|
||||||
abstract val parent: FXMetaNode<M>?
|
|
||||||
abstract val descriptionProperty: ObservableStringValue
|
|
||||||
abstract val descriptor: ItemDescriptor?
|
|
||||||
|
|
||||||
abstract val hasValue: ObservableBooleanValue
|
|
||||||
|
|
||||||
override fun compareTo(other: FXMeta<*>): Int {
|
|
||||||
return if (this.hasValue.get() == other.hasValue.get()) {
|
|
||||||
this.name.toString().compareTo(other.name.toString())
|
|
||||||
} else {
|
|
||||||
this.hasValue.get().compareTo(other.hasValue.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <M : TypedMeta<M>> root(
|
|
||||||
node: M,
|
|
||||||
descriptor: NodeDescriptor? = null,
|
|
||||||
rootName: String = "root"
|
|
||||||
): FXMetaNode<M> =
|
|
||||||
FXMetaNode(NameToken(rootName), null, node, descriptor)
|
|
||||||
|
|
||||||
fun root(node: Meta, descriptor: NodeDescriptor? = null, rootName: String = "root"): FXMetaNode<SealedMeta> =
|
|
||||||
root(node.seal(), descriptor, rootName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FXMetaNode<M : TypedMeta<M>>(
|
|
||||||
override val name: NameToken,
|
|
||||||
override val parent: FXMetaNode<M>?,
|
|
||||||
nodeValue: M? = null,
|
|
||||||
descriptorValue: NodeDescriptor? = null
|
|
||||||
) : FXMeta<M>() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(innerDescriptorProperty) {
|
|
||||||
value ?: parent?.descriptor?.nodes?.get(this@FXMetaNode.name.body)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor? by descriptorProperty
|
|
||||||
|
|
||||||
private val innerNodeProperty = SimpleObjectProperty(nodeValue)
|
|
||||||
|
|
||||||
val nodeProperty: ObjectBinding<M?> = objectBinding(innerNodeProperty) {
|
|
||||||
value ?: parent?.node?.get(this@FXMetaNode.name).node
|
|
||||||
}
|
|
||||||
|
|
||||||
val node: M? by nodeProperty
|
|
||||||
|
|
||||||
override val descriptionProperty = innerDescriptorProperty.stringBinding { it?.info ?: "" }
|
|
||||||
|
|
||||||
override val hasValue: ObservableBooleanValue = nodeProperty.booleanBinding { it != null }
|
|
||||||
|
|
||||||
private val filter: (FXMeta<M>) -> Boolean = { cfg ->
|
|
||||||
!(cfg.descriptor?.attributes?.get(ConfigEditor.NO_CONFIGURATOR_TAG)?.boolean ?: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val children = object : ListBinding<FXMeta<M>>() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
bind(nodeProperty, descriptorProperty)
|
|
||||||
|
|
||||||
val listener: (Name, MetaItem?, MetaItem?) -> Unit = { name, _, _ ->
|
|
||||||
if (name.length == 1) invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
(node as? Config)?.onChange(this, listener)
|
|
||||||
|
|
||||||
nodeProperty.addListener { _, oldValue, newValue ->
|
|
||||||
if (newValue == null) {
|
|
||||||
(oldValue as? Config)?.removeListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newValue is Config) {
|
|
||||||
newValue.onChange(this, listener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun computeValue(): ObservableList<FXMeta<M>> {
|
|
||||||
val nodeKeys = node?.items?.keys?.toSet() ?: emptySet()
|
|
||||||
val descriptorKeys = descriptor?.items?.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?.items?.get(token.body)
|
|
||||||
|
|
||||||
if (actualItem is MetaItemNode || actualDescriptor is NodeDescriptor) {
|
|
||||||
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() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FXMetaValue<M : TypedMeta<M>>(
|
|
||||||
override val name: NameToken,
|
|
||||||
override val parent: FXMetaNode<M>
|
|
||||||
) : FXMeta<M>() {
|
|
||||||
|
|
||||||
public val descriptorProperty = parent.descriptorProperty.objectBinding {
|
|
||||||
it?.values?.get(name.body)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A descriptor that could be manually set to the node
|
|
||||||
*/
|
|
||||||
override val descriptor: ValueDescriptor? by descriptorProperty
|
|
||||||
|
|
||||||
//private val innerValueProperty = SimpleObjectProperty(value)
|
|
||||||
|
|
||||||
public val valueProperty = descriptorProperty.objectBinding { descriptor ->
|
|
||||||
parent.node?.get(name).value ?: descriptor?.default
|
|
||||||
}
|
|
||||||
|
|
||||||
override val hasValue: ObservableBooleanValue = parent.nodeProperty.booleanBinding { it?.get(name) != null }
|
|
||||||
|
|
||||||
public val value by valueProperty
|
|
||||||
|
|
||||||
override val descriptionProperty = descriptorProperty.stringBinding { it?.info ?: "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun <M : MutableMeta<M>> FXMetaNode<M>.remove(name: NameToken) {
|
|
||||||
node?.remove(name.asName())
|
|
||||||
children.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <M : MutableMeta<M>> 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!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMetaNode<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")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMeta<M>.remove() {
|
|
||||||
parent?.node?.remove(name.asName())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addValue(key: String) {
|
|
||||||
val parent = getOrCreateNode()
|
|
||||||
if (descriptor?.multiple == true) {
|
|
||||||
parent.append(key, Null)
|
|
||||||
} else {
|
|
||||||
parent[key] = Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addNode(key: String) {
|
|
||||||
val parent = getOrCreateNode()
|
|
||||||
if (descriptor?.multiple == true) {
|
|
||||||
parent.append(key, Meta.EMPTY)
|
|
||||||
} else {
|
|
||||||
parent[key] = Meta.EMPTY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMetaValue<M>.set(value: Value?) {
|
|
||||||
if (descriptor?.multiple == true) {
|
|
||||||
parent.getOrCreateNode().append(this.name.body, value)
|
|
||||||
} else {
|
|
||||||
parent.getOrCreateNode()[this.name] = value
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,217 @@
|
|||||||
|
package space.kscience.visionforge.editor
|
||||||
|
|
||||||
|
import javafx.beans.binding.Binding
|
||||||
|
import javafx.beans.binding.BooleanBinding
|
||||||
|
import javafx.beans.binding.ListBinding
|
||||||
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
|
import javafx.collections.ObservableList
|
||||||
|
import space.kscience.dataforge.meta.*
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
|
import space.kscience.dataforge.names.*
|
||||||
|
import space.kscience.dataforge.values.Value
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A display for meta and descriptor
|
||||||
|
*/
|
||||||
|
public class FXMetaModel<M : Meta>(
|
||||||
|
public val root: M,
|
||||||
|
public val rootDescriptor: MetaDescriptor?,
|
||||||
|
public val nodeName: Name,
|
||||||
|
public val title: String = nodeName.lastOrNull()?.toString() ?: "Meta"
|
||||||
|
) : Comparable<FXMetaModel<*>> {
|
||||||
|
|
||||||
|
private val existingNode = SimpleObjectProperty<Meta>(root[nodeName])
|
||||||
|
|
||||||
|
public val children: ListBinding<FXMetaModel<M>> = object : ListBinding<FXMetaModel<M>>() {
|
||||||
|
override fun computeValue(): ObservableList<FXMetaModel<M>> {
|
||||||
|
val nodeKeys = existingNode.get().items.keys
|
||||||
|
val descriptorKeys = descriptor?.children?.keys?.map { NameToken(it) } ?: emptySet()
|
||||||
|
return (nodeKeys + descriptorKeys).map {
|
||||||
|
FXMetaModel(
|
||||||
|
root,
|
||||||
|
rootDescriptor,
|
||||||
|
nodeName + it
|
||||||
|
)
|
||||||
|
}.filter(filter).asObservable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
//add listener to the root node if possible
|
||||||
|
if (root is ObservableMeta) {
|
||||||
|
root.onChange(this) { changed ->
|
||||||
|
if (changed.startsWith(nodeName)) {
|
||||||
|
if (nodeName.length == changed.length) existingNode.set(root[nodeName])
|
||||||
|
else if (changed.length == nodeName.length + 1) children.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val descriptor: MetaDescriptor? = rootDescriptor?.get(nodeName)
|
||||||
|
|
||||||
|
public val existsProperty: BooleanBinding = existingNode.isNotNull
|
||||||
|
|
||||||
|
public val exists: Boolean by existsProperty
|
||||||
|
|
||||||
|
public val valueProperty: Binding<Value?> = existingNode.objectBinding {
|
||||||
|
existingNode.get().value ?: descriptor?.defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: FXMetaModel<*>): Int = if (this.exists == other.exists) {
|
||||||
|
this.nodeName.toString().compareTo(other.nodeName.toString())
|
||||||
|
} else {
|
||||||
|
this.exists.compareTo(other.exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
private val filter: (FXMetaModel<*>) -> Boolean = { cfg ->
|
||||||
|
!(cfg.descriptor?.attributes?.get(MutableMetaEditor.NO_CONFIGURATOR_TAG)?.boolean ?: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <M : Meta> root(
|
||||||
|
node: M,
|
||||||
|
descriptor: MetaDescriptor? = null,
|
||||||
|
rootName: String = "root"
|
||||||
|
): 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)
|
||||||
|
}
|
@ -16,45 +16,42 @@
|
|||||||
|
|
||||||
package space.kscience.visionforge.editor
|
package space.kscience.visionforge.editor
|
||||||
|
|
||||||
import javafx.beans.property.SimpleStringProperty
|
|
||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
||||||
import javafx.scene.control.TreeSortMode
|
import javafx.scene.control.TreeSortMode
|
||||||
import javafx.scene.control.TreeTableView
|
import javafx.scene.control.TreeTableView
|
||||||
|
import javafx.scene.layout.BorderPane
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.values.string
|
import space.kscience.dataforge.values.string
|
||||||
import space.kscience.visionforge.dfIconView
|
import space.kscience.visionforge.dfIconView
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MetaViewer(val rootNode: FXMetaNode<*>, title: String = "Meta viewer") : Fragment(title,
|
public class MetaViewer(
|
||||||
dfIconView
|
private val rootNode: FXMetaModel<Meta>,
|
||||||
) {
|
title: String = "Meta viewer"
|
||||||
constructor(meta: Meta, title: String = "Meta viewer"): this(
|
) : Fragment(title, dfIconView) {
|
||||||
FXMeta.root(
|
|
||||||
meta
|
|
||||||
),title = title)
|
|
||||||
|
|
||||||
override val root = borderpane {
|
public constructor(meta: Meta, title: String = "Meta viewer") : this(
|
||||||
|
FXMetaModel.root(
|
||||||
|
meta
|
||||||
|
), title = title
|
||||||
|
)
|
||||||
|
|
||||||
|
override val root: BorderPane = borderpane {
|
||||||
center {
|
center {
|
||||||
treetableview<FXMeta<*>> {
|
treetableview<FXMetaModel<*>> {
|
||||||
isShowRoot = false
|
isShowRoot = false
|
||||||
root = TreeItem(rootNode)
|
root = TreeItem(rootNode)
|
||||||
populate {
|
populate {
|
||||||
when (val fxMeta = it.value) {
|
val fxMeta = it.value
|
||||||
is FXMetaNode -> {
|
fxMeta.children
|
||||||
fxMeta.children
|
|
||||||
}
|
|
||||||
is FXMetaValue -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
root.isExpanded = true
|
root.isExpanded = true
|
||||||
sortMode = TreeSortMode.ALL_DESCENDANTS
|
sortMode = TreeSortMode.ALL_DESCENDANTS
|
||||||
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
||||||
column("Name", FXMeta<*>::name)
|
column("Name", FXMetaModel<*>::title)
|
||||||
column<FXMeta<*>, String>("Value") { cellDataFeatures ->
|
column<FXMetaModel<*>, String>("Value") { cellDataFeatures ->
|
||||||
when (val item = cellDataFeatures.value.value) {
|
val item = cellDataFeatures.value.value
|
||||||
is FXMetaValue -> item.valueProperty.stringBinding { it?.string ?: "" }
|
item.valueProperty.stringBinding { it?.string ?: "" }
|
||||||
is FXMetaNode -> SimpleStringProperty("[node]")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package space.kscience.visionforge.editor
|
||||||
|
|
||||||
|
import javafx.scene.control.*
|
||||||
|
import javafx.scene.control.cell.TextFieldTreeTableCell
|
||||||
|
import javafx.scene.layout.BorderPane
|
||||||
|
import javafx.scene.paint.Color
|
||||||
|
import javafx.scene.text.Text
|
||||||
|
import space.kscience.dataforge.context.Global
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.visionforge.dfIconView
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Configuration editor fragment
|
||||||
|
*
|
||||||
|
* @author Alexander Nozik
|
||||||
|
*/
|
||||||
|
public class MutableMetaEditor(
|
||||||
|
public val rootNode: FXMetaModel<MutableMeta>,
|
||||||
|
public val allowNew: Boolean = true,
|
||||||
|
title: String = "Configuration editor"
|
||||||
|
) : Fragment(title = title, icon = dfIconView) {
|
||||||
|
//TODO replace parameters by properties
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
MutableMeta: MutableMeta,
|
||||||
|
descriptor: MetaDescriptor?,
|
||||||
|
title: String = "Configuration editor"
|
||||||
|
) :
|
||||||
|
this(FXMetaModel.root(MutableMeta, descriptor = descriptor), title = title)
|
||||||
|
|
||||||
|
override val root: BorderPane = borderpane {
|
||||||
|
center = treetableview<FXMetaModel<MutableMeta>> {
|
||||||
|
root = TreeItem(rootNode)
|
||||||
|
root.isExpanded = true
|
||||||
|
sortMode = TreeSortMode.ALL_DESCENDANTS
|
||||||
|
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
||||||
|
populate {
|
||||||
|
it.value.children
|
||||||
|
}
|
||||||
|
column("Name", FXMetaModel<MutableMeta>::title) {
|
||||||
|
setCellFactory {
|
||||||
|
object : TextFieldTreeTableCell<FXMetaModel<MutableMeta>, String>() {
|
||||||
|
override fun updateItem(item: String?, empty: Boolean) {
|
||||||
|
super.updateItem(item, empty)
|
||||||
|
contextMenu?.items?.removeIf { it.text == "Remove" }
|
||||||
|
val content = treeTableRow.item
|
||||||
|
if (!empty) {
|
||||||
|
if (treeTableRow.item != null) {
|
||||||
|
textFillProperty().bind(content.existsProperty.objectBinding {
|
||||||
|
if (it == true) {
|
||||||
|
Color.BLACK
|
||||||
|
} else {
|
||||||
|
Color.GRAY
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (content.exists) {
|
||||||
|
contextmenu {
|
||||||
|
item("Remove") {
|
||||||
|
action {
|
||||||
|
content.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
column("Value") { param: TreeTableColumn.CellDataFeatures<FXMetaModel<MutableMeta>, FXMetaModel<MutableMeta>> ->
|
||||||
|
param.value.valueProperty()
|
||||||
|
}.setCellFactory {
|
||||||
|
ValueCell()
|
||||||
|
}
|
||||||
|
|
||||||
|
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMetaModel<MutableMeta>, String> ->
|
||||||
|
(param.value.value.descriptor?.info ?: "").observable()
|
||||||
|
}.setCellFactory { param: TreeTableColumn<FXMetaModel<MutableMeta>, String> ->
|
||||||
|
val cell = TreeTableCell<FXMetaModel<MutableMeta>, String>()
|
||||||
|
val text = Text()
|
||||||
|
cell.graphic = text
|
||||||
|
cell.prefHeight = Control.USE_COMPUTED_SIZE
|
||||||
|
text.wrappingWidthProperty().bind(param.widthProperty())
|
||||||
|
text.textProperty().bind(cell.itemProperty())
|
||||||
|
cell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showNodeDialog(): String? {
|
||||||
|
val dialog = TextInputDialog()
|
||||||
|
dialog.title = "Node name selection"
|
||||||
|
dialog.contentText = "Enter a name for new node: "
|
||||||
|
dialog.headerText = null
|
||||||
|
|
||||||
|
val result = dialog.showAndWait()
|
||||||
|
return result.orElse(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showValueDialog(): String? {
|
||||||
|
val dialog = TextInputDialog()
|
||||||
|
dialog.title = "Value name selection"
|
||||||
|
dialog.contentText = "Enter a name for new value: "
|
||||||
|
dialog.headerText = null
|
||||||
|
|
||||||
|
val result = dialog.showAndWait()
|
||||||
|
return result.orElse(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ValueCell : TreeTableCell<FXMetaModel<MutableMeta>, FXMetaModel<MutableMeta>?>() {
|
||||||
|
|
||||||
|
public override fun updateItem(item: FXMetaModel<MutableMeta>?, empty: Boolean) {
|
||||||
|
if (!empty) {
|
||||||
|
if (item != null) {
|
||||||
|
text = null
|
||||||
|
val chooser = ValueChooser.build(
|
||||||
|
Global,
|
||||||
|
item.valueProperty,
|
||||||
|
item.descriptor
|
||||||
|
) {
|
||||||
|
item.setValue(it)
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
text = null
|
||||||
|
graphic = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = null
|
||||||
|
graphic = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* The tag not to display node or value in MutableMetaurator
|
||||||
|
*/
|
||||||
|
public const val NO_CONFIGURATOR_TAG: String = "nocfg"
|
||||||
|
}
|
||||||
|
}
|
@ -10,12 +10,13 @@ import javafx.scene.control.TextField
|
|||||||
import javafx.scene.input.KeyCode
|
import javafx.scene.input.KeyCode
|
||||||
import javafx.scene.input.KeyEvent
|
import javafx.scene.input.KeyEvent
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.validate
|
||||||
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.*
|
import space.kscience.dataforge.values.*
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class TextValueChooser : ValueChooserBase<TextField>() {
|
public class TextValueChooser : ValueChooserBase<TextField>() {
|
||||||
|
|
||||||
private val displayText: String
|
private val displayText: String
|
||||||
get() = currentValue().let {
|
get() = currentValue().let {
|
||||||
@ -85,7 +86,7 @@ class TextValueChooser : ValueChooserBase<TextField>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun validate(value: Value): Boolean {
|
private fun validate(value: Value): Boolean {
|
||||||
return descriptor?.isAllowedValue(value) ?: true
|
return descriptor?.validate(value) ?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
@ -101,7 +102,7 @@ class TextValueChooser : ValueChooserBase<TextField>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : ValueChooser.Factory {
|
public companion object : ValueChooser.Factory {
|
||||||
override val name: Name = "text".asName()
|
override val name: Name = "text".asName()
|
||||||
override fun invoke(meta: Meta): ValueChooser =
|
override fun invoke(meta: Meta): ValueChooser =
|
||||||
TextValueChooser()
|
TextValueChooser()
|
||||||
|
@ -13,11 +13,11 @@ import space.kscience.dataforge.values.Value
|
|||||||
* @param value Value after change
|
* @param value Value after change
|
||||||
* @param message Message on unsuccessful change
|
* @param message Message on unsuccessful change
|
||||||
*/
|
*/
|
||||||
class ValueCallbackResponse(val success: Boolean, val value: Value, val message: String)
|
public class ValueCallbackResponse(public val success: Boolean, public val value: Value, public val message: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for some visual object trying to change some value
|
* A callback for some visual object trying to change some value
|
||||||
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
||||||
*/
|
*/
|
||||||
typealias ValueCallback = (Value) -> ValueCallbackResponse
|
public typealias ValueCallback = (Value) -> ValueCallbackResponse
|
||||||
|
|
||||||
|
@ -10,10 +10,12 @@ import javafx.beans.value.ObservableValue
|
|||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||||
|
import space.kscience.dataforge.meta.descriptors.validate
|
||||||
import space.kscience.dataforge.misc.Named
|
import space.kscience.dataforge.misc.Named
|
||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.provider.provideByType
|
import space.kscience.dataforge.provider.provideByType
|
||||||
import space.kscience.dataforge.values.Null
|
import space.kscience.dataforge.values.Null
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
@ -42,8 +44,8 @@ public interface ValueChooser {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public val descriptorProperty: ObjectProperty<ValueDescriptor?>
|
public val descriptorProperty: ObjectProperty<MetaDescriptor?>
|
||||||
public var descriptor: ValueDescriptor?
|
public var descriptor: MetaDescriptor?
|
||||||
|
|
||||||
public val valueProperty: ObjectProperty<Value?>
|
public val valueProperty: ObjectProperty<Value?>
|
||||||
public var value: Value?
|
public var value: Value?
|
||||||
@ -71,7 +73,7 @@ public interface ValueChooser {
|
|||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
private fun findWidgetByType(context: Context, type: String): Factory? {
|
private fun findWidgetByType(context: Context, type: String): Factory? {
|
||||||
return when (type.toName()) {
|
return when (Name.parse(type)) {
|
||||||
TextValueChooser.name -> TextValueChooser
|
TextValueChooser.name -> TextValueChooser
|
||||||
ColorValueChooser.name -> ColorValueChooser
|
ColorValueChooser.name -> ColorValueChooser
|
||||||
ComboBoxValueChooser.name -> ComboBoxValueChooser
|
ComboBoxValueChooser.name -> ComboBoxValueChooser
|
||||||
@ -79,7 +81,7 @@ public interface ValueChooser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun build(context: Context, descriptor: ValueDescriptor?): ValueChooser {
|
private fun build(context: Context, descriptor: MetaDescriptor?): ValueChooser {
|
||||||
return if (descriptor == null) {
|
return if (descriptor == null) {
|
||||||
TextValueChooser();
|
TextValueChooser();
|
||||||
} else {
|
} else {
|
||||||
@ -93,7 +95,7 @@ public interface ValueChooser {
|
|||||||
descriptor.widget
|
descriptor.widget
|
||||||
) ?: TextValueChooser()
|
) ?: TextValueChooser()
|
||||||
}
|
}
|
||||||
descriptor.allowedValues.isNotEmpty() -> ComboBoxValueChooser()
|
!descriptor.allowedValues.isNullOrEmpty() -> ComboBoxValueChooser()
|
||||||
else -> TextValueChooser()
|
else -> TextValueChooser()
|
||||||
}
|
}
|
||||||
chooser.descriptor = descriptor
|
chooser.descriptor = descriptor
|
||||||
@ -101,10 +103,10 @@ public interface ValueChooser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(
|
public fun build(
|
||||||
context: Context,
|
context: Context,
|
||||||
value: ObservableValue<Value?>,
|
value: ObservableValue<Value?>,
|
||||||
descriptor: ValueDescriptor? = null,
|
descriptor: MetaDescriptor? = null,
|
||||||
setter: (Value) -> Unit,
|
setter: (Value) -> Unit,
|
||||||
): ValueChooser {
|
): ValueChooser {
|
||||||
val chooser = build(context, descriptor)
|
val chooser = build(context, descriptor)
|
||||||
@ -113,7 +115,7 @@ public interface ValueChooser {
|
|||||||
chooser.setDisplayValue(it ?: Null)
|
chooser.setDisplayValue(it ?: Null)
|
||||||
}
|
}
|
||||||
chooser.setCallback { result ->
|
chooser.setCallback { result ->
|
||||||
if (descriptor?.isAllowedValue(result) != false) {
|
if (descriptor?.validate(result) != false) {
|
||||||
setter(result)
|
setter(result)
|
||||||
ValueCallbackResponse(true, result, "OK")
|
ValueCallbackResponse(true, result, "OK")
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,7 +8,7 @@ package space.kscience.visionforge.editor
|
|||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.values.Null
|
import space.kscience.dataforge.values.Null
|
||||||
import space.kscience.dataforge.values.Value
|
import space.kscience.dataforge.values.Value
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -18,16 +18,16 @@ import tornadofx.*
|
|||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
abstract class ValueChooserBase<out T : Node> : ValueChooser {
|
public abstract class ValueChooserBase<out T : Node> : ValueChooser {
|
||||||
|
|
||||||
override val node by lazy { buildNode() }
|
override val node: T by lazy { buildNode() }
|
||||||
final override val valueProperty = SimpleObjectProperty<Value>(Null)
|
final override val valueProperty: SimpleObjectProperty<Value> = SimpleObjectProperty<Value>(Null)
|
||||||
final override val descriptorProperty = SimpleObjectProperty<ValueDescriptor>()
|
final override val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
|
||||||
|
|
||||||
override var descriptor: ValueDescriptor? by descriptorProperty
|
override var descriptor: MetaDescriptor? by descriptorProperty
|
||||||
override var value: Value? by valueProperty
|
override var value: Value? by valueProperty
|
||||||
|
|
||||||
fun resetValue() {
|
public fun resetValue() {
|
||||||
setDisplayValue(currentValue())
|
setDisplayValue(currentValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ abstract class ValueChooserBase<out T : Node> : ValueChooser {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected fun currentValue(): Value {
|
protected fun currentValue(): Value {
|
||||||
return value ?: descriptor?.default ?: Null
|
return value ?: descriptor?.defaultValue ?: Null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,39 +5,36 @@ 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.Config
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.MutableItemProvider
|
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import space.kscience.dataforge.meta.update
|
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() {
|
public class VisionEditorFragment(public val selector: (Vision) -> Meta) : Fragment() {
|
||||||
|
|
||||||
val itemProperty = SimpleObjectProperty<Vision>()
|
public val itemProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>()
|
||||||
var item: Vision? by itemProperty
|
public var item: Vision? by itemProperty
|
||||||
val descriptorProperty = SimpleObjectProperty<NodeDescriptor>()
|
public val descriptorProperty: SimpleObjectProperty<MetaDescriptor> = SimpleObjectProperty<MetaDescriptor>()
|
||||||
|
|
||||||
constructor(
|
public constructor(
|
||||||
item: Vision?,
|
item: Vision?,
|
||||||
descriptor: NodeDescriptor?,
|
descriptor: MetaDescriptor?,
|
||||||
selector: (Vision) -> MutableItemProvider = { it.allProperties() },
|
selector: (Vision) -> MutableMetaProvider = { it.meta() },
|
||||||
) : this({ it.describedProperties }) {
|
) : this({ it.describedProperties }) {
|
||||||
this.item = item
|
this.item = item
|
||||||
this.descriptorProperty.set(descriptor)
|
this.descriptorProperty.set(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentConfig: Config? = null
|
private var currentConfig: ObservableMutableMeta? = null
|
||||||
|
|
||||||
private val configProperty: Binding<Config?> = itemProperty.objectBinding { visualObject ->
|
private val configProperty: Binding<ObservableMutableMeta?> = itemProperty.objectBinding { vision ->
|
||||||
if (visualObject == null) return@objectBinding null
|
if (vision == null) return@objectBinding null
|
||||||
val meta = selector(visualObject)
|
val meta = selector(vision)
|
||||||
val config = Config().apply {
|
val config = MutableMeta {
|
||||||
update(meta)
|
update(meta)
|
||||||
onChange(this@VisualObjectEditorFragment) { key, _, after ->
|
}
|
||||||
visualObject.setProperty(key, after)
|
config.onChange(this@VisionEditorFragment) { key ->
|
||||||
}
|
vision.setPropertyNode(key, config[key])
|
||||||
}
|
}
|
||||||
//remember old config reference to cleanup listeners
|
//remember old config reference to cleanup listeners
|
||||||
currentConfig?.removeListener(this)
|
currentConfig?.removeListener(this)
|
||||||
@ -47,7 +44,7 @@ class VisualObjectEditorFragment(val selector: (Vision) -> Meta) : Fragment() {
|
|||||||
|
|
||||||
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
|
private val configEditorProperty: Binding<Node?> = configProperty.objectBinding(descriptorProperty) {
|
||||||
it?.let {
|
it?.let {
|
||||||
ConfigEditor(it, descriptorProperty.get()).root
|
MutableMetaEditor(it, descriptorProperty.get()).root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package space.kscience.visionforge.editor
|
|||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.scene.control.SelectionMode
|
import javafx.scene.control.SelectionMode
|
||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
||||||
|
import javafx.scene.layout.VBox
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionGroup
|
import space.kscience.visionforge.VisionGroup
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -29,13 +30,13 @@ private fun toTreeItem(vision: Vision, title: String): TreeItem<Pair<String, Vis
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class VisualObjectTreeFragment : Fragment() {
|
public class VisionTreeFragment : Fragment() {
|
||||||
val itemProperty = SimpleObjectProperty<Vision>()
|
public val itemProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>()
|
||||||
var item: Vision? by itemProperty
|
public var item: Vision? by itemProperty
|
||||||
|
|
||||||
val selectedProperty = SimpleObjectProperty<Vision>()
|
public val selectedProperty: SimpleObjectProperty<Vision> = SimpleObjectProperty<Vision>()
|
||||||
|
|
||||||
override val root = vbox {
|
override val root: VBox = vbox {
|
||||||
titledpane("Object tree", collapsible = false) {
|
titledpane("Object tree", collapsible = false) {
|
||||||
treeview<Pair<String, Vision>> {
|
treeview<Pair<String, Vision>> {
|
||||||
cellFormat {
|
cellFormat {
|
@ -3,11 +3,15 @@ package space.kscience.visionforge.solid
|
|||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
import javafx.scene.paint.Material
|
import javafx.scene.paint.Material
|
||||||
import javafx.scene.paint.PhongMaterial
|
import javafx.scene.paint.PhongMaterial
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.double
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.dataforge.values.int
|
import space.kscience.dataforge.values.int
|
||||||
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.solid.FXMaterials.GREY
|
||||||
|
|
||||||
public object FXMaterials {
|
public object FXMaterials {
|
||||||
public val RED: PhongMaterial = PhongMaterial().apply {
|
public val RED: PhongMaterial = PhongMaterial().apply {
|
||||||
@ -26,46 +30,43 @@ public object FXMaterials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val BLUE: PhongMaterial = PhongMaterial(Color.BLUE)
|
public val BLUE: PhongMaterial = PhongMaterial(Color.BLUE)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infer color based on meta item
|
* Infer color based on meta item
|
||||||
* @param opacity default opacity
|
* @param opacity default opacity
|
||||||
*/
|
*/
|
||||||
public fun MetaItem.color(opacity: Double = 1.0): Color {
|
public fun Meta.color(opacity: Double = 1.0): Color {
|
||||||
return when (this) {
|
return value?.let {
|
||||||
is MetaItemValue -> if (this.value.type == ValueType.NUMBER) {
|
if (it.type == ValueType.NUMBER) {
|
||||||
val int = value.int
|
val int = it.int
|
||||||
val red = int and 0x00ff0000 shr 16
|
val red = int and 0x00ff0000 shr 16
|
||||||
val green = int and 0x0000ff00 shr 8
|
val green = int and 0x0000ff00 shr 8
|
||||||
val blue = int and 0x000000ff
|
val blue = int and 0x000000ff
|
||||||
Color.rgb(red, green, blue, opacity)
|
Color.rgb(red, green, blue, opacity)
|
||||||
} else {
|
} else {
|
||||||
Color.web(this.value.string)
|
Color.web(it.string)
|
||||||
}
|
}
|
||||||
is MetaItemNode -> {
|
} ?: Color.rgb(
|
||||||
Color.rgb(
|
this[Colors.RED_KEY]?.int ?: 0,
|
||||||
node[Colors.RED_KEY]?.int ?: 0,
|
this[Colors.GREEN_KEY]?.int ?: 0,
|
||||||
node[Colors.GREEN_KEY]?.int ?: 0,
|
this[Colors.BLUE_KEY]?.int ?: 0,
|
||||||
node[Colors.BLUE_KEY]?.int ?: 0,
|
this[SolidMaterial.OPACITY_KEY]?.double ?: opacity
|
||||||
node[SolidMaterial.OPACITY_KEY]?.double ?: opacity
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infer FX material based on meta item
|
* Infer FX material based on meta item
|
||||||
*/
|
*/
|
||||||
public fun MetaItem?.material(): Material {
|
public fun Meta?.material(): Material {
|
||||||
return when (this) {
|
if (this == null) return GREY
|
||||||
null -> FXMaterials.GREY
|
return value?.let {
|
||||||
is MetaItemValue -> PhongMaterial(color())
|
PhongMaterial(color())
|
||||||
is MetaItemNode -> PhongMaterial().apply {
|
} ?: PhongMaterial().apply {
|
||||||
val opacity = node[SolidMaterial.OPACITY_KEY].double ?: 1.0
|
val opacity = get(SolidMaterial.OPACITY_KEY).double ?: 1.0
|
||||||
diffuseColor = node[SolidMaterial.COLOR_KEY]?.color(opacity) ?: Color.DARKGREY
|
diffuseColor = get(SolidMaterial.COLOR_KEY)?.color(opacity) ?: Color.DARKGREY
|
||||||
specularColor = node[SolidMaterial.SPECULAR_COLOR_KEY]?.color(opacity) ?: Color.WHITE
|
specularColor = get(SolidMaterial.SPECULAR_COLOR_KEY)?.color(opacity) ?: Color.WHITE
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,10 @@ package space.kscience.visionforge.solid
|
|||||||
|
|
||||||
import javafx.scene.Group
|
import javafx.scene.Group
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.cutFirst
|
||||||
|
import space.kscience.dataforge.names.firstOrNull
|
||||||
|
import space.kscience.dataforge.names.isEmpty
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -16,7 +19,7 @@ class FXReferenceFactory(val plugin: FX3DPlugin) : FX3DFactory<SolidReferenceGro
|
|||||||
|
|
||||||
obj.onPropertyChange(plugin.context) { name->
|
obj.onPropertyChange(plugin.context) { name->
|
||||||
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
val referenceChild = obj[childName] ?: error("Reference child with name '$childName' not found")
|
val referenceChild = obj[childName] ?: error("Reference child with name '$childName' not found")
|
||||||
val child = node.findChild(childName) ?: error("Object child with name '$childName' not found")
|
val child = node.findChild(childName) ?: error("Object child with name '$childName' not found")
|
||||||
|
@ -5,7 +5,6 @@ import javafx.beans.binding.*
|
|||||||
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.names.startsWith
|
import space.kscience.dataforge.names.startsWith
|
||||||
import space.kscience.dataforge.names.toName
|
|
||||||
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.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
@ -15,7 +14,7 @@ import tornadofx.*
|
|||||||
* A caching binding collection for [Vision] properties
|
* A caching binding collection for [Vision] properties
|
||||||
*/
|
*/
|
||||||
public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vision) {
|
public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vision) {
|
||||||
private val bindings = HashMap<Name, ObjectBinding<MetaItem?>>()
|
private val bindings = HashMap<Name, ObjectBinding<Meta?>>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
obj.onPropertyChange(fx.context) { name ->
|
obj.onPropertyChange(fx.context) { name ->
|
||||||
@ -33,30 +32,29 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public operator fun get(key: Name): ObjectBinding<MetaItem?> {
|
public operator fun get(key: Name): ObjectBinding<Meta?> {
|
||||||
return bindings.getOrPut(key) {
|
return bindings.getOrPut(key) {
|
||||||
object : ObjectBinding<MetaItem?>() {
|
object : ObjectBinding<Meta?>() {
|
||||||
override fun computeValue(): MetaItem? = obj.getProperty(key)
|
override fun computeValue(): Meta? = obj.getProperty(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public operator fun get(key: String) = get(key.toName())
|
public operator fun get(key: String): ObjectBinding<Meta?> = get(Name.parse(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun ObjectBinding<MetaItem?>.value(): Binding<Value?> = objectBinding { it.value }
|
public fun ObjectBinding<Meta?>.value(): Binding<Value?> = objectBinding { it?.value }
|
||||||
public fun ObjectBinding<MetaItem?>.string(): StringBinding = stringBinding { it.string }
|
public fun ObjectBinding<Meta?>.string(): StringBinding = stringBinding { it.string }
|
||||||
public fun ObjectBinding<MetaItem?>.number(): Binding<Number?> = objectBinding { it.number }
|
public fun ObjectBinding<Meta?>.number(): Binding<Number?> = objectBinding { it.number }
|
||||||
public fun ObjectBinding<MetaItem?>.double(): Binding<Double?> = objectBinding { it.double }
|
public fun ObjectBinding<Meta?>.double(): Binding<Double?> = objectBinding { it.double }
|
||||||
public fun ObjectBinding<MetaItem?>.float(): Binding<Float?> = objectBinding { it.float }
|
public fun ObjectBinding<Meta?>.float(): Binding<Float?> = objectBinding { it.float }
|
||||||
public fun ObjectBinding<MetaItem?>.int(): Binding<Int?> = objectBinding { it.int }
|
public fun ObjectBinding<Meta?>.int(): Binding<Int?> = objectBinding { it.int }
|
||||||
public fun ObjectBinding<MetaItem?>.long(): Binding<Long?> = objectBinding { it.long }
|
public fun ObjectBinding<Meta?>.long(): Binding<Long?> = objectBinding { it.long }
|
||||||
public fun ObjectBinding<MetaItem?>.node(): Binding<Meta?> = objectBinding { it.node }
|
|
||||||
|
|
||||||
public fun ObjectBinding<MetaItem?>.string(default: String): StringBinding = stringBinding { it.string ?: default }
|
public fun ObjectBinding<Meta?>.string(default: String): StringBinding = stringBinding { it.string ?: default }
|
||||||
public fun ObjectBinding<MetaItem?>.double(default: Double): DoubleBinding = doubleBinding { it.double ?: default }
|
public fun ObjectBinding<Meta?>.double(default: Double): DoubleBinding = doubleBinding { it.double ?: default }
|
||||||
public fun ObjectBinding<MetaItem?>.float(default: Float): FloatBinding = floatBinding { it.float ?: default }
|
public fun ObjectBinding<Meta?>.float(default: Float): FloatBinding = floatBinding { it.float ?: default }
|
||||||
public fun ObjectBinding<MetaItem?>.int(default: Int): IntegerBinding = integerBinding { it.int ?: default }
|
public fun ObjectBinding<Meta?>.int(default: Int): IntegerBinding = integerBinding { it.int ?: default }
|
||||||
public fun ObjectBinding<MetaItem?>.long(default: Long): LongBinding = longBinding { it.long ?: default }
|
public fun ObjectBinding<Meta?>.long(default: Long): LongBinding = longBinding { it.long ?: default }
|
||||||
|
|
||||||
public fun <T> ObjectBinding<MetaItem?>.transform(transform: (MetaItem) -> T): Binding<T?> = objectBinding { it?.let(transform) }
|
public fun <T> ObjectBinding<Meta?>.transform(transform: (Meta) -> T): Binding<T?> = objectBinding { it?.let(transform) }
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package space.kscience.visionforge.gdml
|
package space.kscience.visionforge.gdml
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MetaBuilder
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
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.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.toName
|
|
||||||
import space.kscience.gdml.*
|
import space.kscience.gdml.*
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.html.VisionOutput
|
import space.kscience.visionforge.html.VisionOutput
|
||||||
@ -41,8 +41,8 @@ public class GdmlTransformer {
|
|||||||
|
|
||||||
internal val styleCache = HashMap<Name, Meta>()
|
internal val styleCache = HashMap<Name, Meta>()
|
||||||
|
|
||||||
public fun Solid.registerAndUseStyle(name: String, builder: MetaBuilder.() -> Unit) {
|
public fun Solid.registerAndUseStyle(name: String, builder: MutableMeta.() -> Unit) {
|
||||||
styleCache.getOrPut(name.toName()) {
|
styleCache.getOrPut(Name.parse(name)) {
|
||||||
Meta(builder)
|
Meta(builder)
|
||||||
}
|
}
|
||||||
useStyle(name)
|
useStyle(name)
|
||||||
@ -118,7 +118,7 @@ private class GdmlTransformerEnv(val settings: GdmlTransformer) {
|
|||||||
private val proto = SolidGroup()
|
private val proto = SolidGroup()
|
||||||
|
|
||||||
private val solids = proto.group(solidsName) {
|
private val solids = proto.group(solidsName) {
|
||||||
setProperty("edges.enabled", false)
|
setPropertyNode("edges.enabled", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val referenceStore = HashMap<Name, MutableList<SolidReferenceGroup>>()
|
private val referenceStore = HashMap<Name, MutableList<SolidReferenceGroup>>()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package space.kscience.visionforge.gdml
|
package space.kscience.visionforge.gdml
|
||||||
|
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.gdml.*
|
import space.kscience.gdml.*
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.get
|
import space.kscience.visionforge.get
|
||||||
@ -23,7 +23,7 @@ class TestCubes {
|
|||||||
fun testCubesDirect() {
|
fun testCubesDirect() {
|
||||||
val vision = cubes.toVision()
|
val vision = cubes.toVision()
|
||||||
// println(Solids.encodeToString(vision))
|
// println(Solids.encodeToString(vision))
|
||||||
val smallBoxPrototype = vision.getPrototype("solids.smallBox".toName()) as? Box
|
val smallBoxPrototype = vision.getPrototype(Name.parse("solids.smallBox")) as? Box
|
||||||
assertNotNull(smallBoxPrototype)
|
assertNotNull(smallBoxPrototype)
|
||||||
assertEquals(30.0, smallBoxPrototype.xSize.toDouble())
|
assertEquals(30.0, smallBoxPrototype.xSize.toDouble())
|
||||||
val smallBoxVision = vision["composite-111.smallBox"]?.unref as? Box
|
val smallBoxVision = vision["composite-111.smallBox"]?.unref as? Box
|
||||||
@ -46,7 +46,7 @@ class TestCubes {
|
|||||||
val vision = cubes.toVision()
|
val vision = cubes.toVision()
|
||||||
val serialized = Solids.encodeToString(vision)
|
val serialized = Solids.encodeToString(vision)
|
||||||
val deserialized = testContext.visionManager.decodeFromString(serialized) as SolidGroup
|
val deserialized = testContext.visionManager.decodeFromString(serialized) as SolidGroup
|
||||||
val smallBox = deserialized.getPrototype("solids.smallBox".toName()) as? Box
|
val smallBox = deserialized.getPrototype(Name.parse("solids.smallBox")) as? Box
|
||||||
assertNotNull(smallBox)
|
assertNotNull(smallBox)
|
||||||
assertEquals(30.0, smallBox.xSize.toDouble())
|
assertEquals(30.0, smallBox.xSize.toDouble())
|
||||||
//println(testContext.visionManager.encodeToString(deserialized))
|
//println(testContext.visionManager.encodeToString(deserialized))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package space.kscience.visionforge.gdml
|
package space.kscience.visionforge.gdml
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.gdml.Gdml
|
import space.kscience.gdml.Gdml
|
||||||
import space.kscience.gdml.decodeFromStream
|
import space.kscience.gdml.decodeFromStream
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
@ -23,7 +23,7 @@ class TestConvertor {
|
|||||||
val stream = javaClass.getResourceAsStream("/gdml/cubes.gdml")!!
|
val stream = javaClass.getResourceAsStream("/gdml/cubes.gdml")!!
|
||||||
val gdml = Gdml.decodeFromStream(stream)
|
val gdml = Gdml.decodeFromStream(stream)
|
||||||
val vision = gdml.toVision()
|
val vision = gdml.toVision()
|
||||||
assertNotNull(vision.getPrototype("solids.box".toName()))
|
assertNotNull(vision.getPrototype(Name.parse("solids.box")))
|
||||||
println(Solids.encodeToString(vision))
|
println(Solids.encodeToString(vision))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import kotlinx.serialization.modules.polymorphic
|
|||||||
import kotlinx.serialization.modules.subclass
|
import kotlinx.serialization.modules.subclass
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionBase
|
||||||
import space.kscience.visionforge.setProperty
|
import space.kscience.visionforge.setProperty
|
||||||
@ -27,7 +27,7 @@ public class VisionOfMarkup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val CONTENT_PROPERTY_KEY: Name = "content".toName()
|
public val CONTENT_PROPERTY_KEY: Name = "content".asName()
|
||||||
public const val COMMONMARK_FORMAT: String = "markdown.commonmark"
|
public const val COMMONMARK_FORMAT: String = "markdown.commonmark"
|
||||||
public const val GFM_FORMAT: String = "markdown.gfm"
|
public const val GFM_FORMAT: String = "markdown.gfm"
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("ru.mipt.npm.gradle.mpp")
|
id("ru.mipt.npm.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val plotlyVersion = "0.4.3"
|
val plotlyVersion = "0.5.0-dev-1"
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
useSerialization()
|
useSerialization()
|
||||||
|
@ -2,6 +2,8 @@ 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
|
||||||
@ -13,10 +15,10 @@ import space.kscience.visionforge.root
|
|||||||
@SerialName("vision.plotly")
|
@SerialName("vision.plotly")
|
||||||
public class VisionOfPlotly private constructor() : VisionBase() {
|
public class VisionOfPlotly private constructor() : VisionBase() {
|
||||||
public constructor(plot: Plot) : this() {
|
public constructor(plot: Plot) : this() {
|
||||||
properties = plot.config
|
properties = plot.meta
|
||||||
}
|
}
|
||||||
|
|
||||||
public val plot: Plot get() = Plot(properties ?: Config())
|
public val plot: Plot get() = Plot(properties?.asObservable() ?: MutableMeta())
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
public fun Plot.asVision(): VisionOfPlotly = VisionOfPlotly(this)
|
||||||
|
@ -31,7 +31,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
|||||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||||
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
||||||
val config = PlotlyConfig.read(meta)
|
val config = PlotlyConfig.read(meta)
|
||||||
println(plot.config)
|
println(plot.meta)
|
||||||
println(plot.data[0].toMeta())
|
println(plot.data[0].toMeta())
|
||||||
element.plot(plot, config)
|
element.plot(plot, config)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import space.kscience.dataforge.context.fetch
|
|||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
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.dataforge.names.toName
|
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionChange
|
import space.kscience.visionforge.VisionChange
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
@ -54,12 +53,12 @@ public class VisionServer internal constructor(
|
|||||||
private val application: Application,
|
private val application: Application,
|
||||||
private val rootRoute: String,
|
private val rootRoute: String,
|
||||||
) : Configurable, CoroutineScope by application {
|
) : Configurable, CoroutineScope by application {
|
||||||
override val config: ObservableMeta = ObservableMeta()
|
override val meta: ObservableMutableMeta = MutableMeta()
|
||||||
public var updateInterval: Long by config.long(300, key = UPDATE_INTERVAL_KEY)
|
public var updateInterval: Long by meta.long(300, key = UPDATE_INTERVAL_KEY)
|
||||||
public var cacheFragments: Boolean by config.boolean(true)
|
public var cacheFragments: Boolean by meta.boolean(true)
|
||||||
public var dataEmbed: Boolean by config.boolean(true, "data.embed".toName())
|
public var dataEmbed: Boolean by meta.boolean(true, Name.parse("data.embed"))
|
||||||
public var dataFetch: Boolean by config.boolean(false, "data.fetch".toName())
|
public var dataFetch: Boolean by meta.boolean(false, Name.parse("data.fetch"))
|
||||||
public var dataConnect: Boolean by config.boolean(true, "data.connect".toName())
|
public var dataConnect: Boolean by meta.boolean(true, Name.parse("data.connect"))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a list of headers that should be applied to all pages
|
* a list of headers that should be applied to all pages
|
||||||
@ -131,14 +130,14 @@ public class VisionServer internal constructor(
|
|||||||
?: error("Vision name is not defined in parameters")
|
?: error("Vision name is not defined in parameters")
|
||||||
|
|
||||||
application.log.debug("Opened server socket for $name")
|
application.log.debug("Opened server socket for $name")
|
||||||
val vision: Vision = visions[name.toName()] ?: error("Plot with id='$name' not registered")
|
val vision: Vision = visions[Name.parse(name)] ?: error("Plot with id='$name' not registered")
|
||||||
|
|
||||||
launch {
|
launch {
|
||||||
incoming.consumeEach {
|
incoming.consumeEach {
|
||||||
val change = visionManager.jsonFormat.decodeFromString(
|
val change = visionManager.jsonFormat.decodeFromString(
|
||||||
VisionChange.serializer(), it.data.decodeToString()
|
VisionChange.serializer(), it.data.decodeToString()
|
||||||
)
|
)
|
||||||
vision.update(change)
|
vision.change(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +160,7 @@ public class VisionServer internal constructor(
|
|||||||
val name: String = call.request.queryParameters["name"]
|
val name: String = call.request.queryParameters["name"]
|
||||||
?: error("Vision name is not defined in parameters")
|
?: error("Vision name is not defined in parameters")
|
||||||
|
|
||||||
val vision: Vision? = visions[name.toName()]
|
val vision: Vision? = visions[Name.parse(name)]
|
||||||
if (vision == null) {
|
if (vision == null) {
|
||||||
call.respond(HttpStatusCode.NotFound, "Vision with name '$name' not found")
|
call.respond(HttpStatusCode.NotFound, "Vision with name '$name' not found")
|
||||||
} else {
|
} else {
|
||||||
@ -232,7 +231,7 @@ public class VisionServer internal constructor(
|
|||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public const val DEFAULT_PAGE: String = "/"
|
public const val DEFAULT_PAGE: String = "/"
|
||||||
public val UPDATE_INTERVAL_KEY: Name = "update.interval".toName()
|
public val UPDATE_INTERVAL_KEY: Name = Name.parse("update.interval")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.MutableItemProvider
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.set
|
|
||||||
import space.kscience.dataforge.meta.value
|
|
||||||
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.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
@ -11,11 +9,17 @@ import space.kscience.visionforge.Colors
|
|||||||
import space.kscience.visionforge.VisionBuilder
|
import space.kscience.visionforge.VisionBuilder
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public class ColorAccessor(private val parent: MutableItemProvider, private val colorKey: Name) {
|
public class ColorAccessor(private val parent: MutableMetaProvider, private val colorKey: Name) {
|
||||||
public var value: Value?
|
public var value: Value?
|
||||||
get() = parent.getItem(colorKey).value
|
get() = parent.getMeta(colorKey)?.value
|
||||||
set(value) {
|
set(value) {
|
||||||
parent[colorKey] = value
|
parent.setValue(colorKey,value)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var item: Meta?
|
||||||
|
get() = parent.getMeta(colorKey)
|
||||||
|
set(value) {
|
||||||
|
parent.setMeta(colorKey,value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public inline fun VisionContainerBuilder<Solid>.composite(
|
|||||||
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]).also { composite ->
|
||||||
composite.configure {
|
composite.configure {
|
||||||
update(group.meta)
|
update(group.meta())
|
||||||
}
|
}
|
||||||
if (group.position != null) {
|
if (group.position != null) {
|
||||||
composite.position = group.position
|
composite.position = group.position
|
||||||
|
@ -2,7 +2,8 @@ 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.ObservableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -95,7 +96,7 @@ public class Extruded(
|
|||||||
public class ExtrudeBuilder(
|
public class ExtrudeBuilder(
|
||||||
public var shape: List<Point2D> = emptyList(),
|
public var shape: List<Point2D> = emptyList(),
|
||||||
public var layers: ArrayList<Layer> = ArrayList(),
|
public var layers: ArrayList<Layer> = ArrayList(),
|
||||||
config: ObservableMeta = ObservableMeta()
|
config: ObservableMutableMeta = MutableMeta()
|
||||||
) : SimpleVisionPropertyContainer<Extruded>(config) {
|
) : SimpleVisionPropertyContainer<Extruded>(config) {
|
||||||
public fun shape(block: Shape2DBuilder.() -> Unit) {
|
public fun shape(block: Shape2DBuilder.() -> Unit) {
|
||||||
this.shape = Shape2DBuilder().apply(block).build()
|
this.shape = Shape2DBuilder().apply(block).build()
|
||||||
@ -105,7 +106,7 @@ 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(config) }
|
internal fun build(): Extruded = Extruded(shape, layers).apply { configure(meta()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
|
@ -2,13 +2,12 @@ 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.number
|
|
||||||
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.visionforge.VisionBuilder
|
import space.kscience.visionforge.VisionBuilder
|
||||||
import space.kscience.visionforge.VisionContainerBuilder
|
import space.kscience.visionforge.VisionContainerBuilder
|
||||||
import space.kscience.visionforge.allProperties
|
import space.kscience.visionforge.numberProperty
|
||||||
import space.kscience.visionforge.set
|
import space.kscience.visionforge.set
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -16,8 +15,8 @@ import space.kscience.visionforge.set
|
|||||||
public class PolyLine(public val points: List<Point3D>) : SolidBase(), Solid {
|
public class PolyLine(public val points: List<Point3D>) : SolidBase(), Solid {
|
||||||
|
|
||||||
//var lineType by string()
|
//var lineType by string()
|
||||||
public var thickness: Number by allProperties(inherit = false).number(1.0,
|
public var thickness: Number by numberProperty(name = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY) { 1.0 }
|
||||||
key = SolidMaterial.MATERIAL_KEY + THICKNESS_KEY)
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val THICKNESS_KEY: Name = "thickness".asName()
|
public val THICKNESS_KEY: Name = "thickness".asName()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
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
|
||||||
@ -35,7 +35,7 @@ import kotlin.reflect.KProperty
|
|||||||
*/
|
*/
|
||||||
public interface Solid : Vision {
|
public interface Solid : Vision {
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor get() = Companion.descriptor
|
override val descriptor: MetaDescriptor get() = Companion.descriptor
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
// val SELECTED_KEY = "selected".asName()
|
// val SELECTED_KEY = "selected".asName()
|
||||||
@ -69,39 +69,38 @@ public interface Solid : Vision {
|
|||||||
public val Y_SCALE_KEY: Name = SCALE_KEY + Y_KEY
|
public val Y_SCALE_KEY: Name = SCALE_KEY + Y_KEY
|
||||||
public val Z_SCALE_KEY: Name = SCALE_KEY + Z_KEY
|
public val Z_SCALE_KEY: Name = SCALE_KEY + Z_KEY
|
||||||
|
|
||||||
public val descriptor: NodeDescriptor by lazy {
|
public val descriptor: MetaDescriptor by lazy {
|
||||||
NodeDescriptor {
|
MetaDescriptor {
|
||||||
value(VISIBLE_KEY) {
|
value(VISIBLE_KEY, ValueType.BOOLEAN) {
|
||||||
inherited = false
|
inherited = false
|
||||||
type(ValueType.BOOLEAN)
|
|
||||||
default(true)
|
default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO replace by descriptor merge
|
//TODO replace by descriptor merge
|
||||||
value(Vision.STYLE_KEY) {
|
value(Vision.STYLE_KEY, ValueType.STRING) {
|
||||||
type(ValueType.STRING)
|
|
||||||
multiple = true
|
multiple = true
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
node(POSITION_KEY){
|
node(POSITION_KEY) {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
node(ROTATION_KEY){
|
node(ROTATION_KEY) {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
node(SCALE_KEY){
|
node(SCALE_KEY) {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
value(DETAIL_KEY) {
|
value(DETAIL_KEY, ValueType.NUMBER) {
|
||||||
type(ValueType.NUMBER)
|
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
item(SolidMaterial.MATERIAL_KEY.toString(), SolidMaterial.descriptor)
|
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()
|
||||||
@ -115,7 +114,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() = allProperties().getItem(LAYER_KEY).int ?: 0
|
get() = getProperty(LAYER_KEY, inherit = true).int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(LAYER_KEY, value)
|
setProperty(LAYER_KEY, value)
|
||||||
}
|
}
|
||||||
@ -136,7 +135,7 @@ public enum class RotationOrder {
|
|||||||
*/
|
*/
|
||||||
public var Solid.rotationOrder: RotationOrder
|
public var Solid.rotationOrder: RotationOrder
|
||||||
get() = getProperty(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
|
get() = getProperty(Solid.ROTATION_ORDER_KEY).enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||||
set(value) = setProperty(Solid.ROTATION_ORDER_KEY, value.name.asValue())
|
set(value) = setPropertyValue(Solid.ROTATION_ORDER_KEY, value.name.asValue())
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,7 +143,7 @@ public var Solid.rotationOrder: RotationOrder
|
|||||||
*/
|
*/
|
||||||
public var Solid.detail: Int?
|
public var Solid.detail: Int?
|
||||||
get() = getProperty(DETAIL_KEY, false).int
|
get() = getProperty(DETAIL_KEY, false).int
|
||||||
set(value) = setProperty(DETAIL_KEY, value?.asValue())
|
set(value) = setPropertyValue(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.
|
||||||
@ -152,7 +151,7 @@ public var Solid.detail: Int?
|
|||||||
*/
|
*/
|
||||||
public var Vision.ignore: Boolean?
|
public var Vision.ignore: Boolean?
|
||||||
get() = getProperty(IGNORE_KEY, false).boolean
|
get() = getProperty(IGNORE_KEY, false).boolean
|
||||||
set(value) = setProperty(IGNORE_KEY, value?.asValue())
|
set(value) = setPropertyValue(IGNORE_KEY, value?.asValue())
|
||||||
|
|
||||||
//var VisualObject.selected: Boolean?
|
//var VisualObject.selected: Boolean?
|
||||||
// get() = getProperty(SELECTED_KEY).boolean
|
// get() = getProperty(SELECTED_KEY).boolean
|
||||||
@ -182,7 +181,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.setProperty(name, null)
|
thisRef.setPropertyNode(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)
|
||||||
|
@ -2,17 +2,17 @@ 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.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.visionforge.VisionBase
|
import space.kscience.visionforge.VisionBase
|
||||||
import space.kscience.visionforge.VisionChange
|
import space.kscience.visionforge.VisionChange
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("solid")
|
@SerialName("solid")
|
||||||
public open class SolidBase : VisionBase(), Solid {
|
public open class SolidBase : VisionBase(), Solid {
|
||||||
override val descriptor: NodeDescriptor get() = Solid.descriptor
|
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
override fun change(change: VisionChange) {
|
||||||
updatePosition(change.properties)
|
updatePosition(change.properties)
|
||||||
super.update(change)
|
super.change(change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +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.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
@ -40,7 +40,7 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor get() = Solid.descriptor
|
override val descriptor: MetaDescriptor get() = Solid.descriptor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a prototype redirecting the request to the parent if prototype is not found.
|
* Get a prototype redirecting the request to the parent if prototype is not found.
|
||||||
@ -60,9 +60,9 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
|
|||||||
|
|
||||||
override fun createGroup(): SolidGroup = SolidGroup()
|
override fun createGroup(): SolidGroup = SolidGroup()
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
override fun change(change: VisionChange) {
|
||||||
updatePosition(change.properties)
|
updatePosition(change.properties)
|
||||||
super.update(change)
|
super.change(change)
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.attributes
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
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
|
||||||
@ -26,6 +26,8 @@ public class SolidMaterial : Scheme() {
|
|||||||
*/
|
*/
|
||||||
public val specularColor: ColorAccessor = ColorAccessor(this, SPECULAR_COLOR_KEY)
|
public val specularColor: ColorAccessor = ColorAccessor(this, SPECULAR_COLOR_KEY)
|
||||||
|
|
||||||
|
public val emissiveColor: ColorAccessor = ColorAccessor(this, "emissiveColor".asName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opacity
|
* Opacity
|
||||||
*/
|
*/
|
||||||
@ -48,43 +50,37 @@ public class SolidMaterial : Scheme() {
|
|||||||
public val WIREFRAME_KEY: Name = "wireframe".asName()
|
public val WIREFRAME_KEY: Name = "wireframe".asName()
|
||||||
public val MATERIAL_WIREFRAME_KEY: Name = MATERIAL_KEY + WIREFRAME_KEY
|
public val MATERIAL_WIREFRAME_KEY: Name = MATERIAL_KEY + WIREFRAME_KEY
|
||||||
|
|
||||||
public override val descriptor: NodeDescriptor by lazy {
|
public override val descriptor: MetaDescriptor by lazy {
|
||||||
//must be lazy to avoid initialization bug
|
//must be lazy to avoid initialization bug
|
||||||
NodeDescriptor {
|
MetaDescriptor {
|
||||||
inherited = true
|
inherited = true
|
||||||
usesStyles = true
|
usesStyles = true
|
||||||
|
|
||||||
value(COLOR_KEY) {
|
value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
|
||||||
inherited = true
|
inherited = true
|
||||||
usesStyles = true
|
usesStyles = true
|
||||||
type(ValueType.STRING, ValueType.NUMBER)
|
|
||||||
widgetType = "color"
|
widgetType = "color"
|
||||||
}
|
}
|
||||||
|
|
||||||
value(SPECULAR_COLOR_KEY) {
|
value(SPECULAR_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
|
||||||
inherited = true
|
inherited = true
|
||||||
usesStyles = true
|
usesStyles = true
|
||||||
type(ValueType.STRING, ValueType.NUMBER)
|
|
||||||
widgetType = "color"
|
widgetType = "color"
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
value(OPACITY_KEY) {
|
value(OPACITY_KEY, ValueType.NUMBER) {
|
||||||
inherited = true
|
inherited = true
|
||||||
usesStyles = true
|
usesStyles = true
|
||||||
type(ValueType.NUMBER)
|
|
||||||
default(1.0)
|
default(1.0)
|
||||||
attributes {
|
attributes["min"] = 0.0
|
||||||
this["min"] = 0.0
|
attributes["max"] = 1.0
|
||||||
this["max"] = 1.0
|
attributes["step"] = 0.1
|
||||||
this["step"] = 0.1
|
|
||||||
}
|
|
||||||
widgetType = "slider"
|
widgetType = "slider"
|
||||||
}
|
}
|
||||||
value(WIREFRAME_KEY) {
|
value(WIREFRAME_KEY, ValueType.BOOLEAN) {
|
||||||
inherited = true
|
inherited = true
|
||||||
usesStyles = true
|
usesStyles = true
|
||||||
type(ValueType.BOOLEAN)
|
|
||||||
default(false)
|
default(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,21 +90,23 @@ public class SolidMaterial : Scheme() {
|
|||||||
|
|
||||||
public val Solid.color: ColorAccessor
|
public val Solid.color: ColorAccessor
|
||||||
get() = ColorAccessor(
|
get() = ColorAccessor(
|
||||||
allProperties(inherit = true),
|
meta(inherit = true),
|
||||||
MATERIAL_COLOR_KEY
|
MATERIAL_COLOR_KEY
|
||||||
)
|
)
|
||||||
|
|
||||||
public var Solid.material: SolidMaterial?
|
public var Solid.material: SolidMaterial?
|
||||||
get() = getProperty(MATERIAL_KEY, inherit = true).node?.let { SolidMaterial.read(it) }
|
get() = getProperty(MATERIAL_KEY, inherit = true)?.let { SolidMaterial.read(it) }
|
||||||
set(value) = setProperty(MATERIAL_KEY, value?.rootNode)
|
set(value) = setPropertyNode(MATERIAL_KEY, value?.meta)
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
|
||||||
ownProperties.getChild(MATERIAL_KEY).update(SolidMaterial, builder)
|
configure(MATERIAL_KEY){
|
||||||
|
updateWith(SolidMaterial,builder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var Solid.opacity: Number?
|
public var Solid.opacity: Number?
|
||||||
get() = getProperty(MATERIAL_OPACITY_KEY, inherit = true).number
|
get() = getProperty(MATERIAL_OPACITY_KEY, inherit = true).number
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(MATERIAL_OPACITY_KEY, value?.asValue())
|
setPropertyValue(MATERIAL_OPACITY_KEY, value?.asValue())
|
||||||
}
|
}
|
@ -4,11 +4,11 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.mapNotNull
|
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.MetaItem
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.asMetaItem
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
|
import space.kscience.dataforge.values.Value
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ private fun SolidReference.getRefProperty(
|
|||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
|
): Meta? = if (!inherit && !includeStyles && !includeDefaults) {
|
||||||
getOwnProperty(name)
|
getOwnProperty(name)
|
||||||
} else {
|
} else {
|
||||||
buildList {
|
buildList {
|
||||||
@ -88,9 +88,9 @@ public class SolidReferenceGroup(
|
|||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): MetaItem? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
): Meta? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor get() = prototype.descriptor
|
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,11 +118,15 @@ public class SolidReferenceGroup(
|
|||||||
ReferenceChild(owner, refName + key.asName())
|
ReferenceChild(owner, refName + key.asName())
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
|
|
||||||
override fun getOwnProperty(name: Name): MetaItem? =
|
override fun getOwnProperty(name: Name): Meta? =
|
||||||
owner.getOwnProperty(childPropertyName(refName, name))
|
owner.getOwnProperty(childPropertyName(refName, name))
|
||||||
|
|
||||||
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
|
override fun setPropertyNode(name: Name, node: Meta?, notify: Boolean) {
|
||||||
owner.setProperty(childPropertyName(refName, name), item, notify)
|
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(
|
override fun getProperty(
|
||||||
@ -130,7 +134,7 @@ public class SolidReferenceGroup(
|
|||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): MetaItem? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
): Meta? = getRefProperty(name, inherit, includeStyles, includeDefaults)
|
||||||
|
|
||||||
override var parent: VisionGroup?
|
override var parent: VisionGroup?
|
||||||
get() {
|
get() {
|
||||||
@ -155,13 +159,13 @@ public class SolidReferenceGroup(
|
|||||||
owner.invalidateProperty(childPropertyName(refName, propertyName))
|
owner.invalidateProperty(childPropertyName(refName, propertyName))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(change: VisionChange) {
|
override fun change(change: VisionChange) {
|
||||||
change.properties?.let {
|
change.properties?.let {
|
||||||
updateProperties(Name.EMPTY, it.asMetaItem())
|
updateProperties(Name.EMPTY, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor get() = prototype.descriptor
|
override val descriptor: MetaDescriptor get() = prototype.descriptor
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +188,7 @@ public fun SolidGroup.ref(
|
|||||||
public fun SolidGroup.ref(
|
public fun SolidGroup.ref(
|
||||||
name: String,
|
name: String,
|
||||||
obj: Solid,
|
obj: Solid,
|
||||||
templateName: Name = name.toName(),
|
templateName: Name = Name.parse(name),
|
||||||
): SolidReferenceGroup {
|
): SolidReferenceGroup {
|
||||||
val existing = getPrototype(templateName)
|
val existing = getPrototype(templateName)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
|
@ -95,13 +95,13 @@ public fun MutablePoint3D.normalizeInPlace() {
|
|||||||
z /= norm
|
z /= norm
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ItemProvider.point3D(default: Float = 0f) = object : Point3D {
|
internal fun MetaProvider.point3D(default: Float = 0f) = object : Point3D {
|
||||||
override val x: Float by float(default)
|
override val x: Float by float(default)
|
||||||
override val y: Float by float(default)
|
override val y: Float by float(default)
|
||||||
override val z: Float by float(default)
|
override val z: Float by float(default)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Point3D.toMeta(): MetaBuilder = Meta {
|
public fun Point3D.toMeta(): Meta = Meta {
|
||||||
X_KEY put x
|
X_KEY put x
|
||||||
Y_KEY put y
|
Y_KEY put y
|
||||||
Z_KEY put z
|
Z_KEY put z
|
||||||
@ -115,7 +115,7 @@ internal fun Meta.toVector(default: Float = 0f) = Point3D(
|
|||||||
)
|
)
|
||||||
|
|
||||||
internal fun Solid.updatePosition(meta: Meta?) {
|
internal fun Solid.updatePosition(meta: Meta?) {
|
||||||
meta[Solid.POSITION_KEY].node?.toVector()?.let { position = it }
|
meta?.get(Solid.POSITION_KEY)?.toVector()?.let { position = it }
|
||||||
meta[Solid.ROTATION_KEY].node?.toVector()?.let { rotation = it }
|
meta?.get(Solid.ROTATION_KEY)?.toVector()?.let { rotation = it }
|
||||||
meta[Solid.SCALE_KEY].node?.toVector(1f)?.let { scale = it }
|
meta?.get(Solid.SCALE_KEY)?.toVector(1f)?.let { scale = it }
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ 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.boolean
|
import space.kscience.dataforge.meta.boolean
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.double
|
import space.kscience.dataforge.meta.double
|
||||||
import space.kscience.visionforge.value
|
import space.kscience.visionforge.value
|
||||||
|
|
||||||
@ -16,8 +16,8 @@ public class Axes : Scheme() {
|
|||||||
public const val AXIS_SIZE: Double = 1000.0
|
public const val AXIS_SIZE: Double = 1000.0
|
||||||
public const val AXIS_WIDTH: Double = 3.0
|
public const val AXIS_WIDTH: Double = 3.0
|
||||||
|
|
||||||
override val descriptor: NodeDescriptor by lazy {
|
override val descriptor: MetaDescriptor by lazy {
|
||||||
NodeDescriptor {
|
MetaDescriptor {
|
||||||
value(Axes::visible){
|
value(Axes::visible){
|
||||||
default(false)
|
default(false)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ 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.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
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 space.kscience.visionforge.value
|
||||||
@ -27,8 +27,8 @@ 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: NodeDescriptor by lazy {
|
override val descriptor: MetaDescriptor by lazy {
|
||||||
NodeDescriptor {
|
MetaDescriptor {
|
||||||
value(Camera::fov){
|
value(Camera::fov){
|
||||||
default(FIELD_OF_VIEW)
|
default(FIELD_OF_VIEW)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package space.kscience.visionforge.solid.specifications
|
package space.kscience.visionforge.solid.specifications
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.attributes
|
|
||||||
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
|
||||||
@ -16,30 +15,26 @@ public class Clipping : Scheme() {
|
|||||||
public var z: Double? by double()
|
public var z: Double? by double()
|
||||||
|
|
||||||
public companion object : SchemeSpec<Clipping>(::Clipping) {
|
public companion object : SchemeSpec<Clipping>(::Clipping) {
|
||||||
override val descriptor: NodeDescriptor = NodeDescriptor {
|
override val descriptor: MetaDescriptor = MetaDescriptor {
|
||||||
value(Clipping::x) {
|
value(Clipping::x) {
|
||||||
widgetType = "range"
|
widgetType = "range"
|
||||||
attributes {
|
attributes["min"] = 0.0
|
||||||
set("min", 0.0)
|
attributes["max"] = 1.0
|
||||||
set("max", 1.0)
|
attributes["step"] = 0.01
|
||||||
set("step", 0.01)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
value(Clipping::y) {
|
value(Clipping::y) {
|
||||||
widgetType = "range"
|
widgetType = "range"
|
||||||
attributes {
|
attributes["min"] = 0.0
|
||||||
set("min", 0.0)
|
attributes["max"] = 1.0
|
||||||
set("max", 1.0)
|
attributes["step"] = 0.01
|
||||||
set("step", 0.01)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
value(Clipping::z) {
|
value(Clipping::z) {
|
||||||
widgetType = "range"
|
widgetType = "range"
|
||||||
attributes {
|
attributes["min"] = 0.0
|
||||||
set("min", 0.0)
|
attributes["max"] = 1.0
|
||||||
set("max", 1.0)
|
attributes["step"] = 0.01
|
||||||
set("step", 0.01)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +50,7 @@ public class CanvasSize : Scheme() {
|
|||||||
public var maxHeight: Number by number { maxSize }
|
public var maxHeight: Number by number { maxSize }
|
||||||
|
|
||||||
public companion object : SchemeSpec<CanvasSize>(::CanvasSize) {
|
public companion object : SchemeSpec<CanvasSize>(::CanvasSize) {
|
||||||
override val descriptor: NodeDescriptor = NodeDescriptor {
|
override val descriptor: MetaDescriptor = MetaDescriptor {
|
||||||
value(CanvasSize::minSize)
|
value(CanvasSize::minSize)
|
||||||
value(CanvasSize::minWith)
|
value(CanvasSize::minWith)
|
||||||
value(CanvasSize::minHeight)
|
value(CanvasSize::minHeight)
|
||||||
@ -82,8 +77,8 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
|
|
||||||
|
|
||||||
public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions) {
|
public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions) {
|
||||||
override val descriptor: NodeDescriptor by lazy {
|
override val descriptor: MetaDescriptor by lazy {
|
||||||
NodeDescriptor {
|
MetaDescriptor {
|
||||||
scheme(Canvas3DOptions::axes, Axes)
|
scheme(Canvas3DOptions::axes, Axes)
|
||||||
scheme(Canvas3DOptions::light, Light)
|
scheme(Canvas3DOptions::light, Light)
|
||||||
|
|
||||||
@ -104,7 +99,7 @@ public class Canvas3DOptions : Scheme() {
|
|||||||
multiple = true
|
multiple = true
|
||||||
default(listOf(0))
|
default(listOf(0))
|
||||||
widgetType = "multiSelect"
|
widgetType = "multiSelect"
|
||||||
allow(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
allowedValues(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
}
|
}
|
||||||
scheme(Canvas3DOptions::clipping, Clipping)
|
scheme(Canvas3DOptions::clipping, Clipping)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package space.kscience.visionforge.solid.transform
|
package space.kscience.visionforge.solid.transform
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.itemSequence
|
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
|
||||||
import space.kscience.visionforge.MutableVisionGroup
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.Vision
|
|
||||||
import space.kscience.visionforge.VisionGroup
|
|
||||||
import space.kscience.visionforge.meta
|
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
|
|
||||||
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
|
private operator fun Number.plus(other: Number) = toFloat() + other.toFloat()
|
||||||
@ -24,10 +21,8 @@ internal fun Vision.updateFrom(other: Vision): Vision {
|
|||||||
scaleX *= other.scaleX
|
scaleX *= other.scaleX
|
||||||
scaleY *= other.scaleY
|
scaleY *= other.scaleY
|
||||||
scaleZ *= other.scaleZ
|
scaleZ *= other.scaleZ
|
||||||
other.meta.itemSequence().forEach { (name, item) ->
|
configure{
|
||||||
if (getProperty(name) == null) {
|
update(other.meta())
|
||||||
setProperty(name, item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.MetaItemNode
|
|
||||||
import space.kscience.dataforge.meta.getIndexed
|
import space.kscience.dataforge.meta.getIndexed
|
||||||
import space.kscience.dataforge.meta.node
|
import space.kscience.dataforge.meta.node
|
||||||
import space.kscience.dataforge.meta.toMetaItem
|
import space.kscience.dataforge.meta.toMeta
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -29,9 +28,9 @@ class ConvexTest {
|
|||||||
val convex = group.children.values.first() as Convex
|
val convex = group.children.values.first() as Convex
|
||||||
|
|
||||||
val json = Solids.jsonForSolids.encodeToJsonElement(Convex.serializer(), convex)
|
val json = Solids.jsonForSolids.encodeToJsonElement(Convex.serializer(), convex)
|
||||||
val meta = json.toMetaItem().node!!
|
val meta = json.toMeta()
|
||||||
|
|
||||||
val points = meta.getIndexed("points").values.map { (it as MetaItemNode<*>).node.point3D() }
|
val points = meta.getIndexed("points").values.map { it.point3D() }
|
||||||
assertEquals(8, points.count())
|
assertEquals(8, points.count())
|
||||||
|
|
||||||
assertEquals(8, convex.points.size)
|
assertEquals(8, convex.points.size)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
import space.kscience.dataforge.values.ValueType
|
import space.kscience.dataforge.values.ValueType
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
@ -16,7 +15,7 @@ class DescriptorTest {
|
|||||||
val axesSize = descriptor["axes.size"]
|
val axesSize = descriptor["axes.size"]
|
||||||
assertNotNull(axesSize)
|
assertNotNull(axesSize)
|
||||||
assertTrue {
|
assertTrue {
|
||||||
ValueType.NUMBER in (axesSize as ValueDescriptor).type!!
|
ValueType.NUMBER in axesSize.valueTypes!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ class PropertyTest {
|
|||||||
fun testInheritedProperty() {
|
fun testInheritedProperty() {
|
||||||
var box: Box? = null
|
var box: Box? = null
|
||||||
val group = SolidGroup().apply {
|
val group = SolidGroup().apply {
|
||||||
setProperty("test", 22)
|
setPropertyNode("test", 22)
|
||||||
group {
|
group {
|
||||||
box = box(100, 100, 100)
|
box = box(100, 100, 100)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package space.kscience.visionforge.solid
|
package space.kscience.visionforge.solid
|
||||||
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.toName
|
|
||||||
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 space.kscience.visionforge.meta
|
||||||
@ -14,7 +13,7 @@ import kotlin.test.assertEquals
|
|||||||
*/
|
*/
|
||||||
fun SolidGroup.refGroup(
|
fun SolidGroup.refGroup(
|
||||||
name: String,
|
name: String,
|
||||||
templateName: Name = name.toName(),
|
templateName: Name = Name.parse(name),
|
||||||
block: MutableVisionGroup.() -> Unit
|
block: MutableVisionGroup.() -> Unit
|
||||||
): SolidReferenceGroup {
|
): SolidReferenceGroup {
|
||||||
val group = SolidGroup().apply(block)
|
val group = SolidGroup().apply(block)
|
||||||
@ -30,10 +29,10 @@ class SerializationTest {
|
|||||||
x = 100
|
x = 100
|
||||||
z = -100
|
z = -100
|
||||||
}
|
}
|
||||||
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
|
||||||
@ -43,10 +42,10 @@ class SerializationTest {
|
|||||||
x = 100
|
x = 100
|
||||||
z = -100
|
z = -100
|
||||||
}
|
}
|
||||||
val group = SolidGroup{
|
val group = SolidGroup {
|
||||||
ref("cube", cube)
|
ref("cube", cube)
|
||||||
refGroup("pg", "pg.content".toName()){
|
refGroup("pg", Name.parse("pg.content")) {
|
||||||
sphere(50){
|
sphere(50) {
|
||||||
x = -100
|
x = -100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,7 +53,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())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,8 +2,9 @@ package space.kscience.visionforge.solid
|
|||||||
|
|
||||||
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.MetaItem
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.toName
|
import space.kscience.dataforge.names.asName
|
||||||
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.visionforge.VisionChange
|
import space.kscience.visionforge.VisionChange
|
||||||
import space.kscience.visionforge.get
|
import space.kscience.visionforge.get
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -24,10 +25,10 @@ class VisionUpdateTest {
|
|||||||
color(123)
|
color(123)
|
||||||
box(100,100,100)
|
box(100,100,100)
|
||||||
}
|
}
|
||||||
propertyChanged("top".toName(), SolidMaterial.MATERIAL_COLOR_KEY, MetaItem.of("red"))
|
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
propertyChanged("origin".toName(), SolidMaterial.MATERIAL_COLOR_KEY, MetaItem.of("red"))
|
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
}
|
}
|
||||||
targetVision.update(dif)
|
targetVision.change(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
|
||||||
@ -40,8 +41,8 @@ class VisionUpdateTest {
|
|||||||
color(123)
|
color(123)
|
||||||
box(100,100,100)
|
box(100,100,100)
|
||||||
}
|
}
|
||||||
propertyChanged("top".toName(), SolidMaterial.MATERIAL_COLOR_KEY, MetaItem.of("red"))
|
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
propertyChanged("origin".toName(), SolidMaterial.MATERIAL_COLOR_KEY, MetaItem.of("red"))
|
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
|
||||||
}
|
}
|
||||||
val serialized = visionManager.jsonFormat.encodeToString(VisionChange.serializer(), change)
|
val serialized = visionManager.jsonFormat.encodeToString(VisionChange.serializer(), change)
|
||||||
println(serialized)
|
println(serialized)
|
||||||
|
@ -90,7 +90,7 @@ public fun Mesh.applyEdges(obj: Solid) {
|
|||||||
MeshThreeFactory.EDGES_MATERIAL_KEY,
|
MeshThreeFactory.EDGES_MATERIAL_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
includeStyles = true
|
includeStyles = true
|
||||||
).node,
|
),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
if (edges == null) {
|
if (edges == null) {
|
||||||
|
@ -168,10 +168,10 @@ public class ThreeCanvas(
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Clipping planes
|
//Clipping planes
|
||||||
options.onChange(this@ThreeCanvas) { name, _, _ ->
|
options.meta.onChange(this@ThreeCanvas) { name->
|
||||||
if (name.startsWith(Canvas3DOptions::clipping.name.asName())) {
|
if (name.startsWith(Canvas3DOptions::clipping.name.asName())) {
|
||||||
val clipping = options.clipping
|
val clipping = options.clipping
|
||||||
if (!clipping.isEmpty()) {
|
if (!clipping.meta.isEmpty()) {
|
||||||
renderer.localClippingEnabled = true
|
renderer.localClippingEnabled = true
|
||||||
boundingBox?.let { boundingBox ->
|
boundingBox?.let { boundingBox ->
|
||||||
val xClippingPlane = clipping.x?.let {
|
val xClippingPlane = clipping.x?.let {
|
||||||
@ -212,9 +212,9 @@ public class ThreeCanvas(
|
|||||||
private fun Object3D.fullName(): Name {
|
private fun Object3D.fullName(): Name {
|
||||||
if (root == null) error("Can't resolve element name without the root")
|
if (root == null) error("Can't resolve element name without the root")
|
||||||
return if (parent == root) {
|
return if (parent == root) {
|
||||||
name.toName()
|
Name.parse(name)
|
||||||
} else {
|
} else {
|
||||||
(parent?.fullName() ?: Name.EMPTY) + name.toName()
|
(parent?.fullName() ?: Name.EMPTY) + Name.parse(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ public class ThreeCanvas(
|
|||||||
private fun buildLight(spec: Light?): info.laht.threekt.lights.Light = AmbientLight(0x404040)
|
private fun buildLight(spec: Light?): info.laht.threekt.lights.Light = AmbientLight(0x404040)
|
||||||
|
|
||||||
private fun addControls(element: Node, controls: Controls) {
|
private fun addControls(element: Node, controls: Controls) {
|
||||||
when (controls["type"].string) {
|
when (controls.meta["type"].string) {
|
||||||
"trackball" -> TrackballControls(camera, element)
|
"trackball" -> TrackballControls(camera, element)
|
||||||
else -> OrbitControls(camera, element)
|
else -> OrbitControls(camera, element)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ 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.dataforge.meta.node
|
|
||||||
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 +19,10 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
|||||||
setFromPoints(Array(obj.points.size) { obj.points[it].toVector() })
|
setFromPoints(Array(obj.points.size) { obj.points[it].toVector() })
|
||||||
}
|
}
|
||||||
|
|
||||||
val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node, true)
|
val material = ThreeMaterials.getLineMaterial(
|
||||||
|
obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
material.linewidth = obj.thickness.toDouble()
|
material.linewidth = obj.thickness.toDouble()
|
||||||
material.color = obj.color.string?.let { Color(it) } ?: DEFAULT_LINE_COLOR
|
material.color = obj.color.string?.let { Color(it) } ?: DEFAULT_LINE_COLOR
|
||||||
|
@ -13,7 +13,7 @@ import space.kscience.dataforge.values.int
|
|||||||
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.Vision
|
||||||
import space.kscience.visionforge.ownProperties
|
import space.kscience.visionforge.meta
|
||||||
import space.kscience.visionforge.solid.SolidMaterial
|
import space.kscience.visionforge.solid.SolidMaterial
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ public object ThreeMaterials {
|
|||||||
private val lineMaterialCache = HashMap<Meta, LineBasicMaterial>()
|
private val lineMaterialCache = HashMap<Meta, LineBasicMaterial>()
|
||||||
|
|
||||||
private fun buildLineMaterial(meta: Meta): LineBasicMaterial = LineBasicMaterial().apply {
|
private fun buildLineMaterial(meta: Meta): LineBasicMaterial = LineBasicMaterial().apply {
|
||||||
color = meta[SolidMaterial.COLOR_KEY]?.getColor() ?: DEFAULT_LINE_COLOR
|
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_LINE_COLOR
|
||||||
opacity = meta[SolidMaterial.OPACITY_KEY].double ?: 1.0
|
opacity = meta[SolidMaterial.OPACITY_KEY].double ?: 1.0
|
||||||
transparent = opacity < 1.0
|
transparent = opacity < 1.0
|
||||||
linewidth = meta["thickness"].double ?: 1.0
|
linewidth = meta["thickness"].double ?: 1.0
|
||||||
@ -59,11 +59,12 @@ public object ThreeMaterials {
|
|||||||
private val materialCache = HashMap<Meta, Material>()
|
private val materialCache = HashMap<Meta, Material>()
|
||||||
|
|
||||||
internal fun buildMaterial(meta: Meta): Material {
|
internal fun buildMaterial(meta: Meta): Material {
|
||||||
|
val material = SolidMaterial.read(meta)
|
||||||
return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor ->
|
return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor ->
|
||||||
MeshPhongMaterial().apply {
|
MeshPhongMaterial().apply {
|
||||||
color = meta[SolidMaterial.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
|
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
|
||||||
specular = specularColor.getColor()
|
specular = specularColor.threeColor()
|
||||||
emissive = specular
|
emissive = material.emissiveColor.item?.threeColor() ?: specular
|
||||||
reflectivity = 0.5
|
reflectivity = 0.5
|
||||||
refractionRatio = 1.0
|
refractionRatio = 1.0
|
||||||
shininess = 100.0
|
shininess = 100.0
|
||||||
@ -73,7 +74,7 @@ public object ThreeMaterials {
|
|||||||
needsUpdate = true
|
needsUpdate = true
|
||||||
}
|
}
|
||||||
} ?: MeshBasicMaterial().apply {
|
} ?: MeshBasicMaterial().apply {
|
||||||
color = meta[SolidMaterial.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
|
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
|
||||||
opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
|
opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
|
||||||
transparent = opacity < 1.0
|
transparent = opacity < 1.0
|
||||||
wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
|
wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
|
||||||
@ -93,22 +94,19 @@ public object ThreeMaterials {
|
|||||||
/**
|
/**
|
||||||
* Infer color based on meta item
|
* Infer color based on meta item
|
||||||
*/
|
*/
|
||||||
public fun MetaItem.getColor(): Color {
|
public fun Meta.threeColor(): Color {
|
||||||
return when (this) {
|
return value?.let { value ->
|
||||||
is MetaItemValue -> if (this.value.type == ValueType.NUMBER) {
|
if (value.type == ValueType.NUMBER) {
|
||||||
val int = value.int
|
val int = value.int
|
||||||
Color(int)
|
Color(int)
|
||||||
} else {
|
} else {
|
||||||
Color(this.value.string)
|
Color(value.string)
|
||||||
}
|
}
|
||||||
is MetaItemNode -> {
|
} ?: Color(
|
||||||
Color(
|
this[Colors.RED_KEY]?.int ?: 0,
|
||||||
node[Colors.RED_KEY]?.int ?: 0,
|
this[Colors.GREEN_KEY]?.int ?: 0,
|
||||||
node[Colors.GREEN_KEY]?.int ?: 0,
|
this[Colors.BLUE_KEY]?.int ?: 0
|
||||||
node[Colors.BLUE_KEY]?.int ?: 0
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var Material.cached: Boolean
|
private var Material.cached: Boolean
|
||||||
@ -119,7 +117,7 @@ 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.ownProperties[SolidMaterial.MATERIAL_KEY]
|
val ownMaterialMeta = vision.meta()[SolidMaterial.MATERIAL_KEY]
|
||||||
val parentMaterialMeta = vision.parent?.getProperty(
|
val parentMaterialMeta = vision.parent?.getProperty(
|
||||||
SolidMaterial.MATERIAL_KEY,
|
SolidMaterial.MATERIAL_KEY,
|
||||||
inherit = true,
|
inherit = true,
|
||||||
@ -135,7 +133,7 @@ public fun Mesh.updateMaterial(vision: Vision) {
|
|||||||
inherit = false,
|
inherit = false,
|
||||||
includeStyles = true,
|
includeStyles = true,
|
||||||
includeDefaults = false
|
includeDefaults = false
|
||||||
).node?.let {
|
)?.let {
|
||||||
ThreeMaterials.cacheMaterial(it)
|
ThreeMaterials.cacheMaterial(it)
|
||||||
} ?: ThreeMaterials.DEFAULT
|
} ?: ThreeMaterials.DEFAULT
|
||||||
}
|
}
|
||||||
@ -143,7 +141,7 @@ public fun Mesh.updateMaterial(vision: Vision) {
|
|||||||
vision.getProperty(
|
vision.getProperty(
|
||||||
SolidMaterial.MATERIAL_KEY,
|
SolidMaterial.MATERIAL_KEY,
|
||||||
inherit = true
|
inherit = true
|
||||||
).node?.let {
|
)?.let {
|
||||||
ThreeMaterials.buildMaterial(it)
|
ThreeMaterials.buildMaterial(it)
|
||||||
} ?: ThreeMaterials.DEFAULT
|
} ?: ThreeMaterials.DEFAULT
|
||||||
}
|
}
|
||||||
@ -162,7 +160,7 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
|||||||
inherit = true,
|
inherit = true,
|
||||||
includeStyles = true,
|
includeStyles = true,
|
||||||
includeDefaults = false
|
includeDefaults = false
|
||||||
)?.getColor() ?: ThreeMaterials.DEFAULT_COLOR
|
)?.threeColor() ?: ThreeMaterials.DEFAULT_COLOR
|
||||||
material.needsUpdate = true
|
material.needsUpdate = true
|
||||||
}
|
}
|
||||||
SolidMaterial.MATERIAL_OPACITY_KEY -> {
|
SolidMaterial.MATERIAL_OPACITY_KEY -> {
|
||||||
|
@ -143,7 +143,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
element,
|
element,
|
||||||
vision as? Solid ?: error("Solid expected but ${vision::class} found"),
|
vision as? Solid ?: error("Solid expected but ${vision::class} found"),
|
||||||
).apply {
|
).apply {
|
||||||
options.update(meta)
|
options.meta.update(meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +195,4 @@ internal fun Object3D.findChild(name: Name): Object3D? {
|
|||||||
name.length == 1 -> this.children.find { it.name == name.tokens.first().toString() }
|
name.length == 1 -> this.children.find { it.name == name.tokens.first().toString() }
|
||||||
else -> findChild(name.tokens.first().asName())?.findChild(name.cutFirst())
|
else -> findChild(name.tokens.first().asName())?.findChild(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public fun Context.withThreeJs(): Context = apply {
|
|
||||||
plugins.fetch(ThreePlugin)
|
|
||||||
}
|
}
|
@ -3,9 +3,9 @@ package space.kscience.visionforge.solid.three
|
|||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.cutFirst
|
import space.kscience.dataforge.names.cutFirst
|
||||||
import space.kscience.dataforge.names.firstOrNull
|
import space.kscience.dataforge.names.firstOrNull
|
||||||
import space.kscience.dataforge.names.toName
|
|
||||||
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.SolidReferenceGroup
|
import space.kscience.visionforge.solid.SolidReferenceGroup
|
||||||
@ -49,7 +49,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
|
|||||||
|
|
||||||
obj.onPropertyChange(three.updateScope) { name->
|
obj.onPropertyChange(three.updateScope) { name->
|
||||||
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
val childName = name.firstOrNull()?.index?.toName() ?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val propertyName = name.cutFirst()
|
val propertyName = name.cutFirst()
|
||||||
val referenceChild = obj[childName] ?: error("Reference child with name '$childName' not found")
|
val referenceChild = obj[childName] ?: error("Reference child with name '$childName' not found")
|
||||||
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
|
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user