Fix crash with single style properties
This commit is contained in:
parent
bd1f7d75fc
commit
dfc0ffda38
@ -1,17 +1,20 @@
|
||||
package space.kscience.visionforge.gdml.demo
|
||||
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.css.*
|
||||
import kotlinx.css.height
|
||||
import kotlinx.css.vh
|
||||
import org.w3c.files.FileReader
|
||||
import org.w3c.files.get
|
||||
import react.*
|
||||
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.fetch
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.gdml.Gdml
|
||||
import space.kscience.gdml.decodeFromString
|
||||
import space.kscience.visionforge.bootstrap.gridRow
|
||||
import space.kscience.visionforge.bootstrap.nameCrumbs
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
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.specifications.Canvas3DOptions
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
external interface GDMLAppProps : RProps {
|
||||
var context: Context
|
||||
@ -62,54 +64,57 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
|
||||
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 {
|
||||
this.context = props.context
|
||||
this.obj = vision
|
||||
this.selected = selected
|
||||
this.options = options
|
||||
lg = 9
|
||||
}
|
||||
}
|
||||
flexColumn {
|
||||
css {
|
||||
height = 100.vh
|
||||
}
|
||||
h1 { +"GDML/JSON loader demo" }
|
||||
//canvas
|
||||
|
||||
}
|
||||
flexColumn {
|
||||
css {
|
||||
+"col-lg-3"
|
||||
padding(top = 4.px)
|
||||
//border(1.px, BorderStyle.solid, Color.lightGray)
|
||||
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)
|
||||
child(ThreeCanvasComponent) {
|
||||
attrs {
|
||||
this.context = props.context
|
||||
this.solid = vision
|
||||
this.selected = selected
|
||||
this.options = options
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) {
|
||||
styledDiv {
|
||||
css {
|
||||
border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
|
||||
flexGrow = 0.0
|
||||
alignContent = Align.center
|
||||
}
|
||||
|
||||
|
27
demo/js-playground/build.gradle.kts
Normal file
27
demo/js-playground/build.gradle.kts
Normal 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"))
|
||||
}
|
51
demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt
Normal file
51
demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt
Normal 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)
|
||||
}
|
11
demo/js-playground/src/main/resources/index.html
Normal file
11
demo/js-playground/src/main/resources/index.html
Normal 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>
|
3
demo/js-playground/webpack.config.d/01.ring.js
vendored
Normal file
3
demo/js-playground/webpack.config.d/01.ring.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
||||
|
||||
config.module.rules.push(...ringConfig.module.rules)
|
@ -34,14 +34,6 @@ external interface MMAppProps : RProps {
|
||||
var selected: Name?
|
||||
}
|
||||
|
||||
private val canvasConfig = Canvas3DOptions {
|
||||
camera = Camera {
|
||||
distance = 2100.0
|
||||
latitude = PI / 6
|
||||
azimuth = PI + PI / 6
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
|
||||
var selected by useState { props.selected }
|
||||
@ -50,8 +42,13 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
|
||||
selected = it
|
||||
}
|
||||
|
||||
val options = useMemo {
|
||||
Canvas3DOptions.invoke {
|
||||
val mmOptions = useMemo {
|
||||
Canvas3DOptions {
|
||||
camera = Camera {
|
||||
distance = 2100.0
|
||||
latitude = PI / 6
|
||||
azimuth = PI + PI / 6
|
||||
}
|
||||
this.onSelect = onSelect
|
||||
}
|
||||
}
|
||||
@ -91,11 +88,9 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
|
||||
child(ThreeCanvasComponent) {
|
||||
attrs {
|
||||
this.context = props.context
|
||||
this.obj = root
|
||||
this.solid = root
|
||||
this.selected = selected
|
||||
this.options = canvasConfig.apply {
|
||||
this.onSelect = onSelect
|
||||
}
|
||||
this.options = mmOptions
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,7 +107,7 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
|
||||
}
|
||||
//settings
|
||||
card("Canvas configuration") {
|
||||
canvasControls(options, root)
|
||||
canvasControls(mmOptions, root)
|
||||
}
|
||||
|
||||
card("Events") {
|
||||
@ -151,7 +146,7 @@ val MMApp = functionalComponent<MMAppProps>("Muon monitor") { props ->
|
||||
+"World"
|
||||
attrs {
|
||||
onClickFunction = {
|
||||
selected = space.kscience.dataforge.names.Name.EMPTY
|
||||
selected = Name.EMPTY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.browser.document
|
||||
import react.child
|
||||
import react.dom.render
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.fetch
|
||||
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 context = Global.buildContext("demo") {}
|
||||
val context = Context("demo")
|
||||
render(element) {
|
||||
child(MMApp) {
|
||||
attrs {
|
||||
|
@ -3,7 +3,6 @@ package space.kscience.visionforge.examples
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.ResourceLocation
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
|
||||
fun main() {
|
||||
@ -11,7 +10,7 @@ fun main() {
|
||||
plugin(Solids)
|
||||
}
|
||||
|
||||
context.makeVisionFile( resourceLocation = ResourceLocation.EMBED) {
|
||||
context.makeVisionFile {
|
||||
vision("canvas") { GdmlShowCase.babyIaxo().toVision() }
|
||||
}
|
||||
}
|
@ -46,5 +46,6 @@ include(
|
||||
":demo:playground",
|
||||
":demo:jupyter-playground",
|
||||
":demo:plotly-fx",
|
||||
":demo:js-playground",
|
||||
":jupyter:visionforge-gdml-jupyter"
|
||||
)
|
@ -24,6 +24,11 @@ public external interface MetaViewerProps : RProps {
|
||||
*/
|
||||
public var root: Meta
|
||||
|
||||
/**
|
||||
* The title of root node
|
||||
*/
|
||||
public var rootName: String?
|
||||
|
||||
/**
|
||||
* 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 actualItem = item ?: descriptorItem?.defaultValue
|
||||
|
||||
val token = props.name.lastOrNull()?.toString() ?: "Meta"
|
||||
val token = props.name.lastOrNull()?.toString() ?: props.rootName ?: ""
|
||||
|
||||
val expanderClick: (Event) -> Unit = {
|
||||
expanded = !expanded
|
||||
|
@ -231,6 +231,7 @@ public val PropertyEditor: FunctionalComponent<PropertyEditorProps> = functional
|
||||
this.name = Name.EMPTY
|
||||
this.descriptor = props.descriptor
|
||||
this.scope = props.scope
|
||||
this.expanded = props.expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import kotlinx.css.margin
|
||||
import kotlinx.css.padding
|
||||
import kotlinx.css.px
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
@ -8,36 +11,63 @@ import react.FunctionalComponent
|
||||
import react.dom.attrs
|
||||
import react.functionalComponent
|
||||
import react.useState
|
||||
import space.kscience.dataforge.meta.double
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.values.asValue
|
||||
import styled.css
|
||||
import styled.styledInput
|
||||
|
||||
@JsExport
|
||||
public val RangeValueChooser: FunctionalComponent<ValueChooserProps> =
|
||||
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 newValue = (it.target as HTMLInputElement).value
|
||||
props.valueChanged?.invoke(newValue.toDoubleOrNull()?.asValue())
|
||||
innerValue = newValue
|
||||
innerValue = newValue.toDoubleOrNull()
|
||||
}
|
||||
|
||||
styledInput(type = InputType.range) {
|
||||
attrs {
|
||||
value = innerValue ?: ""
|
||||
onChangeFunction = handleChange
|
||||
val minValue = props.descriptor?.attributes?.get("min").string
|
||||
minValue?.let {
|
||||
min = it
|
||||
flexRow {
|
||||
styledInput(type = InputType.checkBox) {
|
||||
css{
|
||||
padding(0.px)
|
||||
margin(0.px)
|
||||
}
|
||||
val maxValue = props.descriptor?.attributes?.get("max").string
|
||||
maxValue?.let {
|
||||
max = it
|
||||
attrs {
|
||||
defaultChecked = rangeDisabled.not()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
package space.kscience.visionforge.react
|
||||
|
||||
import kotlinx.css.Display
|
||||
import kotlinx.css.display
|
||||
import kotlinx.css.height
|
||||
import kotlinx.css.pct
|
||||
import kotlinx.css.FlexBasis
|
||||
import kotlinx.css.flexBasis
|
||||
import kotlinx.css.flexGrow
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.HTMLElement
|
||||
import react.*
|
||||
@ -19,8 +18,8 @@ import styled.styledDiv
|
||||
|
||||
public external interface ThreeCanvasProps : RProps {
|
||||
public var context: Context
|
||||
public var options: Canvas3DOptions
|
||||
public var obj: Solid?
|
||||
public var options: Canvas3DOptions?
|
||||
public var solid: Solid?
|
||||
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))
|
||||
|
||||
useEffect(listOf(props.obj, props.options, elementRef)) {
|
||||
useEffect(listOf(props.solid, props.options, elementRef)) {
|
||||
if (canvas == null) {
|
||||
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)) {
|
||||
props.obj?.let { obj ->
|
||||
useEffect(listOf(canvas, props.solid)) {
|
||||
props.solid?.let { obj ->
|
||||
canvas?.render(obj)
|
||||
}
|
||||
}
|
||||
@ -56,8 +55,8 @@ public val ThreeCanvasComponent: FunctionalComponent<ThreeCanvasProps> = functio
|
||||
|
||||
styledDiv {
|
||||
css {
|
||||
display = Display.contents
|
||||
height = 100.pct
|
||||
flexGrow = 1.0
|
||||
flexBasis = FlexBasis.fill
|
||||
}
|
||||
ref = elementRef
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import styled.styledSelect
|
||||
public external interface ValueChooserProps : RProps {
|
||||
public var item: MetaItem?
|
||||
public var descriptor: ValueDescriptor?
|
||||
public var nullable: Boolean?
|
||||
public var valueChanged: ((Value?) -> Unit)?
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,14 @@ import react.RBuilder
|
||||
import react.RHandler
|
||||
import react.dom.WithClassName
|
||||
|
||||
public external interface SmartTabsProps: WithClassName {
|
||||
public external interface SmartTabsProps : WithClassName {
|
||||
public var initSelected: String
|
||||
}
|
||||
|
||||
|
||||
public fun RBuilder.ringSmartTabs(active: String? = null, handler: RHandler<SmartTabsProps>){
|
||||
TabsModule.SmartTabs{
|
||||
active?.let{
|
||||
public fun RBuilder.ringSmartTabs(active: String? = null, handler: RHandler<SmartTabsProps>) {
|
||||
TabsModule.SmartTabs {
|
||||
active?.let {
|
||||
attrs {
|
||||
initSelected = active
|
||||
}
|
||||
|
@ -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 {
|
||||
attrs {
|
||||
this.title = title
|
||||
this.id = id
|
||||
}
|
||||
handler()
|
||||
}
|
||||
|
@ -7,21 +7,20 @@ import ringui.grid.ringGrid
|
||||
import ringui.grid.ringRow
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.react.ThreeCanvasComponent
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import styled.css
|
||||
import styled.styledDiv
|
||||
|
||||
public external interface ThreeViewWithControlsProps : RProps {
|
||||
public external interface ThreeCanvasWithControlsProps : RProps {
|
||||
public var context: Context
|
||||
public var vision: Vision?
|
||||
public var solid: Solid?
|
||||
public var selected: Name?
|
||||
}
|
||||
|
||||
@JsExport
|
||||
public val ThreeViewWithControls: (props: ThreeViewWithControlsProps) -> dynamic =
|
||||
public val ThreeCanvasWithControls: (props: ThreeCanvasWithControlsProps) -> dynamic =
|
||||
functionalComponent("ThreeViewWithControls") { props ->
|
||||
var selected by useState { props.selected }
|
||||
val onSelect: (Name?) -> Unit = {
|
||||
@ -51,7 +50,7 @@ public val ThreeViewWithControls: (props: ThreeViewWithControlsProps) -> dynamic
|
||||
child(ThreeCanvasComponent) {
|
||||
attrs {
|
||||
this.context = props.context
|
||||
this.obj = props.vision as? Solid
|
||||
this.solid = props.solid as? Solid
|
||||
this.selected = selected
|
||||
this.options = options
|
||||
}
|
||||
@ -72,7 +71,7 @@ public val ThreeViewWithControls: (props: ThreeViewWithControlsProps) -> dynamic
|
||||
height = 100.pct
|
||||
overflowY = Overflow.auto
|
||||
}
|
||||
ringThreeControls(options, props.vision, selected, onSelect)
|
||||
ringThreeControls(options, props.solid, selected, onSelect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,10 @@ public class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer {
|
||||
|
||||
override fun render(element: Element, vision: Vision, meta: Meta) {
|
||||
react.dom.render(element) {
|
||||
child(ThreeViewWithControls) {
|
||||
child(ThreeCanvasWithControls) {
|
||||
attrs {
|
||||
this.context = this@ThreeWithControls.context
|
||||
this.vision = vision
|
||||
this.solid = vision as? Solid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package space.kscience.visionforge.ring
|
||||
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.dom.p
|
||||
import react.dom.render
|
||||
import react.useMemo
|
||||
import ringui.island.ringIsland
|
||||
import ringui.island.ringIslandContent
|
||||
import ringui.island.ringIslandHeader
|
||||
@ -10,6 +12,7 @@ import ringui.tabs.ringSmartTabs
|
||||
import ringui.tabs.ringTab
|
||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.react.flexColumn
|
||||
import space.kscience.visionforge.react.metaViewer
|
||||
import space.kscience.visionforge.react.propertyEditor
|
||||
import space.kscience.visionforge.solid.SolidReference
|
||||
@ -20,37 +23,55 @@ public fun RBuilder.ringPropertyEditor(
|
||||
key: Any? = null,
|
||||
) {
|
||||
|
||||
ringIsland("Properties") {
|
||||
propertyEditor(
|
||||
ownProperties = vision.ownProperties,
|
||||
allProperties = vision.allProperties(),
|
||||
updateFlow = vision.propertyChanges,
|
||||
descriptor = descriptor,
|
||||
key = key
|
||||
)
|
||||
val styles = useMemo(vision, key) {
|
||||
if (vision is SolidReference) {
|
||||
(vision.styles + vision.prototype.styles).distinct()
|
||||
} else {
|
||||
vision.styles
|
||||
}
|
||||
}
|
||||
val styles = if (vision is SolidReference) {
|
||||
(vision.styles + vision.prototype.styles).distinct()
|
||||
} else {
|
||||
vision.styles
|
||||
}
|
||||
if (styles.isNotEmpty()) {
|
||||
ringIsland {
|
||||
ringIslandHeader {
|
||||
attrs {
|
||||
border = true
|
||||
flexColumn {
|
||||
ringIsland("Properties") {
|
||||
propertyEditor(
|
||||
ownProperties = vision.ownProperties,
|
||||
allProperties = vision.allProperties(),
|
||||
updateFlow = vision.propertyChanges,
|
||||
descriptor = descriptor,
|
||||
key = key
|
||||
)
|
||||
}
|
||||
|
||||
if (styles.isNotEmpty()) {
|
||||
ringIsland {
|
||||
ringIslandHeader {
|
||||
attrs {
|
||||
border = true
|
||||
}
|
||||
+"Styles"
|
||||
}
|
||||
+"Styles"
|
||||
}
|
||||
ringIslandContent {
|
||||
ringSmartTabs {
|
||||
styles.forEach { styleName ->
|
||||
ringIslandContent {
|
||||
if (styles.size == 1) {
|
||||
val styleName = styles.first()
|
||||
p{
|
||||
+styleName
|
||||
}
|
||||
val style = vision.getStyle(styleName)
|
||||
if (style != null) {
|
||||
ringTab(styleName) {
|
||||
ringTab(styleName, id = styleName) {
|
||||
metaViewer(style)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ringSmartTabs {
|
||||
styles.forEach { styleName ->
|
||||
val style = vision.getStyle(styleName)
|
||||
if (style != null) {
|
||||
ringTab(styleName, id = styleName) {
|
||||
metaViewer(style)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,22 +92,25 @@ public external interface ThreeControlsProps : RProps {
|
||||
|
||||
@JsExport
|
||||
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") {
|
||||
ringIsland("Canvas configuration") {
|
||||
canvasControls(props.canvasOptions, props.vision)
|
||||
}
|
||||
}
|
||||
ringTab("Tree") {
|
||||
styledDiv {
|
||||
flexColumn {
|
||||
css {
|
||||
border(1.px, BorderStyle.solid, Color.lightGray)
|
||||
padding(10.px)
|
||||
flexGrow = 1.0
|
||||
flexWrap = FlexWrap.wrap
|
||||
}
|
||||
h2 { +"Object tree" }
|
||||
styledDiv {
|
||||
css {
|
||||
flex(1.0, 1.0, FlexBasis.inherit)
|
||||
overflowY = Overflow.auto
|
||||
flexGrow = 1.0
|
||||
}
|
||||
props.vision?.let {
|
||||
objectTree(it, props.selected, props.onSelect)
|
||||
@ -115,15 +118,17 @@ public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalCo
|
||||
}
|
||||
}
|
||||
}
|
||||
ringTab("Properties") {
|
||||
props.selected.let { selected ->
|
||||
val selectedObject: Vision? = when {
|
||||
selected == null -> null
|
||||
selected.isEmpty() -> props.vision
|
||||
else -> (props.vision as? VisionGroup)?.get(selected)
|
||||
}
|
||||
if (selectedObject != null) {
|
||||
ringPropertyEditor(selectedObject, key = selected)
|
||||
if (props.selected != null) {
|
||||
ringTab("Properties") {
|
||||
props.selected.let { selected ->
|
||||
val selectedObject: Vision? = when {
|
||||
selected == null -> null
|
||||
selected.isEmpty() -> props.vision
|
||||
else -> (props.vision as? VisionGroup)?.get(selected)
|
||||
}
|
||||
if (selectedObject != null) {
|
||||
ringPropertyEditor(selectedObject, key = selected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.visionforge.*
|
||||
|
||||
public interface SolidReference : Vision {
|
||||
public interface SolidReference : Solid {
|
||||
public val prototype: Solid
|
||||
}
|
||||
|
||||
@ -76,11 +76,7 @@ public class SolidReferenceGroup(
|
||||
return if (name.isEmpty()) prototype else {
|
||||
val proto = (prototype as? SolidGroup)?.get(name)
|
||||
?: error("Prototype with name $name not found in SolidReferenceGroup $refName")
|
||||
when (proto) {
|
||||
is Solid -> proto
|
||||
is SolidReference -> proto.prototype
|
||||
else -> error("Prototype with name $name is ${proto::class} but expected Solid")
|
||||
}
|
||||
proto as? Solid ?: 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 {
|
||||
|
||||
//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 children: Map<NameToken, Vision>
|
||||
|
@ -103,27 +103,31 @@ public class ThreeCanvas(
|
||||
}.apply {
|
||||
setClearColor(Colors.skyblue, 1)
|
||||
//Clipping planes
|
||||
localClippingEnabled = true
|
||||
options.onChange(this@ThreeCanvas) { name, _, _ ->
|
||||
if (name.startsWith(Canvas3DOptions::clipping.name.asName())) {
|
||||
localClippingEnabled = true
|
||||
val clipping = options.clipping
|
||||
boundingBox?.let { boundingBox ->
|
||||
val xClippingPlane = clipping.x?.let {
|
||||
val absoluteValue = boundingBox.min.x + (boundingBox.max.x - boundingBox.min.x) * it
|
||||
Plane(Vector3(-1.0, 0.0, 0.0), absoluteValue)
|
||||
if(!clipping.isEmpty()) {
|
||||
boundingBox?.let { boundingBox ->
|
||||
val xClippingPlane = clipping.x?.let {
|
||||
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 absoluteValue = boundingBox.min.y + (boundingBox.max.y - boundingBox.min.y) * it
|
||||
Plane(Vector3(0.0, -1.0, 0.0), absoluteValue)
|
||||
}
|
||||
}
|
||||
val yClippingPlane = clipping.y?.let {
|
||||
val absoluteValue = boundingBox.min.y + (boundingBox.max.y - boundingBox.min.y) * it
|
||||
Plane(Vector3(0.0, -1.0, 0.0), absoluteValue)
|
||||
}
|
||||
|
||||
val zClippingPlane = clipping.z?.let {
|
||||
val absoluteValue = boundingBox.min.z + (boundingBox.max.z - boundingBox.min.z) * it
|
||||
Plane(Vector3(0.0, 0.0, -1.0), absoluteValue)
|
||||
val zClippingPlane = clipping.z?.let {
|
||||
val absoluteValue = boundingBox.min.z + (boundingBox.max.z - boundingBox.min.z) * it
|
||||
Plane(Vector3(0.0, 0.0, -1.0), absoluteValue)
|
||||
}
|
||||
clippingPlanes = listOfNotNull(xClippingPlane, yClippingPlane, zClippingPlane).toTypedArray()
|
||||
}
|
||||
clippingPlanes = listOfNotNull(xClippingPlane, yClippingPlane, zClippingPlane).toTypedArray()
|
||||
}
|
||||
} else {
|
||||
localClippingEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user