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
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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?
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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() }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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"
|
||||||
)
|
)
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user