Fix crash with single style properties

This commit is contained in:
Alexander Nozik 2021-06-08 18:45:03 +03:00
parent bd1f7d75fc
commit dfc0ffda38
23 changed files with 331 additions and 159 deletions

View File

@ -1,17 +1,20 @@
package space.kscience.visionforge.gdml.demo package space.kscience.visionforge.gdml.demo
import kotlinx.browser.window import kotlinx.browser.window
import kotlinx.css.* import kotlinx.css.height
import kotlinx.css.vh
import org.w3c.files.FileReader import org.w3c.files.FileReader
import org.w3c.files.get import org.w3c.files.get
import react.* import react.*
import react.dom.h1 import react.dom.h1
import ringui.grid.ringCol
import ringui.grid.ringGrid
import ringui.grid.ringRow
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch 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.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
import space.kscience.visionforge.react.ThreeCanvasComponent import space.kscience.visionforge.react.ThreeCanvasComponent
@ -21,7 +24,6 @@ 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 styled.css import styled.css
import styled.styledDiv
external interface GDMLAppProps : RProps { external interface GDMLAppProps : RProps {
var context: Context var context: Context
@ -62,54 +64,57 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
vision = parsedVision as? Solid ?: error("Parsed vision is not a solid") vision = parsedVision as? Solid ?: error("Parsed vision is not a solid")
} }
gridRow {
flexColumn {
css {
+"col-lg-9"
height = 100.vh
}
styledDiv {
css {
+"mx-auto"
+"page-header"
}
h1 { +"GDML/JSON loader demo" }
}
nameCrumbs(selected, "World", onSelect)
//canvas
child(ThreeCanvasComponent) { ringGrid {
ringRow {
ringCol {
attrs { attrs {
this.context = props.context lg = 9
this.obj = vision
this.selected = selected
this.options = options
} }
} flexColumn {
css {
height = 100.vh
}
h1 { +"GDML/JSON loader demo" }
//canvas
} child(ThreeCanvasComponent) {
flexColumn { attrs {
css { this.context = props.context
+"col-lg-3" this.solid = vision
padding(top = 4.px) this.selected = selected
//border(1.px, BorderStyle.solid, Color.lightGray) this.options = options
height = 100.vh
overflowY = Overflow.auto
}
fileDrop("(drag file here)") { files ->
val file = files?.get(0)
if (file != null) {
FileReader().apply {
onload = {
val string = result as String
loadData(file.name, string)
} }
readAsText(file)
} }
} }
}
ringCol {
attrs {
lg = 3
}
flexColumn {
css {
height = 100.vh
}
fileDrop("(drag file here)") { files ->
val file = files?.get(0)
if (file != null) {
FileReader().apply {
onload = {
val string = result as String
loadData(file.name, string)
}
readAsText(file)
}
}
}
nameCrumbs(selected, "World", onSelect)
ringThreeControls(options, vision, selected, onSelect)
}
} }
ringThreeControls(options, vision, selected, onSelect)
} }
} }
} }

View File

