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