Finish ThreeCancas encapsulation

This commit is contained in:
Alexander Nozik 2021-06-06 20:57:39 +03:00
parent 359eb05f83
commit 288307eaa8
17 changed files with 122 additions and 143 deletions

View File

@ -11,7 +11,6 @@ import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.gdml.Gdml import space.kscience.gdml.Gdml
import space.kscience.gdml.decodeFromString import space.kscience.gdml.decodeFromString
import space.kscience.visionforge.Vision
import space.kscience.visionforge.bootstrap.gridRow import space.kscience.visionforge.bootstrap.gridRow
import space.kscience.visionforge.bootstrap.nameCrumbs import space.kscience.visionforge.bootstrap.nameCrumbs
import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.gdml.toVision
@ -21,27 +20,31 @@ import space.kscience.visionforge.ring.ringThreeControls
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
external interface GDMLAppProps : RProps { external interface GDMLAppProps : RProps {
var context: Context var context: Context
var rootVision: Vision? var vision: Solid?
var selected: Name? var selected: Name?
} }
@JsExport @JsExport
val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props -> val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
var canvas: ThreeCanvas? by useState { null } var vision: Solid? by useState { props.vision }
var vision: Vision? by useState { props.rootVision }
val onSelect: (Name?) -> Unit = { val onSelect: (Name?) -> Unit = {
selected = it selected = it
} }
val visionManager = useMemo({ props.context.fetch(Solids).visionManager }, arrayOf(props.context)) val options = useMemo {
Canvas3DOptions.invoke {
this.onSelect = onSelect
}
}
val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager }
fun loadData(name: String, data: String) { fun loadData(name: String, data: String) {
val parsedVision = when { val parsedVision = when {
@ -56,7 +59,7 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
} }
} }
vision = parsedVision vision = parsedVision as? Solid ?: error("Parsed vision is not a solid")
} }
gridRow { gridRow {
@ -78,14 +81,9 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
child(ThreeCanvasComponent) { child(ThreeCanvasComponent) {
attrs { attrs {
this.context = props.context this.context = props.context
this.obj = vision as? Solid this.obj = vision
this.selected = selected this.selected = selected
this.options = Canvas3DOptions.invoke { this.options = options
this.onSelect = onSelect
}
this.canvasCallback = {
canvas = it
}
} }
} }
@ -111,9 +109,7 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
} }
} }
} }
canvas?.let { ringThreeControls(options, props.vision, selected, onSelect)
ringThreeControls(it, selected, onSelect)
}
} }
} }
} }

View File

@ -29,7 +29,7 @@ private class GDMLDemoApp : Application {
//println(context.plugins.fetch(VisionManager).encodeToString(vision)) //println(context.plugins.fetch(VisionManager).encodeToString(vision))
attrs { attrs {
this.context = context this.context = context
this.rootVision = vision this.vision = vision
} }
} }
} }

View File

@ -6,11 +6,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.css.* import kotlinx.css.*
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import react.RProps import react.*
import react.child
import react.dom.* import react.dom.*
import react.functionalComponent
import react.useState
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
@ -26,7 +23,6 @@ import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.objectTree import space.kscience.visionforge.react.objectTree
import space.kscience.visionforge.solid.specifications.Camera import space.kscience.visionforge.solid.specifications.Camera
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import kotlin.math.PI import kotlin.math.PI
@ -49,12 +45,17 @@ private val canvasConfig = Canvas3DOptions {
@JsExport @JsExport
val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props -> val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
var canvas: ThreeCanvas? by useState { null }
val onSelect: (Name?) -> Unit = { val onSelect: (Name?) -> Unit = {
selected = it selected = it
} }
val options = useMemo {
Canvas3DOptions.invoke {
this.onSelect = onSelect
}
}
val root = props.model.root val root = props.model.root
gridRow { gridRow {
@ -95,9 +96,6 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
this.options = canvasConfig.apply { this.options = canvasConfig.apply {
this.onSelect = onSelect this.onSelect = onSelect
} }
this.canvasCallback = {
canvas = it
}
} }
} }
} }
@ -113,11 +111,10 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
flex(0.0, 1.0, FlexBasis.zero) flex(0.0, 1.0, FlexBasis.zero)
} }
//settings //settings
canvas?.let {
card("Canvas configuration") { card("Canvas configuration") {
canvasControls(it) canvasControls(options, root)
}
} }
card("Events") { card("Events") {
button { button {
+"Next" +"Next"

View File

@ -19,7 +19,6 @@ 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
import space.kscience.visionforge.solid.three.configure
class ThreeDemoGrid(element: Element) : VisionLayout<Solid> { class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
private lateinit var navigationElement: HTMLElement private lateinit var navigationElement: HTMLElement
@ -71,7 +70,7 @@ class ThreeDemoGrid(element: Element) : VisionLayout<Solid> {
} }
} }
val element = document.getElementById("output-$name") ?: error("Element not found") val element = document.getElementById("output-$name") ?: error("Element not found")
three.getOrCreateCanvas(element).also { it.configure(canvasOptions) } three.getOrCreateCanvas(element, canvasOptions)
}.render(vision) }.render(vision)
} }
} }

