Name breadcrumbs in property editor for #10
This commit is contained in:
parent
d36542ac5b
commit
9e43d2c572
@ -61,6 +61,7 @@ data class StyleRef(val group: VisualGroup, val styleName: Name)
|
||||
|
||||
val VisualGroup.isEmpty: Boolean get() = this.children.isEmpty()
|
||||
|
||||
|
||||
interface MutableVisualGroup : VisualGroup {
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,8 @@
|
||||
package hep.dataforge.vis.js.editor
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.isEmpty
|
||||
@ -15,58 +17,62 @@ import kotlin.dom.clear
|
||||
fun Element.objectTree(
|
||||
token: NameToken,
|
||||
obj: VisualObject,
|
||||
clickCallback: (VisualObject) -> Unit = {}
|
||||
clickCallback: (Name, VisualObject) -> Unit = {_,_->}
|
||||
) {
|
||||
clear()
|
||||
append {
|
||||
card("Object tree") {
|
||||
subTree(token, obj, clickCallback)
|
||||
subTree(Name.EMPTY, token, obj, clickCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TagConsumer<HTMLElement>.subTree(
|
||||
parentName: Name,
|
||||
token: NameToken,
|
||||
obj: VisualObject,
|
||||
clickCallback: (VisualObject) -> Unit
|
||||
clickCallback: (Name, VisualObject) -> Unit
|
||||
) {
|
||||
val fullName = parentName + token
|
||||
|
||||
if (obj is VisualGroup && !obj.isEmpty) {
|
||||
//display as node if any child is visible
|
||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
||||
lateinit var toggle: HTMLSpanElement
|
||||
div("d-inline-block text-truncate") {
|
||||
toggle = span("objTree-caret")
|
||||
label("objTree-label") {
|
||||
+token.toString()
|
||||
onClickFunction = { clickCallback(obj) }
|
||||
onClickFunction = { clickCallback(fullName, obj) }
|
||||
}
|
||||
}
|
||||
val subtree = ul("objTree-subtree")
|
||||
toggle.onclick = {
|
||||
toggle.classList.toggle("objTree-caret-down")
|
||||
subtree.apply {
|
||||
//If expanded, add children dynamically
|
||||
if (toggle.classList.contains("objTree-caret-down")) {
|
||||
obj.children.entries
|
||||
.filter { !it.key.toString().startsWith("@") }
|
||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
||||
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
||||
.forEach { (token, child) ->
|
||||
.forEach { (childToken, child) ->
|
||||
append {
|
||||
li().apply {
|
||||
subTree(token, child, clickCallback)
|
||||
subTree(fullName, childToken, child, clickCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if not, clear them to conserve memory on very long lists
|
||||
this.clear()
|
||||
}
|
||||
}
|
||||
//jQuery(subtree).asDynamic().collapse("toggle")
|
||||
}
|
||||
} else {
|
||||
div("d-inline-block text-truncate") {
|
||||
val div = div("d-inline-block text-truncate") {
|
||||
span("objTree-leaf")
|
||||
label("objTree-label") {
|
||||
+token.toString()
|
||||
onClickFunction = { clickCallback(obj) }
|
||||
onClickFunction = { clickCallback(fullName, obj) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ import hep.dataforge.js.jsObject
|
||||
import hep.dataforge.meta.DynamicMeta
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.update
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.findStyle
|
||||
import kotlinx.html.dom.append
|
||||
import kotlinx.html.js.div
|
||||
import kotlinx.html.js.h4
|
||||
import kotlinx.html.js.*
|
||||
import org.w3c.dom.Element
|
||||
import kotlin.dom.clear
|
||||
|
||||
@ -17,40 +18,51 @@ import kotlin.dom.clear
|
||||
fun Meta.toDynamic() = JSON.parse<dynamic>(toJson().toString())
|
||||
|
||||
//TODO add node descriptor instead of configuring property selector
|
||||
fun Element.propertyEditor(item: VisualObject?, propertySelector: (VisualObject) -> Meta = { it.config }) {
|
||||
fun Element.propertyEditor(name: Name, item: VisualObject, propertySelector: (VisualObject) -> Meta = { it.config }) {
|
||||
clear()
|
||||
if (item != null) {
|
||||
append {
|
||||
card("Properties") {
|
||||
val dMeta: dynamic = propertySelector(item).toDynamic()
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "form"
|
||||
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
|
||||
}
|
||||
JSONEditor(div(), options, dMeta)
|
||||
}
|
||||
|
||||
val styles = item.styles
|
||||
if (styles.isNotEmpty()) {
|
||||
card("Styles") {
|
||||
item.styles.forEach { style ->
|
||||
val styleMeta = item.findStyle(style)
|
||||
h4("container") { +style }
|
||||
if (styleMeta != null) {
|
||||
div("container").apply {
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "view"
|
||||
}
|
||||
JSONEditor(
|
||||
this,
|
||||
options,
|
||||
styleMeta.toDynamic()
|
||||
)
|
||||
append {
|
||||
card("Properties") {
|
||||
if(!name.isEmpty()) {
|
||||
nav {
|
||||
attributes["aria-label"] = "breadcrumb"
|
||||
ol("breadcrumb") {
|
||||
name.tokens.forEach {token->
|
||||
li("breadcrumb-item") {
|
||||
+token.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val dMeta: dynamic = propertySelector(item).toDynamic()
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "form"
|
||||
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
|
||||
}
|
||||
JSONEditor(div(), options, dMeta)
|
||||
}
|
||||
|
||||
val styles = item.styles
|
||||
if (styles.isNotEmpty()) {
|
||||
card("Styles") {
|
||||
item.styles.forEach { style ->
|
||||
val styleMeta = item.findStyle(style)
|
||||
h4("container") { +style }
|
||||
if (styleMeta != null) {
|
||||
div("container").apply {
|
||||
val options: JSONEditorOptions = jsObject {
|
||||
mode = "view"
|
||||
}
|
||||
JSONEditor(
|
||||
this,
|
||||
options,
|
||||
styleMeta.toDynamic()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) {
|
||||
Box::class with Box.serializer()
|
||||
Convex::class with Convex.serializer()
|
||||
Extruded::class with Extruded.serializer()
|
||||
addSubclass(PolyLine.serializer())
|
||||
addSubclass(Label3D.serializer())
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ package hep.dataforge.vis.spatial.gdml.demo
|
||||
|
||||
import hep.dataforge.context.Global
|
||||
import hep.dataforge.js.Application
|
||||
import hep.dataforge.vis.js.editor.objectTree
|
||||
import hep.dataforge.js.startApplication
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.meta.withBottom
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.vis.js.editor.objectTree
|
||||
import hep.dataforge.vis.js.editor.propertyEditor
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||
@ -159,8 +159,8 @@ private class GDMLDemoApp : Application {
|
||||
output.camera.layers.set(0)
|
||||
configElement.threeSettings(output)
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(NameToken("World"), visual) {
|
||||
editorElement.propertyEditor(it) { item ->
|
||||
treeElement.objectTree(NameToken("World"), visual) { objName, obj ->
|
||||
editorElement.propertyEditor(objName, obj) { item ->
|
||||
//val descriptorMeta = Material3D.descriptor
|
||||
|
||||
val properties = item.allProperties()
|
||||
|
@ -35,7 +35,7 @@ private class GDMLDemoApp : Application {
|
||||
|
||||
private val model = Model()
|
||||
|
||||
private val connection = HttpClient{
|
||||
private val connection = HttpClient {
|
||||
install(JsonFeature) {
|
||||
serializer = KotlinxSerializer(Visual3DPlugin.json)
|
||||
}
|
||||
@ -52,7 +52,6 @@ private class GDMLDemoApp : Application {
|
||||
document.getElementById("settings") ?: error("Element with id 'settings' not found on page")
|
||||
val treeElement = document.getElementById("tree") ?: error("Element with id 'tree' not found on page")
|
||||
val editorElement = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
|
||||
canvasElement.clear()
|
||||
|
||||
canvasElement.clear()
|
||||
val visual: VisualObject3D = model.root
|
||||
@ -63,7 +62,7 @@ private class GDMLDemoApp : Application {
|
||||
output.camera.layers.set(0)
|
||||
output.camera.position.z = -2000.0
|
||||
output.camera.position.y = 500.0
|
||||
settingsElement.threeSettings(output){
|
||||
settingsElement.threeSettings(output) {
|
||||
card("Events") {
|
||||
button {
|
||||
+"Next"
|
||||
@ -83,8 +82,8 @@ private class GDMLDemoApp : Application {
|
||||
}
|
||||
}
|
||||
//tree.visualObjectTree(visual, editor::propertyEditor)
|
||||
treeElement.objectTree(NameToken("World"), visual) {
|
||||
editorElement.propertyEditor(it) { item ->
|
||||
treeElement.objectTree(NameToken("World"), visual) { name, obj ->
|
||||
editorElement.propertyEditor(name, obj) { item ->
|
||||
//val descriptorMeta = Material3D.descriptor
|
||||
|
||||
val properties = item.allProperties()
|
||||
@ -99,10 +98,7 @@ private class GDMLDemoApp : Application {
|
||||
properties.withBottom(bottom)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output.render(visual)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,13 +19,15 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="row" id ="settings"></div>
|
||||
<div class="row" id ="tree"></div>
|
||||
<div class="row" id="tree"></div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="container" id = "canvas"></div>
|
||||
<div id="canvas"></div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="row" id="settings"></div>
|
||||
<div class="row" id="editor"></div>
|
||||
</div>
|
||||
<div class="col-lg-3" id="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user