@ -14,6 +14,7 @@ fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) {
styledDiv { styledDiv {
css { css {
border(style = BorderStyle.dashed, width = 1.px, color = Color.orange) border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
flexGrow = 0.0
alignContent = Align.center alignContent = Align.center
} }

View File

@ -0,0 +1,27 @@
plugins {
id("ru.mipt.npm.gradle.js")
}
kscience{
useCoroutines()
application()
}
kotlin{
js(IR){
useCommonJs()
browser {
commonWebpackConfig {
cssSupport.enabled = false
}
}
}
}
dependencies{
implementation(project(":visionforge-gdml"))
implementation(project(":visionforge-plotly"))
implementation(project(":visionforge-threejs"))
implementation(project(":ui:ring"))
}

View File

@ -0,0 +1,51 @@
import kotlinx.browser.document
import kotlinx.css.height
import kotlinx.css.vh
import kotlinx.css.vw
import kotlinx.css.width
import react.child
import react.dom.render
import space.kscience.dataforge.context.Context
import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.Application
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.ThreeWithControls
import space.kscience.visionforge.startApplication
import styled.css
import styled.styledDiv
private class JsPlaygroundApp : Application {
override fun start(state: Map<String, Any>) {
val playgroundContext = Context {
plugin(ThreeWithControls)
plugin(VisionClient)
}
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
val visionOfD0 = GdmlShowCase.babyIaxo().toVision()
render(element) {
styledDiv {
css{
height = 100.vh
width = 100.vw
}
child(ThreeCanvasWithControls) {
attrs {
context = playgroundContext
solid = visionOfD0
}
}
}
}
}
}
public fun main() {
startApplication(::JsPlaygroundApp)
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js-playground</title>
<script src="js-playground.js"></script>
</head>
<body>
<div id="playground"></div>
</body>
</html>

View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -34,14 +34,6 @@ external interface MMAppProps : RProps {
var selected: Name? var selected: Name?
} }
private val canvasConfig = Canvas3DOptions {
camera = Camera {
distance = 2100.0
latitude = PI / 6
azimuth = PI + PI / 6
}
}
@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 }
@ -50,8 +42,13 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
selected = it selected = it
} }
val options = useMemo { val mmOptions = useMemo {
Canvas3DOptions.invoke { Canvas3DOptions {
camera = Camera {
distance = 2100.0
latitude = PI / 6
azimuth = PI + PI / 6
}
this.onSelect = onSelect this.onSelect = onSelect
} }
} }
@ -91,11 +88,9 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
child(ThreeCanvasComponent) { child(ThreeCanvasComponent) {
attrs { attrs {
this.context = props.context this.context = props.context
this.obj = root this.solid = root
this.selected = selected this.selected = selected
this.options = canvasConfig.apply { this.options = mmOptions
this.onSelect = onSelect
}
} }
} }
} }
@ -112,7 +107,7 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
} }
//settings //settings
card("Canvas configuration") { card("Canvas configuration") {
canvasControls(options, root) canvasControls(mmOptions, root)
} }
card("Events") { card("Events") {
@ -151,7 +146,7 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
+"World" +"World"
attrs { attrs {
onClickFunction = { onClickFunction = {
selected = space.kscience.dataforge.names.Name.EMPTY selected = Name.EMPTY
} }
} }
} }

View File