View File

@ -13,12 +13,11 @@ import react.*
import react.dom.attrs import react.dom.attrs
import react.dom.button import react.dom.button
import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.meta.withDefault
import space.kscience.visionforge.Vision
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.propertyEditor import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css import styled.css
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) { private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
@ -30,37 +29,33 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
fileSaver.saveAs(blob, fileName) fileSaver.saveAs(blob, fileName)
} }
public fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement { public fun RBuilder.canvasControls(canvasOptions: Canvas3DOptions, vision: Vision?): ReactElement {
return child(CanvasControls) { return child(CanvasControls) {
attrs { attrs {
this.canvas = canvas this.canvasOptions = canvasOptions
this.vision = vision
} }
} }
} }
public external interface CanvasControlsProps : RProps { public external interface CanvasControlsProps : RProps {
public var canvas: ThreeCanvas public var canvasOptions: Canvas3DOptions
public var vision: Vision?
} }
public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props -> public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
val visionManager = useMemo(
{ props.canvas.three.solids.visionManager },
arrayOf(props.canvas)
)
flexColumn { flexColumn {
flexRow { flexRow {
css { css {
border(1.px, BorderStyle.solid, Color.blue) border(1.px, BorderStyle.solid, Color.blue)
padding(4.px) padding(4.px)
} }
props.vision?.manager?.let { manager ->
button { button {
+"Export" +"Export"
attrs { attrs {
onClickFunction = { onClickFunction = {
val json = (props.canvas.content as? SolidGroup)?.let { group -> val json = manager.encodeToString(props.vision!!)
visionManager.encodeToString(group)
}
if (json != null) {
saveData(it, "object.json", "text/json") { saveData(it, "object.json", "text/json") {
json json
} }
@ -70,8 +65,8 @@ public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functional
} }
} }
propertyEditor( propertyEditor(
ownProperties = props.canvas.options, ownProperties = props.canvasOptions,
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta), allProperties = props.canvasOptions.withDefault(Canvas3DOptions.descriptor.defaultMeta),
descriptor = Canvas3DOptions.descriptor, descriptor = Canvas3DOptions.descriptor,
expanded = false expanded = false
) )

View File

@ -9,23 +9,23 @@ import space.kscience.dataforge.names.isEmpty
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.react.objectTree import space.kscience.visionforge.react.objectTree
import space.kscience.visionforge.solid.three.ThreeCanvas import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
public external interface ThreeControlsProps : RProps { public external interface ThreeControlsProps : RProps {
public var canvas: ThreeCanvas public var canvasOptions: Canvas3DOptions
public var vision: Vision?
public var selected: Name? public var selected: Name?
public var onSelect: (Name) -> Unit public var onSelect: (Name) -> Unit
} }
@JsExport @JsExport
public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props -> public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props ->
val vision = props.canvas.content
tabPane(if (props.selected != null) "Properties" else null) { tabPane(if (props.selected != null) "Properties" else null) {
tab("Canvas") { tab("Canvas") {
card("Canvas configuration") { card("Canvas configuration") {
canvasControls(props.canvas) canvasControls(props.canvasOptions, props.vision)
} }
} }
tab("Tree") { tab("Tree") {
@ -38,7 +38,7 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
css { css {
flex(1.0, 1.0, FlexBasis.inherit) flex(1.0, 1.0, FlexBasis.inherit)
} }
props.canvas.content?.let { props.vision?.let {
objectTree(it, props.selected, props.onSelect) objectTree(it, props.selected, props.onSelect)
} }
} }
@ -47,8 +47,8 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
props.selected.let { selected -> props.selected.let { selected ->
val selectedObject: Vision? = when { val selectedObject: Vision? = when {
selected == null -> null selected == null -> null
selected.isEmpty() -> vision selected.isEmpty() -> props.vision
else -> (vision as? VisionGroup)?.get(selected) else -> (props.vision as? VisionGroup)?.get(selected)
} }
if (selectedObject != null) { if (selectedObject != null) {
visionPropertyEditor(selectedObject, key = selected) visionPropertyEditor(selectedObject, key = selected)
@ -62,13 +62,15 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
} }
public fun RBuilder.threeControls( public fun RBuilder.threeControls(
canvas: ThreeCanvas, canvasOptions: Canvas3DOptions,
vision: Vision?,
selected: Name?, selected: Name?,
onSelect: (Name) -> Unit = {}, onSelect: (Name) -> Unit = {},
builder: TabBuilder.() -> Unit = {}, builder: TabBuilder.() -> Unit = {},
): ReactElement = child(ThreeControls) { ): ReactElement = child(ThreeControls) {
attrs { attrs {
this.canvas = canvas this.canvasOptions = canvasOptions
this.vision = vision
this.selected = selected this.selected = selected
this.onSelect = onSelect this.onSelect = onSelect
} }

View File

@ -14,16 +14,14 @@ import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
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
import space.kscience.visionforge.solid.three.configure
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
public external interface ThreeCanvasProps : RProps { public external interface ThreeCanvasProps : RProps {
public var context: Context public var context: Context
public var options: Canvas3DOptions
public var obj: Solid? public var obj: Solid?
public var options: Canvas3DOptions?
public var selected: Name? public var selected: Name?
public var canvasCallback: ((ThreeCanvas?) -> Unit)?
} }
public external interface ThreeCanvasState : RState { public external interface ThreeCanvasState : RState {
@ -42,22 +40,15 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
useEffect(listOf(props.obj, props.options, elementRef)) { useEffect(listOf(props.obj, props.options, elementRef)) {
if (canvas == null) { if (canvas == null) {
val element = elementRef.current as? HTMLElement ?: error("Canvas element not found") val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
val newCanvas: ThreeCanvas = three.getOrCreateCanvas(element) canvas = three.getOrCreateCanvas(element, props.options)
props.options?.let {
newCanvas.configure(it)
}
props.canvasCallback?.invoke(newCanvas)
canvas = newCanvas
} }
} }
useEffect(listOf(canvas, props.obj)) { useEffect(listOf(canvas, props.obj)) {
props.obj?.let { obj -> props.obj?.let { obj ->
if (canvas?.content != obj) {
canvas?.render(obj) canvas?.render(obj)
} }
} }
}
useEffect(listOf(canvas, props.selected)) { useEffect(listOf(canvas, props.selected)) {
canvas?.select(props.selected) canvas?.select(props.selected)

View File

@ -1,10 +1,7 @@
package space.kscience.visionforge.ring package space.kscience.visionforge.ring
import kotlinx.css.* import kotlinx.css.*
import react.RProps import react.*
import react.child
import react.functionalComponent
import react.useState
import ringui.grid.ringCol import ringui.grid.ringCol
import ringui.grid.ringGrid import ringui.grid.ringGrid
import ringui.grid.ringRow import ringui.grid.ringRow
@ -14,25 +11,27 @@ import space.kscience.visionforge.Vision
import space.kscience.visionforge.react.ThreeCanvasComponent import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
public external interface GdmlViewProps : RProps { public external interface ThreeWithControlsProps : RProps {
public var context: Context public var context: Context
public var rootVision: Vision? public var vision: Vision?
public var selected: Name? public var selected: Name?
} }
@JsExport @JsExport
public val ThreeViewWithControls: (props: GdmlViewProps) -> dynamic = public val ThreeViewWithControls: (props: ThreeWithControlsProps) -> dynamic =
functionalComponent<GdmlViewProps>("ThreeViewWithControls") { props -> functionalComponent("ThreeViewWithControls") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
var canvas: ThreeCanvas? by useState { null }
val onSelect: (Name?) -> Unit = { val onSelect: (Name?) -> Unit = {
selected = it selected = it
} }
val options = useMemo {
Canvas3DOptions.invoke {
this.onSelect = onSelect
}
}
styledDiv { styledDiv {
css { css {
@ -50,14 +49,9 @@ public val ThreeViewWithControls: (props: GdmlViewProps) -> dynamic =
child(ThreeCanvasComponent) { child(ThreeCanvasComponent) {
attrs { attrs {
this.context = props.context this.context = props.context
this.obj = props.rootVision as? Solid this.obj = props.vision as? Solid
this.selected = selected this.selected = selected
this.options = Canvas3DOptions.invoke { this.options = options
this.onSelect = onSelect
}
this.canvasCallback = {
canvas = it
}
} }
} }
@ -76,9 +70,7 @@ public val ThreeViewWithControls: (props: GdmlViewProps) -> dynamic =
height = 100.pct height = 100.pct
overflowY = Overflow.auto overflowY = Overflow.auto
} }
canvas?.let { ringThreeControls(options, props.vision, selected, onSelect)
ringThreeControls(it, selected, onSelect)
}
} }
} }
} }

View File

@ -28,7 +28,7 @@ public class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
child(ThreeViewWithControls) { child(ThreeViewWithControls) {
attrs { attrs {
this.context = this@ThreeWithControls.context this.context = this@ThreeWithControls.context
this.rootVision = vision this.vision = vision
} }
} }
} }

View File

@ -18,13 +18,12 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.isEmpty
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.encodeToString
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.objectTree import space.kscience.visionforge.react.objectTree
import space.kscience.visionforge.react.propertyEditor import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
@ -37,48 +36,45 @@ internal fun saveData(event: Event, fileName: String, mimeType: String = "text/p
fileSaver.saveAs(blob, fileName) fileSaver.saveAs(blob, fileName)
} }
internal fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement { internal fun RBuilder.canvasControls(options: Canvas3DOptions, vision: Vision?): ReactElement {
return child(CanvasControls) { return child(CanvasControls) {
attrs { attrs {
this.canvas = canvas this.options = options
this.vision = vision
} }
} }
} }
internal external interface CanvasControlsProps : RProps { internal external interface CanvasControlsProps : RProps {
public var canvas: ThreeCanvas public var options: Canvas3DOptions
public var vision: Vision?
} }
internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props -> internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
val visionManager = useMemo(
{ props.canvas.three.solids.visionManager },
arrayOf(props.canvas)
)
flexColumn { flexColumn {
flexRow { flexRow {
css { css {
border(1.px, BorderStyle.solid, Color.blue) border(1.px, BorderStyle.solid, Color.blue)
padding(4.px) padding(4.px)
} }
props.vision?.let { vision ->
button { button {
+"Export" +"Export"
attrs { attrs {
onClickFunction = { onClickFunction = {
val json = (props.canvas.content as? SolidGroup)?.let { group -> val json = vision.encodeToString()
visionManager.encodeToString(group)
}
if (json != null) {
saveData(it, "object.json", "text/json") { saveData(it, "object.json", "text/json") {
json json
} }
} }
} }
} }
} }
} }
propertyEditor( propertyEditor(
ownProperties = props.canvas.options, ownProperties = props.options,
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta), allProperties = props.options.withDefault(Canvas3DOptions.descriptor.defaultMeta),
descriptor = Canvas3DOptions.descriptor, descriptor = Canvas3DOptions.descriptor,
expanded = false expanded = false
) )
@ -88,18 +84,18 @@ internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = function
public external interface ThreeControlsProps : RProps { public external interface ThreeControlsProps : RProps {
public var canvas: ThreeCanvas public var canvasOptions: Canvas3DOptions
public var vision: Vision?
public var selected: Name? public var selected: Name?
public var onSelect: (Name) -> Unit public var onSelect: (Name) -> Unit
} }
@JsExport @JsExport
public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props -> public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props ->
val vision = props.canvas.content
ringSmartTabs(if (props.selected != null) "Properties" else null) { ringSmartTabs(if (props.selected != null) "Properties" else null) {
ringTab("Canvas") { ringTab("Canvas") {
ringIsland("Canvas configuration") { ringIsland("Canvas configuration") {
canvasControls(props.canvas) canvasControls(props.canvasOptions, props.vision)
} }
} }
ringTab("Tree") { ringTab("Tree") {
@ -113,7 +109,7 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
css { css {
flex(1.0, 1.0, FlexBasis.inherit) flex(1.0, 1.0, FlexBasis.inherit)
} }
props.canvas.content?.let { props.vision?.let {
objectTree(it, props.selected, props.onSelect) objectTree(it, props.selected, props.onSelect)
} }
} }
@ -123,8 +119,8 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
props.selected.let { selected -> props.selected.let { selected ->
val selectedObject: Vision? = when { val selectedObject: Vision? = when {
selected == null -> null selected == null -> null
selected.isEmpty() -> vision selected.isEmpty() -> props.vision
else -> (vision as? VisionGroup)?.get(selected) else -> (props.vision as? VisionGroup)?.get(selected)
} }
if (selectedObject != null) { if (selectedObject != null) {
ringPropertyEditor(selectedObject, key = selected) ringPropertyEditor(selectedObject, key = selected)
@ -136,13 +132,15 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
} }
public fun RBuilder.ringThreeControls( public fun RBuilder.ringThreeControls(
canvas: ThreeCanvas, canvasOptions: Canvas3DOptions,
vision: Vision?,
selected: Name?, selected: Name?,
onSelect: (Name) -> Unit = {}, onSelect: (Name) -> Unit = {},
builder: RBuilder.() -> Unit = {}, builder: RBuilder.() -> Unit = {},
): ReactElement = child(ThreeControls) { ): ReactElement = child(ThreeControls) {
attrs { attrs {
this.canvas = canvas this.canvasOptions = canvasOptions
this.vision = vision
this.selected = selected this.selected = selected
this.onSelect = onSelect this.onSelect = onSelect
} }

View File

@ -27,6 +27,9 @@ public interface Vision : Described, CoroutineScope {
*/ */
public var parent: VisionGroup? public var parent: VisionGroup?
/**
* Owner [VisionManager]. Used to define coroutine scope a serialization
*/
public val manager: VisionManager? get() = parent?.manager public val manager: VisionManager? get() = parent?.manager
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
@ -69,7 +72,7 @@ public interface Vision : Described, CoroutineScope {
/** /**
* Notify all listeners that a property has been changed and should be invalidated * Notify all listeners that a property has been changed and should be invalidated
*/ */
public fun invalidateProperty(propertyName: Name): Unit public fun invalidateProperty(propertyName: Name)
/** /**
* Update this vision using a dif represented by [VisionChange]. * Update this vision using a dif represented by [VisionChange].

View File

@ -92,7 +92,6 @@ public open class VisionBase : Vision {
} }
} }
//TODO check memory consumption for the flow //TODO check memory consumption for the flow
@Transient @Transient
private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow() private val propertyInvalidationFlow: MutableSharedFlow<Name> = MutableSharedFlow()

View File

@ -64,9 +64,15 @@ private fun Vision.isolate(manager: VisionManager): Vision {
return manager.decodeFromJson(json) return manager.decodeFromJson(json)
} }
/**
* @param void flag showing that this vision child should be removed
* @param vision a new value for vision content
* @param properties updated properties
* @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [void] flag to true.
*/
@Serializable @Serializable
public data class VisionChange( public data class VisionChange(
public val reset: Boolean = false, public val void: Boolean = false,
public val vision: Vision? = null, public val vision: Vision? = null,
@Serializable(MetaSerializer::class) public val properties: Meta? = null, @Serializable(MetaSerializer::class) public val properties: Meta? = null,
public val children: Map<Name, VisionChange>? = null, public val children: Map<Name, VisionChange>? = null,

View File

@ -134,7 +134,7 @@ public open class VisionGroupBase(
override fun update(change: VisionChange) { override fun update(change: VisionChange) {
change.children?.forEach { (name, change) -> change.children?.forEach { (name, change) ->
when { when {
change.reset -> set(name, null) change.void -> 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)?.update(change)
} }

View File

@ -96,3 +96,6 @@ public abstract class VisionPlugin(meta: Meta = Meta.EMPTY) : AbstractPlugin(met
* Fetch a [VisionManager] from this plugin or create a child plugin with a [VisionManager] * Fetch a [VisionManager] from this plugin or create a child plugin with a [VisionManager]
*/ */
public val Context.visionManager: VisionManager get() = fetch(VisionManager) public val Context.visionManager: VisionManager get() = fetch(VisionManager)
public fun Vision.encodeToString(): String =
manager?.encodeToString(this) ?: error("VisionManager not defined in Vision")

View File

@ -39,9 +39,8 @@ import kotlin.math.sin
*/ */
public class ThreeCanvas( public class ThreeCanvas(
public val three: ThreePlugin, public val three: ThreePlugin,
public val options: Canvas3DOptions = Canvas3DOptions()
) { ) {
public val options = Canvas3DOptions()
private var boundingBox: Box3? = null private var boundingBox: Box3? = null
private var root: Object3D? = null private var root: Object3D? = null
set(value) { set(value) {
@ -52,9 +51,6 @@ public class ThreeCanvas(
private val raycaster = Raycaster() private val raycaster = Raycaster()
private val mousePosition: Vector2 = Vector2() private val mousePosition: Vector2 = Vector2()
public var content: Solid? = null
private set
private val scene: Scene = Scene().apply { private val scene: Scene = Scene().apply {
options.useProperty(Canvas3DOptions::axes, this) { axesConfig -> options.useProperty(Canvas3DOptions::axes, this) { axesConfig ->
getObjectByName(AXES_NAME)?.let { remove(it) } getObjectByName(AXES_NAME)?.let { remove(it) }
@ -251,7 +247,6 @@ public class ThreeCanvas(
val object3D = three.buildObject3D(vision) val object3D = three.buildObject3D(vision)
object3D.name = "@root" object3D.name = "@root"
scene.add(object3D) scene.add(object3D)
content = vision
root = object3D root = object3D
} }
@ -315,9 +310,9 @@ public class ThreeCanvas(
} }
} }
public fun ThreeCanvas.configure(options: Canvas3DOptions) { //public fun ThreeCanvas.configure(newOptions: Canvas3DOptions) {
this.options.update(options.toMeta()) // this.options.update(newOptions.toMeta())
options.onChange(this) { name, _, newItem -> // options.onChange(this) { name, _, newItem ->
options[name] = newItem // this.options[name] = newItem
} // }
} //}

View File

@ -116,9 +116,12 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
public fun getOrCreateCanvas( public fun getOrCreateCanvas(
element: Element, element: Element,
): ThreeCanvas = canvasCache.getOrPut(element){ThreeCanvas(this).apply { options: Canvas3DOptions = Canvas3DOptions(),
): ThreeCanvas = canvasCache.getOrPut(element) {
ThreeCanvas(this, options).apply {
attach(element) attach(element)
}} }
}
override fun content(target: String): Map<Name, Any> { override fun content(target: String): Map<Name, Any> {
return when (target) { return when (target) {