All tests pass

This commit is contained in:
Alexander Nozik 2022-08-12 22:16:06 +03:00
parent 9221df785d
commit 0ea1ee056a
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
77 changed files with 372 additions and 314 deletions

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.project")
id("space.kscience.gradle.project")
// id("org.jetbrains.kotlinx.kover") version "0.5.0"
}

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
kscience{

View File

@ -321,7 +321,7 @@ private fun buildVolume(volume: DGeoVolume, context: RootToSolidContext): Solid?
}
return if (group.children.isEmpty()) {
null
} else if (group.items.size == 1 && group.properties.raw == null) {
} else if (group.items.size == 1 && group.properties.own == null) {
group.items.values.first().apply { parent = null }
} else {
group

View File

@ -1,8 +1,8 @@
import ru.mipt.npm.gradle.DependencyConfiguration
import ru.mipt.npm.gradle.FXModule
import space.kscience.gradle.DependencyConfiguration
import space.kscience.gradle.FXModule
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
application
}
@ -36,7 +36,7 @@ kotlin {
jvmMain {
dependencies {
implementation(project(":visionforge-fx"))
implementation("ch.qos.logback:logback-classic:1.2.5")
implementation("ch.qos.logback:logback-classic:1.2.11")
}
}
jsMain {

View File

@ -6,7 +6,6 @@ import space.kscience.dataforge.names.Name
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Vision
import space.kscience.visionforge.get
import space.kscience.visionforge.getPropertyValue
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.material
@ -20,7 +19,7 @@ class GDMLVisionTest {
@Test
fun testCubesStyles(){
val segment = cubes.children["composite-000.segment-0"] as Solid
println(segment.getPropertyValue(Vision.STYLE_KEY))
println(segment.properties.getValue(Vision.STYLE_KEY))
// println(segment.computePropertyNode(SolidMaterial.MATERIAL_KEY))
// println(segment.computeProperty(SolidMaterial.MATERIAL_COLOR_KEY))
@ -34,7 +33,7 @@ class GDMLVisionTest {
fun testPrototypeProperty() {
val child = cubes[Name.of("composite-000","segment-0")]
assertNotNull(child)
child.setPropertyValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", child.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
child.properties.setValue(SolidMaterial.MATERIAL_COLOR_KEY, "red".asValue())
assertEquals("red", child.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
}
}

View File

@ -26,6 +26,7 @@ import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.set
import styled.css
import styled.styledDiv
@ -56,7 +57,7 @@ val GDMLApp = fc<GDMLAppProps>("GDMLApp") { props ->
console.info("Marking layers for file $name")
markLayers()
ambientLight {
color(Colors.white)
color.set(Colors.white)
}
}
}

View File

@ -10,6 +10,7 @@ import space.kscience.visionforge.Colors
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.react.render
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.set
import space.kscience.visionforge.solid.three.ThreePlugin
import space.kscience.visionforge.startApplication
import styled.injectGlobal
@ -46,7 +47,7 @@ private class GDMLDemoApp : Application {
child(GDMLApp) {
val vision = GdmlShowCase.cubes().toVision().apply {
ambientLight {
color(Colors.white)
color.set(Colors.white)
}
}
//println(context.plugins.fetch(VisionManager).encodeToString(vision))

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.js")
}
kscience{

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
application
}

View File

@ -69,7 +69,7 @@ class Model(val manager: VisionManager) {
fun reset() {
map.values.forEach {
it.properties[SolidMaterial.MATERIAL_COLOR_KEY] = null
it.properties.setProperty(SolidMaterial.MATERIAL_COLOR_KEY, null)
}
tracks.children.clear()
}

View File

@ -25,6 +25,7 @@ import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.tab
import space.kscience.visionforge.solid.ambientLight
import space.kscience.visionforge.solid.set
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.edges
import styled.css
@ -57,7 +58,7 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
props.model.root.apply {
edges()
ambientLight{
color(Colors.white)
color.set(Colors.white)
}
}
}

View File

@ -17,6 +17,7 @@ private class MMDemoApp : Application {
val context = Context("MM-demo") {
plugin(ThreePlugin)
}
val visionManager = context.fetch(VisionManager)
val model = Model(visionManager)

View File

@ -5,7 +5,6 @@
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">-->
<title>Three js demo for particle physics</title>
<script type="text/javascript" src="muon-monitor.js"></script>
<link rel="stylesheet" href="css/custom-bootstrap.css">
</head>
<body class="application">
<div class="container-fluid max-vh-100" id = "app"> </div>

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("space.kscience.gradle.jvm")
application
}

View File

@ -1,8 +1,8 @@
import ru.mipt.npm.gradle.DependencyConfiguration
import ru.mipt.npm.gradle.FXModule
import space.kscience.gradle.DependencyConfiguration
import space.kscience.gradle.FXModule
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
application
}

View File

@ -4,7 +4,6 @@ import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxGeometry
import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.number
import space.kscience.dataforge.names.asName
@ -43,13 +42,13 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
it.layers.enable(this@VariableBox.layer)
}
}
mesh.scale.z = meta[VALUE].number?.toDouble() ?: 1.0
mesh.scale.z = properties.getValue(VALUE)?.number?.toDouble() ?: 1.0
//add listener to object properties
onPropertyChange { name ->
when {
name == VALUE -> {
val value = meta[VALUE].int ?: 0
val value = properties.getValue(VALUE)?.int ?: 0
val size = value.toFloat() / 255f * 20f
mesh.scale.z = size.toDouble()
mesh.position.z = size.toDouble() / 2
@ -69,9 +68,9 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
}
var value: Int
get() = meta[VALUE].int ?: 0
get() = properties.getValue(VALUE)?.int ?: 0
set(value) {
setPropertyValue(VALUE, value.asValue())
properties.setValue(VALUE, value.asValue())
}
companion object {

View File

@ -6,4 +6,4 @@ kotlin.jupyter.add.scanner=false
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4G
toolsVersion=0.11.8-kotlin-1.7.10
toolsVersion=0.12.0-kotlin-1.7.20-Beta

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
id("org.jetbrains.kotlin.jupyter.api")
}
@ -21,5 +21,5 @@ kotlin {
}
readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
}

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
description = "Jupyter api artifact for GDML rendering"
@ -56,5 +56,5 @@ kscience {
}
readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
}

View File

@ -15,10 +15,10 @@ pluginManagement {
}
plugins {
id("ru.mipt.npm.gradle.project") version toolsVersion
id("ru.mipt.npm.gradle.mpp") version toolsVersion
id("ru.mipt.npm.gradle.jvm") version toolsVersion
id("ru.mipt.npm.gradle.js") version toolsVersion
id("space.kscience.gradle.project") version toolsVersion
id("space.kscience.gradle.mpp") version toolsVersion
id("space.kscience.gradle.jvm") version toolsVersion
id("space.kscience.gradle.js") version toolsVersion
}
}
@ -34,7 +34,7 @@ dependencyResolutionManagement {
versionCatalogs {
create("npmlibs") {
from("ru.mipt.npm:version-catalog:$toolsVersion")
from("space.kscience:version-catalog:$toolsVersion")
}
}
}

View File

@ -1,6 +1,6 @@
plugins {
kotlin("js")
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.js")
}
val dataforgeVersion: String by rootProject.extra

View File

@ -1,5 +1,6 @@
package space.kscience.visionforge.bootstrap
import kotlinx.coroutines.GlobalScope
import kotlinx.css.BorderStyle
import kotlinx.css.Color
import kotlinx.css.padding
@ -15,7 +16,6 @@ import react.RBuilder
import react.dom.attrs
import react.dom.button
import react.fc
import space.kscience.dataforge.meta.withDefault
import space.kscience.visionforge.Vision
import space.kscience.visionforge.encodeToString
import space.kscience.visionforge.react.flexColumn
@ -69,8 +69,8 @@ public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { prop
}
}
propertyEditor(
ownProperties = props.canvasOptions.meta,
allProperties = props.canvasOptions.meta.withDefault(Canvas3DOptions.descriptor.defaultNode),
scope = props.vision?.manager?.context ?: GlobalScope,
properties = props.canvasOptions.meta,
descriptor = Canvas3DOptions.descriptor,
expanded = false
)