@ -6,6 +6,7 @@ import io.ktor.client.features.json.serializer.KotlinxSerializer
import kotlinx.browser.document import kotlinx.browser.document
import react.child import react.child
import react.dom.render import react.dom.render
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Global import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.fetch import space.kscience.dataforge.context.fetch
import space.kscience.visionforge.Application import space.kscience.visionforge.Application
@ -29,7 +30,7 @@ private class MMDemoApp : Application {
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page") val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
val context = Global.buildContext("demo") {} val context = Context("demo")
render(element) { render(element) {
child(MMApp) { child(MMApp) {
attrs { attrs {

View File

@ -3,7 +3,6 @@ package space.kscience.visionforge.examples
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.gdml.GdmlShowCase import space.kscience.gdml.GdmlShowCase
import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.solid.Solids import space.kscience.visionforge.solid.Solids
fun main() { fun main() {
@ -11,7 +10,7 @@ fun main() {
plugin(Solids) plugin(Solids)
} }
context.makeVisionFile( resourceLocation = ResourceLocation.EMBED) { context.makeVisionFile {
vision("canvas") { GdmlShowCase.babyIaxo().toVision() } vision("canvas") { GdmlShowCase.babyIaxo().toVision() }
} }
} }

View File

@ -46,5 +46,6 @@ include(
":demo:playground", ":demo:playground",
":demo:jupyter-playground", ":demo:jupyter-playground",
":demo:plotly-fx", ":demo:plotly-fx",
":demo:js-playground",
":jupyter:visionforge-gdml-jupyter" ":jupyter:visionforge-gdml-jupyter"
) )

View File

@ -24,6 +24,11 @@ public external interface MetaViewerProps : RProps {
*/ */
public var root: Meta public var root: Meta
/**
* The title of root node
*/
public var rootName: String?
/** /**
* Full path to the displayed node in [root]. Could be empty * Full path to the displayed node in [root]. Could be empty
*/ */
@ -45,7 +50,7 @@ private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
val actualItem = item ?: descriptorItem?.defaultValue val actualItem = item ?: descriptorItem?.defaultValue
val token = props.name.lastOrNull()?.toString() ?: "Meta" val token = props.name.lastOrNull()?.toString() ?: props.rootName ?: ""
val expanderClick: (Event) -> Unit = { val expanderClick: (Event) -> Unit = {
expanded = !expanded expanded = !expanded

View File

@ -231,6 +231,7 @@ public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functional
this.name = Name.EMPTY this.name = Name.EMPTY
this.descriptor = props.descriptor this.descriptor = props.descriptor
this.scope = props.scope this.scope = props.scope
this.expanded = props.expanded
} }
} }
} }

View File

@ -1,5 +1,8 @@
package space.kscience.visionforge.react package space.kscience.visionforge.react
import kotlinx.css.margin
import kotlinx.css.padding
import kotlinx.css.px
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onChangeFunction
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
@ -8,36 +11,63 @@ import react.FunctionalComponent
import react.dom.attrs import react.dom.attrs
import react.functionalComponent import react.functionalComponent
import react.useState import react.useState
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import styled.css
import styled.styledInput import styled.styledInput
@JsExport @JsExport
public val RangeValueChooser: FunctionalComponent<ValueChooserProps> = public val RangeValueChooser: FunctionalComponent<ValueChooserProps> =
functionalComponent("RangeValueChooser") { props -> functionalComponent("RangeValueChooser") { props ->
var innerValue by useState(props.item.string) var innerValue by useState(props.item.double)
var rangeDisabled: Boolean by useState(props.item == null)
val handleDisable: (Event) -> Unit = {
val checkBoxValue = (it.target as HTMLInputElement).checked
rangeDisabled = !checkBoxValue
if(!checkBoxValue) {
props.valueChanged?.invoke(null)
} else {
props.valueChanged?.invoke(innerValue?.asValue())
}
}
val handleChange: (Event) -> Unit = { val handleChange: (Event) -> Unit = {
val newValue = (it.target as HTMLInputElement).value val newValue = (it.target as HTMLInputElement).value
props.valueChanged?.invoke(newValue.toDoubleOrNull()?.asValue()) props.valueChanged?.invoke(newValue.toDoubleOrNull()?.asValue())
innerValue = newValue innerValue = newValue.toDoubleOrNull()
} }
styledInput(type = InputType.range) { flexRow {
attrs { styledInput(type = InputType.checkBox) {
value = innerValue ?: "" css{
onChangeFunction = handleChange padding(0.px)
val minValue = props.descriptor?.attributes?.get("min").string margin(0.px)
minValue?.let {
min = it
} }
val maxValue = props.descriptor?.attributes?.get("max").string attrs {
maxValue?.let { defaultChecked = rangeDisabled.not()
max = it onChangeFunction = handleDisable
} }
props.descriptor?.attributes?.get("step").string?.let { }
step = it
styledInput(type = InputType.range) {
attrs {
disabled = rangeDisabled
value = innerValue?.toString() ?: ""
onChangeFunction = handleChange
val minValue = props.descriptor?.attributes?.get("min").string
minValue?.let {
min = it
}
val maxValue = props.descriptor?.attributes?.get("max").string
maxValue?.let {
max = it
}
props.descriptor?.attributes?.get("step").string?.let {
step = it
}
} }
} }
} }

View File

@ -1,9 +1,8 @@
package space.kscience.visionforge.react package space.kscience.visionforge.react
import kotlinx.css.Display import kotlinx.css.FlexBasis
import kotlinx.css.display import kotlinx.css.flexBasis
import kotlinx.css.height import kotlinx.css.flexGrow
import kotlinx.css.pct
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import react.* import react.*
@ -19,8 +18,8 @@ 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 options: Canvas3DOptions?
public var obj: Solid? public var solid: Solid?
public var selected: Name? public var selected: Name?
} }
@ -37,15 +36,15 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
val three: ThreePlugin = useMemo({ props.context.fetch(ThreePlugin) }, arrayOf(props.context)) val three: ThreePlugin = useMemo({ props.context.fetch(ThreePlugin) }, arrayOf(props.context))
useEffect(listOf(props.obj, props.options, elementRef)) { useEffect(listOf(props.solid, 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")
canvas = three.getOrCreateCanvas(element, props.options) canvas = three.getOrCreateCanvas(element, props.options ?: Canvas3DOptions())
} }
} }
useEffect(listOf(canvas, props.obj)) { useEffect(listOf(canvas, props.solid)) {
props.obj?.let { obj -> props.solid?.let { obj ->
canvas?.render(obj) canvas?.render(obj)
} }
} }
@ -56,8 +55,8 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
styledDiv { styledDiv {
css { css {
display = Display.contents flexGrow = 1.0
height = 100.pct flexBasis = FlexBasis.fill
} }
ref = elementRef ref = elementRef
} }

View File

@ -21,6 +21,7 @@ import styled.styledSelect
public external interface ValueChooserProps : RProps { public external interface ValueChooserProps : RProps {
public var item: MetaItem? public var item: MetaItem?
public var descriptor: ValueDescriptor? public var descriptor: ValueDescriptor?
public var nullable: Boolean?
public var valueChanged: ((Value?) -> Unit)? public var valueChanged: ((Value?) -> Unit)?
} }

View File

@ -4,14 +4,14 @@ import react.RBuilder
import react.RHandler import react.RHandler
import react.dom.WithClassName import react.dom.WithClassName
public external interface SmartTabsProps: WithClassName { public external interface SmartTabsProps : WithClassName {
public var initSelected: String public var initSelected: String
} }
public fun RBuilder.ringSmartTabs(active: String? = null, handler: RHandler<SmartTabsProps>){ public fun RBuilder.ringSmartTabs(active: String? = null, handler: RHandler<SmartTabsProps>) {
TabsModule.SmartTabs{ TabsModule.SmartTabs {
active?.let{ active?.let {
attrs { attrs {
initSelected = active initSelected = active
} }

View File

@ -40,10 +40,11 @@ public fun RBuilder.ringTabs(active: String? = null, handler: RHandler<TabsProps
} }
} }
public fun RBuilder.ringTab(title: dynamic, handler: RHandler<TabProps>) { public fun RBuilder.ringTab(title: dynamic, id: String = title.toString(), handler: RHandler<TabProps>) {
TabsModule.Tab { TabsModule.Tab {
attrs { attrs {
this.title = title this.title = title
this.id = id
} }
handler() handler()
} }

View File

@ -7,21 +7,20 @@ import ringui.grid.ringGrid
import ringui.grid.ringRow import ringui.grid.ringRow
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.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 styled.css import styled.css
import styled.styledDiv import styled.styledDiv
public external interface ThreeViewWithControlsProps : RProps { public external interface ThreeCanvasWithControlsProps : RProps {
public var context: Context public var context: Context
public var vision: Vision? public var solid: Solid?
public var selected: Name? public var selected: Name?
} }
@JsExport @JsExport
public val ThreeViewWithControls: (props: ThreeViewWithControlsProps) -> dynamic = public val ThreeCanvasWithControls: (props: ThreeCanvasWithControlsProps) -> dynamic =
functionalComponent("ThreeViewWithControls") { props -> functionalComponent("ThreeViewWithControls") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
val onSelect: (Name?) -> Unit = { val onSelect: (Name?) -> Unit = {
@ -51,7 +50,7 @@ public val ThreeViewWithControls: (props: ThreeViewWithControlsProps) -> dynamic
child(ThreeCanvasComponent) { child(ThreeCanvasComponent) {
attrs { attrs {
this.context = props.context this.context = props.context
this.obj = props.vision as? Solid this.solid = props.solid as? Solid
this.selected = selected this.selected = selected
this.options = options this.options = options
} }
@ -72,7 +71,7 @@ public val ThreeViewWithControls: (props: ThreeViewWithControlsProps) -> dynamic
height = 100.pct height = 100.pct
overflowY = Overflow.auto overflowY = Overflow.auto
} }
ringThreeControls(options, props.vision, selected, onSelect) ringThreeControls(options, props.solid, selected, onSelect)
} }
} }
} }

View File

@ -25,10 +25,10 @@ public class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
override fun render(element: Element, vision: Vision, meta: Meta) { override fun render(element: Element, vision: Vision, meta: Meta) {
react.dom.render(element) { react.dom.render(element) {
child(ThreeViewWithControls) { child(ThreeCanvasWithControls) {
attrs { attrs {
this.context = this@ThreeWithControls.context this.context = this@ThreeWithControls.context
this.vision = vision this.solid = vision as? Solid
} }
} }
} }

View File

@ -2,7 +2,9 @@ package space.kscience.visionforge.ring
import org.w3c.dom.Element import org.w3c.dom.Element
import react.RBuilder import react.RBuilder
import react.dom.p
import react.dom.render import react.dom.render
import react.useMemo
import ringui.island.ringIsland import ringui.island.ringIsland
import ringui.island.ringIslandContent import ringui.island.ringIslandContent
import ringui.island.ringIslandHeader import ringui.island.ringIslandHeader
@ -10,6 +12,7 @@ import ringui.tabs.ringSmartTabs
import ringui.tabs.ringTab import ringui.tabs.ringTab
import space.kscience.dataforge.meta.descriptors.NodeDescriptor import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.visionforge.* import space.kscience.visionforge.*
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.metaViewer import space.kscience.visionforge.react.metaViewer
import space.kscience.visionforge.react.propertyEditor import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.solid.SolidReference import space.kscience.visionforge.solid.SolidReference
@ -20,37 +23,55 @@ public fun RBuilder.ringPropertyEditor(
key: Any? = null, key: Any? = null,
) { ) {
ringIsland("Properties") { val styles = useMemo(vision, key) {
propertyEditor( if (vision is SolidReference) {
ownProperties = vision.ownProperties, (vision.styles + vision.prototype.styles).distinct()
allProperties = vision.allProperties(), } else {
updateFlow = vision.propertyChanges, vision.styles
descriptor = descriptor, }
key = key
)
} }
val styles = if (vision is SolidReference) { flexColumn {
(vision.styles + vision.prototype.styles).distinct() ringIsland("Properties") {
} else { propertyEditor(
vision.styles ownProperties = vision.ownProperties,
} allProperties = vision.allProperties(),
if (styles.isNotEmpty()) { updateFlow = vision.propertyChanges,
ringIsland { descriptor = descriptor,
ringIslandHeader { key = key
attrs { )
border = true }
if (styles.isNotEmpty()) {
ringIsland {
ringIslandHeader {
attrs {
border = true
}
+"Styles"
} }
+"Styles" ringIslandContent {
} if (styles.size == 1) {
ringIslandContent { val styleName = styles.first()
ringSmartTabs { p{
styles.forEach { styleName -> +styleName
}
val style = vision.getStyle(styleName) val style = vision.getStyle(styleName)
if (style != null) { if (style != null) {
ringTab(styleName) { ringTab(styleName, id = styleName) {
metaViewer(style) metaViewer(style)
} }
} }
} else {
ringSmartTabs {
styles.forEach { styleName ->
val style = vision.getStyle(styleName)
if (style != null) {
ringTab(styleName, id = styleName) {
metaViewer(style)
}
}
}
}
} }
} }
} }

View File

@ -92,22 +92,25 @@ public external interface ThreeControlsProps : RProps {
@JsExport @JsExport
public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props -> public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props ->
ringSmartTabs(if (props.selected != null) "Properties" else null) { ringSmartTabs(if (props.selected != null) "Properties" else "Tree") {
ringTab("Canvas") { ringTab("Canvas") {
ringIsland("Canvas configuration") { ringIsland("Canvas configuration") {
canvasControls(props.canvasOptions, props.vision) canvasControls(props.canvasOptions, props.vision)
} }
} }
ringTab("Tree") { ringTab("Tree") {
styledDiv { flexColumn {
css { css {
border(1.px, BorderStyle.solid, Color.lightGray) border(1.px, BorderStyle.solid, Color.lightGray)
padding(10.px) padding(10.px)
flexGrow = 1.0
flexWrap = FlexWrap.wrap
} }
h2 { +"Object tree" } h2 { +"Object tree" }
styledDiv { styledDiv {
css { css {
flex(1.0, 1.0, FlexBasis.inherit) overflowY = Overflow.auto
flexGrow = 1.0
} }
props.vision?.let { props.vision?.let {
objectTree(it, props.selected, props.onSelect) objectTree(it, props.selected, props.onSelect)
@ -115,15 +118,17 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
} }
} }
} }
ringTab("Properties") { if (props.selected != null) {
props.selected.let { selected -> ringTab("Properties") {
val selectedObject: Vision? = when { props.selected.let { selected ->
selected == null -> null val selectedObject: Vision? = when {
selected.isEmpty() -> props.vision selected == null -> null
else -> (props.vision as? VisionGroup)?.get(selected) selected.isEmpty() -> props.vision
} else -> (props.vision as? VisionGroup)?.get(selected)
if (selectedObject != null) { }
ringPropertyEditor(selectedObject, key = selected) if (selectedObject != null) {
ringPropertyEditor(selectedObject, key = selected)
}
} }
} }
} }

View File

@ -11,7 +11,7 @@ import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import space.kscience.visionforge.* import space.kscience.visionforge.*
public interface SolidReference : Vision { public interface SolidReference : Solid {
public val prototype: Solid public val prototype: Solid
} }
@ -76,11 +76,7 @@ public class SolidReferenceGroup(
return if (name.isEmpty()) prototype else { return if (name.isEmpty()) prototype else {
val proto = (prototype as? SolidGroup)?.get(name) val proto = (prototype as? SolidGroup)?.get(name)
?: error("Prototype with name $name not found in SolidReferenceGroup $refName") ?: error("Prototype with name $name not found in SolidReferenceGroup $refName")
when (proto) { proto as? Solid ?: error("Prototype with name $name is ${proto::class} but expected Solid")
is Solid -> proto
is SolidReference -> proto.prototype
else -> error("Prototype with name $name is ${proto::class} but expected Solid")
}
} }
} }
@ -100,6 +96,22 @@ public class SolidReferenceGroup(
*/ */
private inner class ReferenceChild(private val childName: Name) : SolidReference, VisionGroup { private inner class ReferenceChild(private val childName: Name) : SolidReference, VisionGroup {
//TODO replace by properties
override var position: Point3D?
get() = prototype.position
set(value) {
error("Can't set position of reference")
}
override var rotation: Point3D?
get() = prototype.rotation
set(value) {
error("Can't set position of reference")
}
override var scale: Point3D?
get() = prototype.scale
set(value) {
error("Can't set position of reference")
}
override val prototype: Solid get() = prototypeFor(childName) override val prototype: Solid get() = prototypeFor(childName)
override val children: Map<NameToken, Vision> override val children: Map<NameToken, Vision>

View File

@ -103,27 +103,31 @@ public class ThreeCanvas(
}.apply { }.apply {
setClearColor(Colors.skyblue, 1) setClearColor(Colors.skyblue, 1)
//Clipping planes //Clipping planes
localClippingEnabled = true
options.onChange(this@ThreeCanvas) { name, _, _ -> options.onChange(this@ThreeCanvas) { name, _, _ ->
if (name.startsWith(Canvas3DOptions::clipping.name.asName())) { if (name.startsWith(Canvas3DOptions::clipping.name.asName())) {
localClippingEnabled = true
val clipping = options.clipping val clipping = options.clipping
boundingBox?.let { boundingBox -> if(!clipping.isEmpty()) {
val xClippingPlane = clipping.x?.let { boundingBox?.let { boundingBox ->
val absoluteValue = boundingBox.min.x + (boundingBox.max.x - boundingBox.min.x) * it val xClippingPlane = clipping.x?.let {
Plane(Vector3(-1.0, 0.0, 0.0), absoluteValue) val absoluteValue = boundingBox.min.x + (boundingBox.max.x - boundingBox.min.x) * it
Plane(Vector3(-1.0, 0.0, 0.0), absoluteValue)
} }
val yClippingPlane = clipping.y?.let { val yClippingPlane = clipping.y?.let {
val absoluteValue = boundingBox.min.y + (boundingBox.max.y - boundingBox.min.y) * it val absoluteValue = boundingBox.min.y + (boundingBox.max.y - boundingBox.min.y) * it
Plane(Vector3(0.0, -1.0, 0.0), absoluteValue) Plane(Vector3(0.0, -1.0, 0.0), absoluteValue)
} }
val zClippingPlane = clipping.z?.let { val zClippingPlane = clipping.z?.let {
val absoluteValue = boundingBox.min.z + (boundingBox.max.z - boundingBox.min.z) * it val absoluteValue = boundingBox.min.z + (boundingBox.max.z - boundingBox.min.z) * it
Plane(Vector3(0.0, 0.0, -1.0), absoluteValue) Plane(Vector3(0.0, 0.0, -1.0), absoluteValue)
}
clippingPlanes = listOfNotNull(xClippingPlane, yClippingPlane, zClippingPlane).toTypedArray()
} }
clippingPlanes = listOfNotNull(xClippingPlane, yClippingPlane, zClippingPlane).toTypedArray()
} }
} else {
localClippingEnabled = false
} }
} }
} }