View File

@ -3,13 +3,16 @@ package space.kscience.visionforge.bootstrap
import org.w3c.dom.Element
import react.RBuilder
import react.dom.client.createRoot
import react.key
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.getStyle
import space.kscience.visionforge.react.EditorPropertyState
import space.kscience.visionforge.react.PropertyEditor
import space.kscience.visionforge.react.metaViewer
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.react.render
import space.kscience.visionforge.root
import space.kscience.visionforge.solid.SolidReference
import space.kscience.visionforge.styles
@ -20,12 +23,25 @@ public fun RBuilder.visionPropertyEditor(
) {
card("Properties") {
propertyEditor(
ownProperties = vision.meta,
allProperties = vision.computeProperties(),
descriptor = descriptor,
key = key
)
child(PropertyEditor){
attrs{
this.key = key?.toString()
this.meta = vision.properties.root()
this.updates = vision.properties.changes
this.descriptor = descriptor
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
this.getPropertyState = {name->
if(vision.properties.own?.get(name)!= null){
EditorPropertyState.Defined
} else if(vision.properties.root()[name] != null){
// TODO differentiate
EditorPropertyState.Default()
} else {
EditorPropertyState.Undefined
}
}
}
}
}
val styles = if (vision is SolidReference) {
(vision.styles + vision.prototype.styles).distinct()

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.js")
}
dependencies{

View File

@ -25,7 +25,7 @@ public val MultiSelectChooser: FC<ValueChooserProps> = fc("MultiSelectChooser")
select {
attrs {
multiple = true
values = (props.actual.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
values = (props.meta.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
onChangeFunction = onChange
}
props.descriptor?.allowedValues?.forEach { optionValue ->

View File

@ -1,13 +1,18 @@
package space.kscience.visionforge.react
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.css.*
import kotlinx.css.properties.TextDecoration
import kotlinx.html.js.onClickFunction
import org.w3c.dom.Element
import org.w3c.dom.events.Event
import react.*
import react.dom.attrs
import react.dom.client.createRoot
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.ValueRequirement
@ -19,17 +24,30 @@ import styled.styledButton
import styled.styledDiv
import styled.styledSpan
/**
* The display state of a property
*/
public sealed class EditorPropertyState {
public object Defined : EditorPropertyState()
public class Default(public val source: String = "unknown") : EditorPropertyState()
public object Undefined : EditorPropertyState()
}
public external interface PropertyEditorProps : Props {
/**
* Root config object - always non-null
*/
public var meta: ObservableMutableMeta
public var meta: MutableMeta
/**
* Provide default item (greyed out if used)
*/
public var withDefault: MetaProvider
public var getPropertyState: (Name) -> EditorPropertyState
public var scope: CoroutineScope
public var updates: Flow<Name>
/**
* Full path to the displayed node in [meta]. Could be empty
@ -54,7 +72,7 @@ private val PropertyEditorItem: FC<PropertyEditorProps> = fc("PropertyEditorItem
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
var expanded: Boolean by useState { props.expanded ?: true }
val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) }
var ownProperty: ObservableMutableMeta by useState { props.meta.getOrCreate(props.name) }
var property: MutableMeta by useState { props.meta.getOrCreate(props.name) }
val keys = useMemo(descriptor) {
buildSet {
@ -70,17 +88,18 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
val token = props.name.lastOrNull()?.toString() ?: "Properties"
fun update() {
ownProperty = props.meta.getOrCreate(props.name)
property = props.meta.getOrCreate(props.name)
}
useEffect(props.meta) {
props.meta.onChange(props) { updatedName ->
val job = props.updates.onEach { updatedName ->
if (updatedName == props.name) {
update()
}
}
}.launchIn(props.scope)
cleanup {
props.meta.removeListener(props)
job.cancel()
}
}
@ -115,7 +134,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
styledSpan {
css {
+TreeStyles.treeLabel
if (ownProperty.isEmpty()) {
if (property.isEmpty()) {
+TreeStyles.treeLabelInactive
}
}
@ -131,8 +150,8 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
ValueChooser {
attrs {
this.descriptor = descriptor
this.meta = ownProperty
this.actual = props.withDefault.getMeta(props.name) ?: ownProperty
this.meta = property
this.state = props.getPropertyState(props.name)
}
}
}
@ -156,7 +175,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
}
+"\u00D7"
attrs {
if (ownProperty.isEmpty()) {
if (property.isEmpty()) {
disabled = true
} else {
onClickFunction = removeClick
@ -179,9 +198,11 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
attrs {
this.key = props.name.toString()
this.meta = props.meta
this.withDefault = props.withDefault
this.name = props.name + token
this.descriptor = props.descriptor
this.scope = props.scope
this.getPropertyState = { props.getPropertyState(props.name + token) }
this.updates = props.updates
}
}
//configEditor(props.root, props.name + token, props.descriptor, props.default)
@ -197,44 +218,51 @@ public val PropertyEditor: FC<PropertyEditorProps> = fc("PropertyEditor") { prop
attrs {
this.key = ""
this.meta = props.meta
this.withDefault = props.withDefault
this.name = Name.EMPTY
this.descriptor = props.descriptor
this.expanded = props.expanded
this.scope = props.scope
this.getPropertyState = props.getPropertyState
this.updates = props.updates
}
}
}
@OptIn(ExperimentalCoroutinesApi::class)
public fun RBuilder.propertyEditor(
ownProperties: ObservableMutableMeta,
allProperties: MetaProvider = ownProperties,
scope: CoroutineScope,
properties: ObservableMutableMeta,
descriptor: MetaDescriptor? = null,
key: Any? = null,
expanded: Boolean? = null,
) {
child(PropertyEditor) {
attrs {
this.meta = ownProperties
this.withDefault = allProperties
this.meta = properties
this.descriptor = descriptor
this.key = key?.toString() ?: ""
this.expanded = expanded
this.scope = scope
this.getPropertyState = { name ->
if (properties[name] != null) {
EditorPropertyState.Defined
} else if (descriptor?.get(name)?.defaultValue != null) {
EditorPropertyState.Default("descriptor")
} else {
EditorPropertyState.Undefined
}
}
this.updates = callbackFlow {
properties.onChange(scope) { name ->
scope.launch {
send(name)
}
}
invokeOnClose {
properties.removeListener(scope)
}
}
}
}
}
public fun RBuilder.configEditor(
config: ObservableMutableMeta,
default: MetaProvider = config,
descriptor: MetaDescriptor? = null,
key: Any? = null,
): Unit = propertyEditor(config, default, descriptor, key = key)
public fun Element.configEditor(
config: ObservableMutableMeta,
default: Meta = config,
descriptor: MetaDescriptor? = null,
key: Any? = null,
): Unit = createRoot(this).render {
configEditor(config, default, descriptor, key = key)
}

View File

@ -20,7 +20,7 @@ import styled.styledInput
@JsExport
public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") { props ->
var innerValue by useState(props.actual.double)
var innerValue by useState(props.meta.double)
var rangeDisabled: Boolean by useState(props.meta.value == null)
val handleDisable: (Event) -> Unit = {

View File

@ -16,6 +16,7 @@ import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.asSequence
import space.kscience.visionforge.isEmpty
import styled.css
import styled.styledDiv
@ -59,9 +60,9 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
val obj = props.obj
//display as node if any child is visible
if (obj is VisionGroup<*>) {
if (obj is VisionGroup) {
flexRow {
if (obj.items.any { !it.key.body.startsWith("@") }) {
if (obj.children.keys.any { !it.body.startsWith("@") }) {
styledSpan {
css {
+TreeStyles.treeCaret
@ -81,9 +82,9 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
css {
+TreeStyles.tree
}
obj.items.entries
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
.sortedBy { (it.value as? VisionGroup<*>)?.isEmpty() ?: true } // ignore empty groups
obj.children.asSequence()
.filter { !it.first.toString().startsWith("@") } // ignore statics and other hidden children
.sortedBy { (it.second as? VisionGroup)?.children?.isEmpty() ?: true } // ignore empty groups
.forEach { (childToken, child) ->
styledDiv {
css {
@ -92,7 +93,7 @@ private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
child(ObjectTree) {
attrs {
this.name = props.name + childToken
this.obj = child.vision
this.obj = child
this.selected = props.selected
this.clickCallback = props.clickCallback
}

View File

@ -27,13 +27,13 @@ import styled.styledSelect
public external interface ValueChooserProps : Props {
public var descriptor: MetaDescriptor?
public var meta: ObservableMutableMeta
public var actual: Meta
public var meta: MutableMeta
public var state: EditorPropertyState
}
@JsExport
public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser") { props ->
var value by useState(props.actual.string ?: "")
var value by useState(props.meta.string ?: "")
val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
value = (event.target as HTMLInputElement).value
@ -67,7 +67,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
}
attrs {
//this.attributes["indeterminate"] = (props.item == null).toString()
checked = props.actual.boolean ?: false
checked = props.meta.boolean ?: false
onChangeFunction = handleChange
}
}
@ -75,7 +75,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
@JsExport
public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser") { props ->
var innerValue by useState(props.actual.string ?: "")
var innerValue by useState(props.meta.string ?: "")
val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
innerValue = (event.target as HTMLInputElement).value
@ -113,7 +113,7 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
@JsExport
public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") { props ->
var selected by useState(props.actual.string ?: "")
var selected by useState(props.meta.string ?: "")
val handleChange: (Event) -> Unit = {
selected = (it.target as HTMLSelectElement).value
props.meta.value = selected.asValue()
@ -128,7 +128,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
}
}
attrs {
this.value = props.actual.string ?: ""
this.value = props.meta.string ?: ""
multiple = false
onChangeFunction = handleChange
}
@ -146,7 +146,7 @@ public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") {
margin(0.px)
}
attrs {
this.value = props.actual.value?.let { value ->
this.value = props.meta.value?.let { value ->
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
else value.string
} ?: "#000000"

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.js")
}
val dataforgeVersion: String by rootProject.extra

View File

@ -9,18 +9,19 @@ import react.dom.div
import react.dom.span
import ringui.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.length
import space.kscience.visionforge.*
import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.Vision
import space.kscience.visionforge.react.*
import space.kscience.visionforge.root
import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.visionManager
import styled.css
import styled.styledDiv
@ -38,7 +39,7 @@ public fun ThreeCanvasWithControlsProps.solid(block: SolidGroup.() -> Unit) {
}
}
public fun ThreeCanvasWithControlsProps.options(block: Canvas3DOptions.() -> Unit){
public fun ThreeCanvasWithControlsProps.options(block: Canvas3DOptions.() -> Unit) {
options = Canvas3DOptions(block)
}
@ -81,14 +82,14 @@ public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): Unit = styled
@JsExport
public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("ThreeViewWithControls") { props ->
var selected by useState { props.selected }
var selected: Name? by useState { props.selected }
var solid: Solid? by useState(null)
useEffect {
props.context.launch {
solid = props.builderOfSolid.await()
//ensure that the solid is properly rooted
if(solid?.parent == null){
if (solid?.parent == null) {
solid?.setAsRoot(props.context.visionManager)
}
}
@ -164,12 +165,25 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
nameCrumbs(selected) { selected = it }
}
IslandContent {
propertyEditor(
ownProperties = vision.properties(),
allProperties = vision.computeProperties(),
descriptor = vision.descriptor,
key = selected
)
child(PropertyEditor) {
attrs {
this.key = selected.toString()
this.meta = vision.properties.root()
this.updates = vision.properties.changes
this.descriptor = vision.descriptor
this.scope = props.context
this.getPropertyState = { name ->
if (vision.properties.own?.get(name) != null) {
EditorPropertyState.Defined
} else if (vision.properties.root()[name] != null) {
// TODO differentiate
EditorPropertyState.Default()
} else {
EditorPropertyState.Undefined
}
}
}
}
}
}
}

View File

@ -4,17 +4,16 @@ import org.w3c.dom.Element
import react.RBuilder
import react.dom.client.createRoot
import react.dom.p
import react.key
import ringui.Island
import ringui.SmartTabs
import ringui.Tab
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get
import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperties
import space.kscience.visionforge.getStyle
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.metaViewer
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.react.render
import space.kscience.visionforge.react.*
import space.kscience.visionforge.root
import space.kscience.visionforge.solid.SolidReference
import space.kscience.visionforge.styles
@ -31,12 +30,25 @@ public fun RBuilder.ringPropertyEditor(
flexColumn {
Island("Properties") {
propertyEditor(
ownProperties = vision.meta,
allProperties = vision.computeProperties(),
descriptor = descriptor,
key = key
)
child(PropertyEditor) {
attrs {
this.key = key?.toString()
this.meta = vision.properties.root()
this.updates = vision.properties.changes
this.descriptor = descriptor
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
this.getPropertyState = {name->
if(vision.properties.own?.get(name)!= null){
EditorPropertyState.Defined
} else if(vision.properties.root()[name] != null){
// TODO differentiate
EditorPropertyState.Default()
} else {
EditorPropertyState.Undefined
}
}
}
}
}
if (styles.isNotEmpty()) {

View File

@ -1,5 +1,6 @@
package space.kscience.visionforge.ring
import kotlinx.coroutines.GlobalScope
import kotlinx.css.BorderStyle
import kotlinx.css.Color
import kotlinx.css.padding
@ -18,7 +19,6 @@ import react.fc
import ringui.Island
import ringui.SmartTabs
import ringui.Tab
import space.kscience.dataforge.meta.withDefault
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.encodeToString
@ -75,8 +75,8 @@ internal val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { pr
}
}
propertyEditor(
ownProperties = props.options.meta,
allProperties = props.options.meta.withDefault(Canvas3DOptions.descriptor.defaultNode),
scope = props.vision?.manager?.context ?: GlobalScope,
properties = props.options.meta,
descriptor = Canvas3DOptions.descriptor,
expanded = false
)

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
val dataforgeVersion: String by rootProject.extra
@ -28,5 +28,5 @@ kscience{
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
maturity = space.kscience.gradle.Maturity.DEVELOPMENT
}

View File

@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline
@JvmInline
public value class StyleSheet(private val owner: Vision) {
private val styleNode: Meta get() = owner.properties[STYLESHEET_KEY]
private val styleNode: Meta get() = owner.properties.getProperty(STYLESHEET_KEY)
public val items: Map<NameToken, Meta> get() = styleNode.items
@ -23,7 +23,7 @@ public value class StyleSheet(private val owner: Vision) {
* Define a style without notifying owner
*/
public fun define(key: String, style: Meta?) {
owner.properties[STYLESHEET_KEY + key] = style
owner.properties.setProperty(STYLESHEET_KEY + key, style)
}
/**
@ -86,7 +86,7 @@ public val Vision.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.
*/
public fun Vision.useStyle(name: String) {
styles = (properties.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
styles = (properties.own?.get(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
}
@ -94,7 +94,7 @@ public fun Vision.useStyle(name: String) {
* Resolve a style with given name for given [Vision]. The style is not necessarily applied to this [Vision].
*/
public fun Vision.getStyle(name: String): Meta? =
properties.raw?.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
properties.own?.getMeta(StyleSheet.STYLESHEET_KEY + name) ?: parent?.getStyle(name)
/**
* Resolve a property from all styles

View File

@ -1,9 +1,9 @@
package space.kscience.visionforge
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.meta.descriptors.Described
@ -30,7 +30,7 @@ public interface Vision : Described {
/**
* Owner [VisionManager]. Used to define coroutine scope a serialization
*/
public val manager: VisionManager get() = parent?.manager ?: Global.visionManager
public val manager: VisionManager? get() = parent?.manager
public val properties: MutableVisionProperties
@ -67,13 +67,17 @@ public var Vision.visible: Boolean?
/**
* Subscribe on property updates. The subscription is bound to the given scope and canceled when the scope is canceled
*/
public fun Vision.onPropertyChange(callback: (Name) -> Unit): Job = properties.changes.onEach {
public fun Vision.onPropertyChange(
scope: CoroutineScope? = manager?.context,
callback: (Name) -> Unit
): Job = properties.changes.onEach {
callback(it)
}.launchIn(manager.context)
}.launchIn(scope ?: error("Orphan Vision can't observe properties"))
public fun <V : Vision, T> V.useProperty(
property: KProperty1<V, T>,
scope: CoroutineScope? = manager?.context,
callBack: V.(T) -> Unit,
): Job {
//Pass initial value.
@ -82,5 +86,5 @@ public fun <V : Vision, T> V.useProperty(
if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty))
}
}.launchIn(manager.context)
}.launchIn(scope ?: error("Orphan Vision can't observe properties"))
}

View File

@ -91,8 +91,8 @@ private fun CoroutineScope.collectChange(
) {
//Collect properties change
source.onPropertyChange { propertyName ->
val newItem = source.properties.raw?.get(propertyName)
source.onPropertyChange(this) { propertyName ->
val newItem = source.properties.own?.get(propertyName)
collector().propertyChanged(name, propertyName, newItem)
}
@ -118,8 +118,8 @@ private fun CoroutineScope.collectChange(
*/
public fun Vision.flowChanges(
collectionDuration: Duration,
manager: VisionManager = this.manager,
): Flow<VisionChange> = flow {
val manager = manager?: error("Orphan vision could not collect changes")
var collector = VisionChangeBuilder(manager)
coroutineScope {

View File

@ -124,7 +124,7 @@ internal abstract class VisionChildrenImpl(
return items!!
}
private val scope: CoroutineScope get() = group.manager.context
private val scope: CoroutineScope? get() = group.manager?.context
override val keys: Set<NameToken> get() = items?.keys ?: emptySet()
@ -134,7 +134,7 @@ internal abstract class VisionChildrenImpl(
override val changes: SharedFlow<Name> get() = _changes
private fun onChange(name: Name) {
scope.launch {
scope?.launch {
_changes.emit(name)
}
}
@ -158,7 +158,7 @@ internal abstract class VisionChildrenImpl(
//set parent
value.parent = group
//start update jobs (only if the vision is rooted)
scope.let { scope ->
scope?.let { scope ->
val job = value.children?.changes?.onEach {
onChange(token + it)
}?.launchIn(scope)

View File

@ -107,7 +107,8 @@ public abstract class VisionPlugin(meta: Meta = Meta.EMPTY) : AbstractPlugin(met
*/
public val Context.visionManager: VisionManager get() = fetch(VisionManager)
public fun Vision.encodeToString(): String = manager.encodeToString(this)
public fun Vision.encodeToString(): String =
manager?.encodeToString(this) ?: error("Orphan vision could not be encoded")
/**
* A root vision attached to [VisionManager]

View File

@ -1,5 +1,7 @@
package space.kscience.visionforge
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
@ -16,14 +18,14 @@ public interface VisionProperties {
/**
* Raw Visions own properties without styles, defaults, etc.
*/
public val raw: Meta?
public val own: Meta?
public val descriptor: MetaDescriptor?
public fun getValue(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): Value?
/**
@ -31,10 +33,10 @@ public interface VisionProperties {
* @param inherit toggles parent node property lookup. Null means inference from descriptor.
* @param includeStyles toggles inclusion of properties from styles.
*/
public operator fun get(
public fun getProperty(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): Meta
public val changes: Flow<Name>
@ -48,10 +50,10 @@ public interface VisionProperties {
public interface MutableVisionProperties : VisionProperties {
override operator fun get(
override fun getProperty(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
inherit: Boolean?,
includeStyles: Boolean?,
): MutableMeta = VisionPropertiesItem(
this,
name,
@ -60,7 +62,7 @@ public interface MutableVisionProperties : VisionProperties {
)
public operator fun set(
public fun setProperty(
name: Name,
node: Meta?,
)
@ -84,7 +86,7 @@ private class VisionPropertiesItem(
override val items: Map<NameToken, MutableMeta>
get() {
val metaKeys = properties.raw?.getMeta(nodeName)?.items?.keys ?: emptySet()
val metaKeys = properties.own?.getMeta(nodeName)?.items?.keys ?: emptySet()
val descriptorKeys = descriptor?.children?.map { NameToken(it.key) } ?: emptySet()
val defaultKeys = default?.get(nodeName)?.items?.keys ?: emptySet()
val inheritFlag = descriptor?.inherited ?: inherit
@ -119,7 +121,7 @@ private class VisionPropertiesItem(
)
override fun setMeta(name: Name, node: Meta?) {
properties[nodeName + name] = node
properties.setProperty(nodeName + name, node)
}
override fun toString(): String = Meta.toString(this)
@ -131,11 +133,10 @@ public abstract class AbstractVisionProperties(
private val vision: Vision,
) : MutableVisionProperties {
override val descriptor: MetaDescriptor? get() = vision.descriptor
protected val default: Meta? get() = descriptor?.defaultNode
protected abstract var properties: MutableMeta?
override val raw: Meta? get() = properties
override val own: Meta? get() = properties
@Synchronized
protected fun getOrCreateProperties(): MutableMeta {
@ -149,20 +150,24 @@ public abstract class AbstractVisionProperties(
override fun getValue(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
inherit: Boolean?,
includeStyles: Boolean?,
): Value? {
raw?.get(name)?.value?.let { return it }
if (includeStyles) {
val descriptor = descriptor?.get(name)
val inheritFlag = inherit ?: descriptor?.inherited ?: false
val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true
own?.get(name)?.value?.let { return it }
if (stylesFlag) {
vision.getStyleProperty(name)?.value?.let { return it }
}
if (inherit) {
if (inheritFlag) {
vision.parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it }
}
return default?.get(name)?.value
return descriptor?.defaultValue
}
override fun set(name: Name, node: Meta?) {
override fun setProperty(name: Name, node: Meta?) {
//TODO check old value?
if (name.isEmpty()) {
properties = node?.asMutableMeta()
@ -188,6 +193,7 @@ public abstract class AbstractVisionProperties(
private val _changes = MutableSharedFlow<Name>(10)
override val changes: SharedFlow<Name> get() = _changes
@OptIn(DelicateCoroutinesApi::class)
override fun invalidate(propertyName: Name) {
if (propertyName == Vision.STYLE_KEY) {
vision.styles.asSequence()
@ -198,85 +204,46 @@ public abstract class AbstractVisionProperties(
invalidate(it.key.asName())
}
}
vision.manager.context.launch {
(vision.manager?.context ?: GlobalScope).launch {
_changes.emit(propertyName)
}
}
}
public fun VisionProperties.getValue(
name: Name,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): Value? {
val descriptor = descriptor?.get(name)
val inheritFlag = inherit ?: descriptor?.inherited ?: false
val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true
return getValue(name, inheritFlag, stylesFlag)
}
public fun VisionProperties.getValue(
name: String,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): Value? = getValue(name.parseAsName(), inherit, includeStyles)
/**
* Compute the property based on the provided value descriptor. By default, use Vision own descriptor
*/
public operator fun VisionProperties.get(
name: Name,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): Meta {
val descriptor: MetaDescriptor? = descriptor?.get(name)
val inheritFlag = inherit ?: descriptor?.inherited ?: false
val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true
return get(name, inheritFlag, stylesFlag)
}
/**
* Get [Vision] property using key as a String
*/
public operator fun VisionProperties.get(
public fun VisionProperties.getProperty(
name: String,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): Meta = get(name.parseAsName(), inherit, includeStyles)
/**
* Compute the property based on the provided value descriptor. By default, use Vision own descriptor
*/
public operator fun MutableVisionProperties.get(
name: Name,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): MutableMeta {
val descriptor: MetaDescriptor? = descriptor?.get(name)
val inheritFlag = inherit ?: descriptor?.inherited ?: false
val stylesFlag = includeStyles ?: descriptor?.usesStyles ?: true
return get(name, inheritFlag, stylesFlag)
}
): Meta = getProperty(name.parseAsName(), inherit, includeStyles)
/**
* The root property node with given inheritance and style flags
* @param inherit - inherit properties from the [Vision] parent. If null, infer from descriptor
* @param includeStyles - include style information. If null, infer from descriptor
*/
public fun MutableVisionProperties.root(
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): MutableMeta = get(Name.EMPTY, inherit, includeStyles)
): MutableMeta = getProperty(Name.EMPTY, inherit, includeStyles)
/**
* Get [Vision] property using key as a String
*/
public operator fun MutableVisionProperties.get(
public fun MutableVisionProperties.getProperty(
name: String,
inherit: Boolean? = null,
includeStyles: Boolean? = null,
): MutableMeta = get(name.parseAsName(), inherit, includeStyles)
): MutableMeta = getProperty(name.parseAsName(), inherit, includeStyles)
public operator fun MutableVisionProperties.set(name: Name, value: Number): Unit =

View File

@ -9,7 +9,7 @@ import space.kscience.dataforge.names.Name
import space.kscience.visionforge.*
//TODO replace by something
internal val Vision.mutableProperties get() = properties[Name.EMPTY, false, false]
internal val Vision.mutableProperties get() = properties.getProperty(Name.EMPTY, false, false)
@Serializable
public abstract class VisionOfHtmlInput : AbstractVision() {

View File

@ -54,7 +54,7 @@ class HtmlTagTest {
div {
h2 { +"Properties" }
ul {
vision.properties.raw?.items?.forEach {
vision.properties.own?.items?.forEach {
li {
a { +it.key.toString() }
p { +it.value.toString() }

View File

@ -2,7 +2,7 @@ package space.kscience.visionforge.meta
import space.kscience.dataforge.meta.*
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.get
import space.kscience.visionforge.getProperty
import space.kscience.visionforge.getValue
import space.kscience.visionforge.set
import kotlin.test.Test
@ -30,7 +30,7 @@ internal class VisionPropertyTest {
@Test
fun testPropertyEdit() {
val vision = VisionGroup()
vision.properties["fff.ddd"].apply {
vision.properties.getProperty("fff.ddd").apply {
value = 2.asValue()
}
assertEquals(2, vision.properties.getValue("fff.ddd")?.int)
@ -40,7 +40,7 @@ internal class VisionPropertyTest {
@Test
fun testPropertyUpdate() {
val vision = VisionGroup()
vision.properties["fff"].updateWith(TestScheme) {
vision.properties.getProperty("fff").updateWith(TestScheme) {
ddd = 2
}
assertEquals(2, vision.properties.getValue("fff.ddd")?.int)

View File

@ -115,7 +115,7 @@ public class VisionClient : AbstractPlugin() {
onopen = {
feedbackJob = vision.flowChanges(
feedbackAggregationTime.milliseconds
feedbackAggregationTime.milliseconds,
).onEach { change ->
send(visionManager.encodeToString(change))
}.launchIn(visionManager.context)

View File

@ -1,12 +1,12 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("space.kscience.gradle.jvm")
}
val dataforgeVersion: String by rootProject.extra
val fxVersion: String by rootProject.extra
kscience{
useFx(ru.mipt.npm.gradle.FXModule.CONTROLS, version = fxVersion)
useFx(space.kscience.gradle.FXModule.CONTROLS, version = fxVersion)
}
dependencies {
@ -15,12 +15,12 @@ dependencies {
api("org.fxyz3d:fxyz3d:0.5.4") {
exclude(module = "slf4j-simple")
}
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}")
api("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:${space.kscience.gradle.KScienceVersions.coroutinesVersion}")
implementation("eu.mihosoft.vrl.jcsg:jcsg:0.5.7") {
exclude(module = "slf4j-simple")
}
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
maturity = space.kscience.gradle.Maturity.PROTOTYPE
}

View File

@ -16,7 +16,6 @@ import space.kscience.dataforge.context.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.misc.Type
import space.kscience.visionforge.get
import space.kscience.visionforge.solid.FX3DFactory.Companion.TYPE
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_WIREFRAME_KEY
@ -77,7 +76,7 @@ public class FX3DPlugin : AbstractPlugin() {
is PolyLine -> PolyLine3D(
obj.points.map { Point3D(it.x, it.y, it.z) },
obj.thickness.toFloat(),
obj.properties.get(SolidMaterial.MATERIAL_COLOR_KEY).color()
obj.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).color()
).apply {
this.meshView.cullFace = CullFace.FRONT
}

View File

@ -6,7 +6,6 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith
import space.kscience.visionforge.Vision
import space.kscience.visionforge.get
import space.kscience.visionforge.onPropertyChange
import tornadofx.*
@ -35,7 +34,7 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
public operator fun get(key: Name): ObjectBinding<Meta?> {
return bindings.getOrPut(key) {
object : ObjectBinding<Meta?>() {
override fun computeValue(): Meta = obj.properties[key]
override fun computeValue(): Meta = obj.properties.getProperty(key)
}
}
}

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
kotlin {
@ -13,5 +13,10 @@ kotlin {
api("space.kscience:gdml:0.4.0")
}
}
jvmTest{
dependencies{
implementation("ch.qos.logback:logback-classic:1.2.11")
}
}
}
}

View File

@ -1,5 +1,6 @@
package space.kscience.visionforge.gdml
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.info
import space.kscience.dataforge.context.logger
import space.kscience.dataforge.names.Name
@ -50,7 +51,7 @@ private fun VisionCounterTree.topToBottom(): Sequence<VisionCounterTree> = seque
}
public fun SolidGroup.markLayers(thresholds: List<Int> = listOf(500, 1000, 20000, 50000)) {
val logger = manager.context.logger
val logger = manager?.context?.logger ?: Global.logger
val counterTree = VisionCounterTree(Name.EMPTY, this, hashMapOf())
val totalCount = counterTree.childrenCount
if (totalCount > (thresholds.firstOrNull() ?: 0)) {

View File

@ -26,7 +26,7 @@ class TestCubes {
val smallBoxPrototype = vision.getPrototype(Name.parse("solids.smallBox")) as? Box
assertNotNull(smallBoxPrototype)
assertEquals(30.0, smallBoxPrototype.xSize.toDouble())
val smallBoxVision = vision.children["composite-111.smallBox"]?.unref as? Box
val smallBoxVision = vision.children["composite-111.smallBox"]?.prototype as? Box
assertNotNull(smallBoxVision)
assertEquals(30.0, smallBoxVision.xSize.toDouble())
}

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
val markdownVersion = "0.2.4"

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
val plotlyVersion = "0.5.3-dev-1"

View File

@ -16,7 +16,7 @@ import space.kscience.visionforge.root
public class VisionOfPlotly private constructor() : AbstractVision() {
public constructor(plot: Plot) : this() {
properties[Name.EMPTY] = plot.meta
properties.setProperty(Name.EMPTY, plot.meta)
}
public val plot: Plot get() = Plot(properties.root().asObservable())

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("space.kscience.gradle.jvm")
}
val ktorVersion = npmlibs.versions.ktor.get()

View File

@ -92,6 +92,7 @@ public class VisionServer internal constructor(
header()
}
title(title)
consumer.header()
}
body {
//Load the fragment and remember all loaded visions

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
kscience{
@ -20,9 +20,14 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4")
}
}
jvmTest{
dependencies{
implementation("ch.qos.logback:logback-classic:1.2.11")
}
}
}
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
maturity = space.kscience.gradle.Maturity.DEVELOPMENT
}

View File

@ -29,7 +29,7 @@ public class ColorAccessor(
}
public fun Vision.color(): ReadOnlyProperty<Vision, ColorAccessor> = ReadOnlyProperty { _, property ->
ColorAccessor(properties.root(), property.name.asName())
ColorAccessor(properties.root(true), property.name.asName())
}
public var ColorAccessor?.string: String?

View File

@ -33,7 +33,7 @@ public inline fun MutableVisionContainer<Solid>.composite(
}
val res = Composite(type, children[0], children[1])
res.properties[Name.EMPTY] = group.properties.raw
res.properties.setProperty(Name.EMPTY, group.properties.own)
set(name, res)
return res
@ -49,7 +49,7 @@ public fun SolidGroup.smartComposite(
@VisionBuilder builder: SolidGroup.() -> Unit,
): Solid = if (type == CompositeType.GROUP) {
val group = SolidGroup(builder)
if (name == null && group.properties.raw == null) {
if (name == null && group.properties.own == null) {
//append directly to group if no properties are defined
group.items.forEach { (_, value) ->
value.parent = null

View File

@ -107,7 +107,7 @@ public class ExtrudeBuilder(
}
internal fun build(): Extruded = Extruded(shape, layers).apply {
this.properties[Name.EMPTY] = this@ExtrudeBuilder.properties
this.properties.setProperty(Name.EMPTY, this@ExtrudeBuilder.properties)
}
}

View File

@ -10,7 +10,7 @@ import space.kscience.visionforge.*
public class PolyLine(public val points: List<Point3D>) : SolidBase<PolyLine>() {
//var lineType by string()
public var thickness: Number by properties[SolidMaterial.MATERIAL_KEY].number { 1.0 }
public var thickness: Number by properties.getProperty(SolidMaterial.MATERIAL_KEY).number { 1.0 }
}
@VisionBuilder

View File

@ -170,7 +170,7 @@ internal fun float(name: Name, default: Number): ReadWriteProperty<Solid, Number
internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D?> =
object : ReadWriteProperty<Solid, Point3D?> {
override fun getValue(thisRef: Solid, property: KProperty<*>): Point3D? {
val item = thisRef.properties.raw?.get(name) ?: return null
val item = thisRef.properties.own?.get(name) ?: return null
return object : Point3D {
override val x: Float get() = item[X_KEY]?.float ?: default
override val y: Float get() = item[Y_KEY]?.float ?: default
@ -180,7 +180,7 @@ internal fun point(name: Name, default: Float): ReadWriteProperty<Solid, Point3D
override fun setValue(thisRef: Solid, property: KProperty<*>, value: Point3D?) {
if (value == null) {
thisRef.properties[name] = null
thisRef.properties.setProperty(name, null)
} else {
thisRef.properties[name + X_KEY] = value.x
thisRef.properties[name + Y_KEY] = value.y

View File

@ -54,7 +54,7 @@ public class SolidGroup : AbstractVisionGroup(), Solid, PrototypeHolder, Mutable
* If prototype is a ref, then it is unfolded automatically.
*/
override fun getPrototype(name: Name): Solid? =
prototypes?.get(name)?.unref ?: (parent as? PrototypeHolder)?.getPrototype(name)
prototypes?.get(name)?.prototype ?: (parent as? PrototypeHolder)?.getPrototype(name)
/**
* Create or edit prototype node as a group

View File

@ -99,15 +99,15 @@ public class SolidMaterial : Scheme() {
}
public val Solid.color: ColorAccessor
get() = ColorAccessor(properties.root(), MATERIAL_COLOR_KEY)
get() = ColorAccessor(properties.root(true), MATERIAL_COLOR_KEY)
public var Solid.material: SolidMaterial?
get() = SolidMaterial.read(properties[MATERIAL_KEY])
set(value) = properties.set(MATERIAL_KEY, value?.meta)
get() = SolidMaterial.read(properties.getProperty(MATERIAL_KEY))
set(value) = properties.setProperty(MATERIAL_KEY, value?.meta)
@VisionBuilder
public fun Solid.material(builder: SolidMaterial.() -> Unit) {
properties[MATERIAL_KEY].updateWith(SolidMaterial, builder)
properties.getProperty(MATERIAL_KEY).updateWith(SolidMaterial, builder)
}
public var Solid.opacity: Number?

View File

@ -16,9 +16,10 @@ import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD
* Get a vision prototype if it is a [SolidReference] or vision itself if it is not.
* Unref is recursive, so it always returns a non-reference.
*/
public val Vision.unref: Solid
public val Vision.prototype: Solid
get() = when (this) {
is SolidReference -> prototype.unref
is SolidReference -> prototype.prototype
is SolidReferenceChild -> prototype.prototype
is Solid -> this
else -> error("This Vision is neither Solid nor SolidReference")
}
@ -55,13 +56,13 @@ public class SolidReference(
propertiesInternal = value
}
override val raw: Meta? get() = properties
override val own: Meta? get() = properties
override fun get(name: Name, inherit: Boolean, includeStyles: Boolean): MutableMeta {
return properties?.getMeta(name) ?: prototype.properties.get(name, inherit, includeStyles)
override fun getProperty(name: Name, inherit: Boolean?, includeStyles: Boolean?): MutableMeta {
return properties?.getMeta(name) ?: prototype.properties.getProperty(name, inherit, includeStyles)
}
override fun getValue(name: Name, inherit: Boolean, includeStyles: Boolean): Value? {
override fun getValue(name: Name, inherit: Boolean?, includeStyles: Boolean?): Value? {
return properties?.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
}
}
@ -105,23 +106,23 @@ internal class SolidReferenceChild(
override val properties: MutableVisionProperties = object : MutableVisionProperties {
override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor
override val raw: MutableMeta by lazy { owner.properties[childToken(childName).asName()] }
override val own: MutableMeta by lazy { owner.properties.getProperty(childToken(childName).asName()) }
override fun get(name: Name, inherit: Boolean, includeStyles: Boolean): MutableMeta =
raw.getMeta(name) ?: prototype.properties.get(name, inherit, includeStyles)
override fun getProperty(name: Name, inherit: Boolean?, includeStyles: Boolean?): MutableMeta =
own.getMeta(name) ?: prototype.properties.getProperty(name, inherit, includeStyles)
override fun getValue(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
): Value? = raw.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
inherit: Boolean?,
includeStyles: Boolean?,
): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
override fun set(name: Name, node: Meta?) {
raw.setMeta(name, node)
override fun setProperty(name: Name, node: Meta?) {
own.setMeta(name, node)
}
override fun setValue(name: Name, value: Value?) {
raw.setValue(name, value)
own.setValue(name, value)
}
override val changes: Flow<Name> get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }

View File

@ -20,7 +20,7 @@ internal fun Solid.updateFrom(other: Solid): Solid {
scaleX *= other.scaleX
scaleY *= other.scaleY
scaleZ *= other.scaleZ
properties[Name.EMPTY] = other.properties.root()
properties.setProperty(Name.EMPTY, other.properties.root())
return this
}

View File

@ -3,7 +3,6 @@ package space.kscience.visionforge.solid
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withTimeout
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.asName
@ -26,13 +25,13 @@ class PropertyTest {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testColorUpdate() = runTest {
fun testColorUpdate() = runTest(dispatchTimeoutMs = 200) {
val box = Box(10.0f, 10.0f, 10.0f)
val c = CompletableDeferred<String?>()
box.onPropertyChange {
val subscription = box.onPropertyChange(this) {
if (it == SolidMaterial.MATERIAL_COLOR_KEY) {
c.complete(box.color.string)
}
@ -42,8 +41,8 @@ class PropertyTest {
color.set("pink")
}
assertEquals("pink", withTimeout(50) { c.await() })
assertEquals("pink", c.await())
subscription.cancel()
}
@Test

View File

@ -31,7 +31,7 @@ class SerializationTest {
val string = Solids.encodeToString(cube)
println(string)
val newCube = Solids.decodeFromString(string)
assertEquals(cube.properties.raw, newCube.properties.raw)
assertEquals(cube.properties.own, newCube.properties.own)
}
@Test
@ -52,7 +52,7 @@ class SerializationTest {
val string = Solids.encodeToString(group)
println(string)
val reconstructed = Solids.decodeFromString(string) as SolidGroup
assertEquals(group.children["cube"]?.properties?.raw, reconstructed.children["cube"]?.properties?.raw)
assertEquals(group.children["cube"]?.properties?.own, reconstructed.children["cube"]?.properties?.own)
}
@Test

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
val tablesVersion = "0.2.0-dev-3"
@ -36,5 +36,5 @@ kotlin {
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
maturity = space.kscience.gradle.Maturity.PROTOTYPE
}

View File

@ -17,7 +17,7 @@ internal class VisionOfTableTest {
val x by ColumnHeader.typed<Value>()
val y by ColumnHeader.typed<Value>()
val table = ColumnTable(100) {
val table = ColumnTable<Value>(100) {
x.fill { it.asValue() }
y.values = x.values.map { it?.double?.pow(2)?.asValue() }
}

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.js")
id("space.kscience.gradle.js")
}
kotlin{

View File

@ -10,7 +10,6 @@ import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith
import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.get
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.set
import space.kscience.visionforge.solid.Solid
@ -78,7 +77,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
@VisionBuilder
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
properties.set(EDGES_ENABLED_KEY, enabled)
SolidMaterial.write(properties[EDGES_MATERIAL_KEY]).apply(block)
SolidMaterial.write(properties.getProperty(EDGES_MATERIAL_KEY)).apply(block)
}
internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
@ -94,9 +93,9 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
public fun Mesh.applyEdges(obj: Solid) {
val edges = children.find { it.name == "@edges" } as? LineSegments
//inherited edges definition, enabled by default
if (obj.properties.get(EDGES_ENABLED_KEY, inherit = true).boolean != false) {
if (obj.properties.getProperty(EDGES_ENABLED_KEY, inherit = true).boolean != false) {
val bufferGeometry = geometry as? BufferGeometry ?: return
val material = ThreeMaterials.getLineMaterial(obj.properties[EDGES_MATERIAL_KEY], true)
val material = ThreeMaterials.getLineMaterial(obj.properties.getProperty(EDGES_MATERIAL_KEY), true)
if (edges == null) {
add(
LineSegments(

View File

@ -11,7 +11,6 @@ import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.CanvasTextBaseline
import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.MIDDLE
import space.kscience.visionforge.get
import space.kscience.visionforge.solid.SolidLabel
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
@ -27,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
context.fillStyle = obj.properties[SolidMaterial.MATERIAL_COLOR_KEY].value ?: "black"
context.fillStyle = obj.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).value ?: "black"
context.textBaseline = CanvasTextBaseline.MIDDLE
val metrics = context.measureText(obj.text)
//canvas.width = metrics.width.toInt()

View File

@ -4,7 +4,6 @@ import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D
import info.laht.threekt.math.Color
import info.laht.threekt.objects.LineSegments
import space.kscience.visionforge.get
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.solid.PolyLine
import space.kscience.visionforge.solid.SolidMaterial
@ -25,7 +24,7 @@ public object ThreeLineFactory : ThreeFactory<PolyLine> {
}
val material = ThreeMaterials.getLineMaterial(
obj.properties[SolidMaterial.MATERIAL_KEY],
obj.properties.getProperty(SolidMaterial.MATERIAL_KEY),
false
)

View File

@ -10,7 +10,9 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.visionforge.*
import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision
import space.kscience.visionforge.getStyleNodes
import space.kscience.visionforge.solid.ColorAccessor
import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.SolidReference
@ -129,15 +131,15 @@ private var Material.cached: Boolean
}
public fun Mesh.updateMaterial(vision: Vision) {
val ownMaterialMeta = vision.properties.raw?.get(SolidMaterial.MATERIAL_KEY)
val ownMaterialMeta = vision.properties.own?.get(SolidMaterial.MATERIAL_KEY)
if (ownMaterialMeta == null) {
if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) {
updateMaterial(vision.prototype)
} else {
material = ThreeMaterials.cacheMaterial(vision.properties[SolidMaterial.MATERIAL_KEY])
material = ThreeMaterials.cacheMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
}
} else {
material = ThreeMaterials.buildMaterial(vision.properties[SolidMaterial.MATERIAL_KEY])
material = ThreeMaterials.buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
}
}
@ -152,15 +154,16 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
} else {
when (propertyName) {
SolidMaterial.MATERIAL_COLOR_KEY -> {
material.asDynamic().color = vision.properties[SolidMaterial.MATERIAL_COLOR_KEY].threeColor()
material.asDynamic().color = vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor()
?: ThreeMaterials.DEFAULT_COLOR
}
SolidMaterial.SPECULAR_COLOR_KEY -> {
material.asDynamic().specular = vision.properties[SolidMaterial.SPECULAR_COLOR_KEY].threeColor()
material.asDynamic().specular = vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor()
?: ThreeMaterials.DEFAULT_COLOR
}
SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY -> {
material.asDynamic().emissive = vision.properties[SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY].threeColor()
material.asDynamic().emissive = vision.properties.getProperty(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY)
.threeColor()
?: ThreeMaterials.BLACK_COLOR
}
SolidMaterial.MATERIAL_OPACITY_KEY -> {

View File

@ -1,6 +1,8 @@
package space.kscience.visionforge.solid.three
import info.laht.threekt.core.Object3D
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import space.kscience.dataforge.context.*
@ -9,7 +11,6 @@ import space.kscience.dataforge.meta.update
import space.kscience.dataforge.names.*
import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.visible
@ -48,11 +49,11 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
public fun buildObject3D(obj: Solid): Object3D = when (obj) {
is ThreeJsVision -> obj.render(this)
is SolidReferenceGroup -> ThreeReferenceFactory.build(this, obj)
is SolidReference -> ThreeReferenceFactory.build(this, obj)
is SolidGroup -> {
val group = ThreeGroup()
obj.items.forEach { (token, child) ->
if (child is Solid && token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
if (token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
try {
val object3D = buildObject3D(child)
group[token] = object3D
@ -67,7 +68,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
updatePosition(obj)
//obj.onChildrenChange()
obj.onPropertyChange { name ->
obj.properties.changes.onEach { name ->
if (
name.startsWith(Solid.POSITION_KEY) ||
name.startsWith(Solid.ROTATION_KEY) ||
@ -78,10 +79,10 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
} else if (name == Vision.VISIBLE_KEY) {
visible = obj.visible ?: true
}
}
}.launchIn(context)
obj.onStructureChanged(this){ childName ->
val child = get(childName)
obj.children.changes.onEach { childName ->
val child = obj.children[childName]
//removing old object
findChild(childName)?.let { oldChild ->
@ -97,7 +98,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
logger.error(ex) { "Failed to render $child" }
}
}
}
}.launchIn(context)
}
}
is Composite -> compositeFactory.build(this, obj)

View File

@ -7,20 +7,21 @@ import space.kscience.dataforge.names.cutFirst
import space.kscience.dataforge.names.firstOrNull
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.SolidReferenceGroup
import space.kscience.visionforge.solid.SolidReferenceGroup.Companion.REFERENCE_CHILD_PROPERTY_PREFIX
import space.kscience.visionforge.solid.SolidReference
import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD_PROPERTY_PREFIX
import kotlin.reflect.KClass
public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
public object ThreeReferenceFactory : ThreeFactory<SolidReference> {
private val cache = HashMap<Solid, Object3D>()
override val type: KClass<SolidReferenceGroup> = SolidReferenceGroup::class
override val type: KClass<SolidReference> = SolidReference::class
private fun Object3D.replicate(): Object3D {
return when (this) {
is Mesh -> Mesh(geometry, material).also {
it.applyMatrix4(matrix)
}
else -> clone(false)
}.also { obj: Object3D ->
obj.name = this.name
@ -30,7 +31,7 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
}
}
override fun build(three: ThreePlugin, obj: SolidReferenceGroup): Object3D {
override fun build(three: ThreePlugin, obj: SolidReference): Object3D {
val template = obj.prototype
val cachedObject = cache.getOrPut(template) {
three.buildObject3D(template)
@ -39,18 +40,20 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReferenceGroup> {
val object3D: Object3D = cachedObject.replicate()
object3D.updatePosition(obj)
if(object3D is Mesh){
if (object3D is Mesh) {
//object3D.material = ThreeMaterials.buildMaterial(obj.getProperty(SolidMaterial.MATERIAL_KEY).node!!)
object3D.applyProperties(obj)
}
//TODO apply child properties
obj.onPropertyChange { name->
obj.onPropertyChange { name ->
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
val childName = name.firstOrNull()?.index?.let(Name::parse)
?: error("Wrong syntax for reference child property: '$name'")
val propertyName = name.cutFirst()
val referenceChild = obj.children[childName] ?: error("Reference child with name '$childName' not found")
val referenceChild =
obj.children[childName] ?: error("Reference child with name '$childName' not found")
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
child.updateProperty(referenceChild, propertyName)
} else {

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
}
val ktorVersion: String by rootProject.extra