From d1e2d8d60bef8ed248537e59a57b4670d14e0d23 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 1 Oct 2019 22:22:13 +0300 Subject: [PATCH] New Proxy child styling and json editor --- .../vis/common/AbstractVisualGroup.kt | 41 +- .../vis/common/AbstractVisualObject.kt | 14 +- .../{VisualGroup.kt => MutableVisualGroup.kt} | 22 +- .../hep/dataforge/vis/common/VisualObject.kt | 12 +- .../vis/spatial/gdml/GDMLTransformer.kt | 32 +- .../vis/spatial/gdml/optimizations.kt | 8 +- .../vis/spatial/gdml/demo/GDMLDemoApp.kt | 10 +- .../jsMain/web/css/img/jsoneditor-icons.svg | 748 ++++++++++++++++++ .../src/jsMain/web/css/jsoneditor.min.css | 6 + .../src/jsMain/web/index.html | 1 + .../dataforge/vis/spatial/gdml/testMain.kt | 23 +- dataforge-vis-spatial/build.gradle.kts | 1 + .../kotlin/hep/dataforge/vis/spatial/Proxy.kt | 84 +- .../dataforge/vis/spatial/Visual3DPlugin.kt | 4 +- .../dataforge/vis/spatial/VisualGroup3D.kt | 54 +- .../dataforge/vis/spatial/VisualObject3D.kt | 17 +- .../vis/spatial/three/ThreeProxyFactory.kt | 7 +- .../vis/spatial/tree/jsVisualTree.kt | 21 +- .../dataforge/vis/spatial/tree/jsonEditor.kt | 185 +++++ .../vis/spatial/tree/propertyEditor.kt | 19 +- 20 files changed, 1145 insertions(+), 164 deletions(-) rename dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/{VisualGroup.kt => MutableVisualGroup.kt} (93%) create mode 100644 dataforge-vis-spatial-gdml/src/jsMain/web/css/img/jsoneditor-icons.svg create mode 100644 dataforge-vis-spatial-gdml/src/jsMain/web/css/jsoneditor.min.css create mode 100644 dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsonEditor.kt diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt index ba2fabb0..fda6c7fc 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualGroup.kt @@ -1,18 +1,16 @@ package hep.dataforge.vis.common +import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaItem -import hep.dataforge.names.Name -import hep.dataforge.names.NameToken -import hep.dataforge.names.asName -import hep.dataforge.names.isEmpty +import hep.dataforge.names.* import kotlinx.serialization.Transient /** * Abstract implementation of group of [VisualObject] */ -abstract class AbstractVisualGroup : AbstractVisualObject(), VisualGroup { +abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup { //protected abstract val _children: MutableMap @@ -21,6 +19,32 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), VisualGroup { */ abstract override val children: Map //get() = _children + //TODO replace by custom object with get/set functionality + protected abstract val styles: MutableMap + + override fun getStyle(name: Name): Meta? = styles[name] + + override fun setStyle(name: Name, meta: Meta) { + fun VisualObject.applyStyle(name: Name, meta: Meta) { + if (style.contains(name.toString())) { + //full update + //TODO do a fine grained update + if (this is AbstractVisualObject) { + styleChanged() + } else { + propertyChanged(EmptyName) + } + } + if (this is VisualGroup) { + this.children.forEach { (_, child) -> + child.applyStyle(name, meta) + } + } + } + styles[name] = meta + applyStyle(name, meta) + } + // init { // //Do after deserialization @@ -75,12 +99,13 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), VisualGroup { /** * Add a static child. Statics could not be found by name, removed or replaced */ - protected abstract fun addStatic(child: VisualObject) + protected open fun addStatic(child: VisualObject) = + setChild(NameToken("@static(${child.hashCode()})"), child) /** * Recursively create a child group */ - protected abstract fun createGroup(name: Name): VisualGroup + protected abstract fun createGroup(name: Name): MutableVisualGroup /** * Add named or unnamed child to the group. If key is [null] the child is considered unnamed. Both key and value are not @@ -103,7 +128,7 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), VisualGroup { } else -> { //TODO add safety check - val parent = (get(name.cutLast()) as? VisualGroup) ?: createGroup(name.cutLast()) + val parent = (get(name.cutLast()) as? MutableVisualGroup) ?: createGroup(name.cutLast()) parent[name.last()!!.asName()] = child } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt index 6624b0b1..385c9360 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/AbstractVisualObject.kt @@ -17,12 +17,13 @@ abstract class AbstractVisualObject : VisualObject { @Transient override var parent: VisualObject? = null - protected abstract var properties: Config? + abstract override var properties: Config? override var style: List get() = properties?.let { it[STYLE_KEY].stringList } ?: emptyList() set(value) { - setProperty(VisualObject.STYLE_KEY, value) + setProperty(STYLE_KEY, value) + styleChanged() } /** @@ -57,12 +58,11 @@ abstract class AbstractVisualObject : VisualObject { private var styleCache: Laminate? = null - private fun styles(): Laminate { - return styleCache ?: kotlin.run { + protected val actualStyles: Laminate + get() = styleCache ?: run { Laminate(style.map { it.toName() }.mapNotNull(::findStyle)) .also { styleCache = it } } - } /** * Helper to reset style cache @@ -74,9 +74,9 @@ abstract class AbstractVisualObject : VisualObject { override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { - properties?.get(name) ?: parent?.getProperty(name, inherit) ?: styles()[name] + properties?.get(name) ?: parent?.getProperty(name, inherit) ?: actualStyles[name] } else { - properties?.get(name) ?: styles()[name] + properties?.get(name) ?: actualStyles[name] } } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt similarity index 93% rename from dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt rename to dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt index 4288d640..f3b1ca7d 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualGroup.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/MutableVisualGroup.kt @@ -4,7 +4,7 @@ import hep.dataforge.meta.Meta import hep.dataforge.names.* import hep.dataforge.provider.Provider -interface VisualGroup : VisualObject, Provider, Iterable { +interface VisualGroup : Provider, Iterable, VisualObject { /** * A map of top level named children */ @@ -26,6 +26,7 @@ interface VisualGroup : VisualObject, Provider, Iterable { else -> emptyMap() } + /** * Iterate over children of this group */ @@ -42,6 +43,17 @@ interface VisualGroup : VisualObject, Provider, Iterable { */ fun setStyle(name: Name, meta: Meta) + operator fun get(name: Name): VisualObject? { + return when { + name.isEmpty() -> this + name.length == 1 -> children[name.first()!!] + else -> (children[name.first()!!] as? VisualGroup)?.get(name.cutFirst()) + } + } +} + +interface MutableVisualGroup : VisualGroup { + /** * Add listener for children structure change. * @param owner the handler to properly remove listeners @@ -54,14 +66,6 @@ interface VisualGroup : VisualObject, Provider, Iterable { */ fun removeChildrenChangeListener(owner: Any?) - operator fun get(name: Name): VisualObject? { - return when { - name.isEmpty() -> this - name.length == 1 -> children[name.first()!!] - else -> (children[name.first()!!] as? VisualGroup)?.get(name.cutFirst()) - } - } - operator fun set(name: Name, child: VisualObject?) } diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt index a9600be6..4a5ce8b3 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/common/VisualObject.kt @@ -1,5 +1,6 @@ package hep.dataforge.vis.common +import hep.dataforge.meta.Config import hep.dataforge.meta.Configurable import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaRepr @@ -25,6 +26,11 @@ interface VisualObject : MetaRepr, Configurable { @Transient var parent: VisualObject? + /** + * Direct properties access + */ + val properties: Config? + /** * Set property for this object */ @@ -62,4 +68,8 @@ interface VisualObject : MetaRepr, Configurable { } fun VisualObject.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = getProperty(key.toName(), inherit) -fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(), value) \ No newline at end of file +fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(), value) + +fun VisualObject.applyStyle(name: String) { + style = style + name +} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt index 85d8ddec..da1c7f67 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/GDMLTransformer.kt @@ -1,13 +1,18 @@ package hep.dataforge.vis.spatial.gdml import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.buildMeta +import hep.dataforge.names.Name import hep.dataforge.names.toName import hep.dataforge.vis.common.Colors +import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.common.applyStyle import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualObject3D -import hep.dataforge.vis.spatial.material +import hep.dataforge.vis.spatial.VisualObject3D.Companion.COLOR_KEY import scientifik.gdml.* +import kotlin.collections.set import kotlin.random.Random class GDMLTransformer(val root: GDML) { @@ -24,25 +29,33 @@ class GDMLTransformer(val root: GDML) { * A special group for local templates */ val templates by lazy { VisualGroup3D() } + private val styles = HashMap() var lUnit: LUnit = LUnit.MM var solidAction: (GDMLSolid) -> Action = { Action.CACHE } - var volumeAction: (GDMLGroup) -> Action = { Action.ACCEPT } + var volumeAction: (GDMLGroup) -> Action = { Action.CACHE } var solidConfiguration: VisualObject3D.(parent: GDMLVolume, solid: GDMLSolid) -> Unit = { _, _ -> } + fun VisualObject.useStyle(name: String, builder: MetaBuilder.() -> Unit) { + styles.getOrPut(name.toName()){ + buildMeta(builder) + } + applyStyle(name) + } + internal fun configureSolid(obj: VisualObject3D, parent: GDMLVolume, solid: GDMLSolid) { val material = parent.materialref.resolve(root) ?: GDMLElement(parent.materialref.ref) - val materialColor = materialCache.getOrPut(material) { - buildMeta { - "color" to Colors.rgbToString(random.nextInt(0, Int.MAX_VALUE)) - } + val styleName = "material[${material.name}]" + + obj.useStyle(styleName){ + COLOR_KEY to Colors.rgbToString(random.nextInt(0, Int.MAX_VALUE)) + "gdml.material" to material.name } - obj.setProperty("gdml.material".toName(), material.name) - obj.material = materialColor + obj.solidConfiguration(parent, solid) } @@ -72,6 +85,9 @@ class GDMLTransformer(val root: GDML) { // res = it(res) // } final.templates = templates + styles.forEach { + final.setStyle(it.key, it.value) + } onFinish(this@GDMLTransformer) return final } diff --git a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/optimizations.kt b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/optimizations.kt index ef842aa7..bf077d72 100644 --- a/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/optimizations.kt +++ b/dataforge-vis-spatial-gdml/src/commonMain/kotlin/hep/dataforge/vis/spatial/gdml/optimizations.kt @@ -2,7 +2,7 @@ package hep.dataforge.vis.spatial.gdml import hep.dataforge.meta.update import hep.dataforge.names.asName -import hep.dataforge.vis.common.VisualGroup +import hep.dataforge.vis.common.MutableVisualGroup import hep.dataforge.vis.spatial.Point3D import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualObject3D @@ -16,7 +16,7 @@ typealias GDMLOptimization = GDMLTransformer.(VisualGroup3D) -> VisualGroup3D * Collapse nodes with single child */ val optimizeSingleChild: GDMLOptimization = { tree -> - fun VisualGroup.replaceChildren() { + fun MutableVisualGroup.replaceChildren() { children.forEach { (key, child) -> if (child is VisualGroup3D && child.children.size == 1) { val newChild = child.children.values.first().apply { @@ -40,13 +40,13 @@ val optimizeSingleChild: GDMLOptimization = { tree -> } } - if (newChild is VisualGroup) { + if (newChild is MutableVisualGroup) { newChild.replaceChildren() } //actual replacement set(key.asName(), newChild) - } else if (child is VisualGroup) { + } else if (child is MutableVisualGroup) { child.replaceChildren() } } diff --git a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt index b55529fc..49f8a382 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt +++ b/dataforge-vis-spatial-gdml/src/jsMain/kotlin/hep/dataforge/vis/spatial/gdml/demo/GDMLDemoApp.kt @@ -57,11 +57,11 @@ private class GDMLDemoApp : ApplicationBase() { onload = { val string = result as String - try { +// try { block(file.name, string) - } catch (ex: Exception) { - console.error(ex) - } +// } catch (ex: Exception) { +// console.error(ex) +// } } readAsText(file) @@ -190,7 +190,7 @@ private class GDMLDemoApp : ApplicationBase() { if (visual is VisualGroup) { visual.toTree(editor::propertyEditor).render(tree as HTMLElement) { - showCheckboxes = true + showCheckboxes = false } } diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/css/img/jsoneditor-icons.svg b/dataforge-vis-spatial-gdml/src/jsMain/web/css/img/jsoneditor-icons.svg new file mode 100644 index 00000000..332be179 --- /dev/null +++ b/dataforge-vis-spatial-gdml/src/jsMain/web/css/img/jsoneditor-icons.svg @@ -0,0 +1,748 @@ + + + JSON Editor Icons + + + + image/svg+xml + + JSON Editor Icons + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/css/jsoneditor.min.css b/dataforge-vis-spatial-gdml/src/jsMain/web/css/jsoneditor.min.css new file mode 100644 index 00000000..e436fb54 --- /dev/null +++ b/dataforge-vis-spatial-gdml/src/jsMain/web/css/jsoneditor.min.css @@ -0,0 +1,6 @@ +.jsoneditor .search input{height:auto;border:inherit;border:none;box-shadow:none}.jsoneditor table{border-collapse:collapse;width:auto}.jsoneditor td,.jsoneditor th{padding:0;display:table-cell;text-align:left;vertical-align:inherit;border-radius:inherit}.jsoneditor{color:#1a1a1a;border:thin solid #3883fa;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;height:100%;position:relative;padding:0;line-height:100%}div.jsoneditor-default,div.jsoneditor-field,div.jsoneditor-readonly,div.jsoneditor-value{border:1px solid transparent;min-height:16px;min-width:32px;padding:2px;margin:1px;word-wrap:break-word;float:left}div.jsoneditor-field p,div.jsoneditor-value p{margin:0}div.jsoneditor-value{word-break:break-word}div.jsoneditor-value.jsoneditor-empty::after{content:"value"}div.jsoneditor-value.jsoneditor-string{color:#006000}div.jsoneditor-value.jsoneditor-number{color:#ee422e}div.jsoneditor-value.jsoneditor-boolean{color:#ff8c00}div.jsoneditor-value.jsoneditor-null{color:#004ed0}div.jsoneditor-value.jsoneditor-invalid{color:#000}div.jsoneditor-readonly{min-width:16px;color:grey}div.jsoneditor-empty{border-color:#d3d3d3;border-style:dashed;border-radius:2px}div.jsoneditor-field.jsoneditor-empty::after{content:"field"}div.jsoneditor td{vertical-align:top}div.jsoneditor td.jsoneditor-separator{padding:3px 0;vertical-align:top;color:grey}div.jsoneditor td.jsoneditor-tree{vertical-align:top}div.jsoneditor div.jsoneditor-anchor{cursor:pointer}div.jsoneditor div.jsoneditor-anchor .picker_wrapper.popup.popup_bottom{top:28px;left:-10px}div.jsoneditor.busy pre.jsoneditor-preview{background:#f5f5f5;color:grey}div.jsoneditor.busy div.jsoneditor-busy{display:inherit}div.jsoneditor code.jsoneditor-preview{background:0 0}div.jsoneditor.jsoneditor-mode-preview pre.jsoneditor-preview{width:100%;height:100%;box-sizing:border-box;overflow:auto;padding:2px;margin:0;white-space:pre-wrap;word-break:break-all}div.jsoneditor-default{color:grey;padding-left:10px}div.jsoneditor-tree{width:100%;height:100%;position:relative;overflow:auto}div.jsoneditor-tree button.jsoneditor-button{width:24px;height:24px;padding:0;margin:0;border:none;cursor:pointer;background:transparent url(img/jsoneditor-icons.svg)}div.jsoneditor-tree button.jsoneditor-button:focus{background-color:#f5f5f5;outline:#e5e5e5 solid 1px}div.jsoneditor-tree button.jsoneditor-collapsed{background-position:0 -48px}div.jsoneditor-tree button.jsoneditor-expanded{background-position:0 -72px}div.jsoneditor-tree button.jsoneditor-contextmenu{background-position:-48px -72px}div.jsoneditor-tree button.jsoneditor-invisible{visibility:hidden;background:0 0}div.jsoneditor-tree button.jsoneditor-dragarea{background:url(img/jsoneditor-icons.svg) -72px -72px;cursor:move}div.jsoneditor-tree :focus{outline:0}div.jsoneditor-tree div.jsoneditor-show-more{display:inline-block;padding:3px 4px;margin:2px 0;background-color:#e5e5e5;border-radius:3px;color:grey;font-family:arial,sans-serif;font-size:10pt}div.jsoneditor-tree div.jsoneditor-show-more a{display:inline-block;color:grey}div.jsoneditor-tree div.jsoneditor-color{display:inline-block;width:12px;height:12px;margin:4px;border:1px solid grey;cursor:pointer}div.jsoneditor-tree div.jsoneditor-date{background:#a1a1a1;color:#fff;font-family:arial,sans-serif;border-radius:3px;display:inline-block;padding:3px;margin:0 3px}div.jsoneditor-tree table.jsoneditor-tree{border-collapse:collapse;border-spacing:0;width:100%}div.jsoneditor-tree .jsoneditor-button.jsoneditor-schema-error{width:24px;height:24px;padding:0;margin:0 4px 0 0;background:url(img/jsoneditor-icons.svg) -168px -48px}div.jsoneditor-outer{position:static;width:100%;height:100%;margin:0;padding:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}div.jsoneditor-outer.has-nav-bar{margin-top:-26px;padding-top:26px}div.jsoneditor-outer.has-nav-bar.has-main-menu-bar{margin-top:-61px;padding-top:61px}div.jsoneditor-outer.has-status-bar{margin-bottom:-26px;padding-bottom:26px}div.jsoneditor-outer.has-main-menu-bar{margin-top:-35px;padding-top:35px}div.jsoneditor-busy{position:absolute;top:15%;left:0;box-sizing:border-box;width:100%;text-align:center;display:none}div.jsoneditor-busy span{background-color:#ffffab;border:1px solid #fe0;border-radius:3px;padding:5px 15px;box-shadow:0 0 5px rgba(0,0,0,.4)}div.jsoneditor-field.jsoneditor-empty::after,div.jsoneditor-value.jsoneditor-empty::after{pointer-events:none;color:#d3d3d3;font-size:8pt}a.jsoneditor-value.jsoneditor-url,div.jsoneditor-value.jsoneditor-url{color:#006000;text-decoration:underline}a.jsoneditor-value.jsoneditor-url{display:inline-block;padding:2px;margin:2px}a.jsoneditor-value.jsoneditor-url:focus,a.jsoneditor-value.jsoneditor-url:hover{color:#ee422e}div.jsoneditor-field.jsoneditor-highlight,div.jsoneditor-field[contenteditable=true]:focus,div.jsoneditor-field[contenteditable=true]:hover,div.jsoneditor-value.jsoneditor-highlight,div.jsoneditor-value[contenteditable=true]:focus,div.jsoneditor-value[contenteditable=true]:hover{background-color:#ffffab;border:1px solid #fe0;border-radius:2px}div.jsoneditor-field.jsoneditor-highlight-active,div.jsoneditor-field.jsoneditor-highlight-active:focus,div.jsoneditor-field.jsoneditor-highlight-active:hover,div.jsoneditor-value.jsoneditor-highlight-active,div.jsoneditor-value.jsoneditor-highlight-active:focus,div.jsoneditor-value.jsoneditor-highlight-active:hover{background-color:#fe0;border:1px solid #ffc700;border-radius:2px}div.jsoneditor-value.jsoneditor-array,div.jsoneditor-value.jsoneditor-object{min-width:16px}div.jsoneditor-mode-form tr.jsoneditor-expandable td.jsoneditor-tree,div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree{cursor:pointer}div.jsoneditor-tree button.jsoneditor-contextmenu.jsoneditor-selected,div.jsoneditor-tree button.jsoneditor-contextmenu:focus,div.jsoneditor-tree button.jsoneditor-contextmenu:hover,tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu{background-position:-48px -48px}div.jsoneditor-tree div.jsoneditor-show-more a:focus,div.jsoneditor-tree div.jsoneditor-show-more a:hover{color:#ee422e}.ace-jsoneditor,textarea.jsoneditor-text{min-height:150px}textarea.jsoneditor-text{width:100%;height:100%;margin:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;outline-width:0;border:none;background-color:#fff;resize:none}tr.jsoneditor-highlight,tr.jsoneditor-selected{background-color:#d3d3d3}tr.jsoneditor-selected button.jsoneditor-contextmenu,tr.jsoneditor-selected button.jsoneditor-dragarea{visibility:hidden}tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu,tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea{visibility:visible}div.jsoneditor-tree button.jsoneditor-dragarea:focus,div.jsoneditor-tree button.jsoneditor-dragarea:hover,tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea{background-position:-72px -48px}div.jsoneditor td,div.jsoneditor th,div.jsoneditor tr{padding:0;margin:0}.jsoneditor-popover,.jsoneditor-schema-error,div.jsoneditor td,div.jsoneditor textarea,div.jsoneditor th,div.jsoneditor-field,div.jsoneditor-value,pre.jsoneditor-preview{font-family:"dejavu sans mono","droid sans mono",consolas,monaco,"lucida console","courier new",courier,monospace,sans-serif;font-size:10pt;color:#1a1a1a}.jsoneditor-schema-error{cursor:default;display:inline-block;height:24px;line-height:24px;position:relative;text-align:center;width:24px}.jsoneditor-popover{background-color:#4c4c4c;border-radius:3px;box-shadow:0 0 5px rgba(0,0,0,.4);color:#fff;padding:7px 10px;position:absolute;cursor:auto;width:200px;z-index:999}.jsoneditor-popover.jsoneditor-above{bottom:32px;left:-98px}.jsoneditor-popover.jsoneditor-above:before{border-top:7px solid #4c4c4c;bottom:-7px}.jsoneditor-popover.jsoneditor-below{top:32px;left:-98px}.jsoneditor-popover.jsoneditor-below:before{border-bottom:7px solid #4c4c4c;top:-7px}.jsoneditor-popover.jsoneditor-left{top:-7px;right:32px}.jsoneditor-popover.jsoneditor-left:before{border-left:7px solid #4c4c4c;border-top:7px solid transparent;border-bottom:7px solid transparent;content:"";top:19px;right:-14px;left:inherit;margin-left:inherit;margin-top:-7px;position:absolute}.jsoneditor-popover.jsoneditor-right{top:-7px;left:32px}.jsoneditor-popover.jsoneditor-right:before{border-right:7px solid #4c4c4c;border-top:7px solid transparent;border-bottom:7px solid transparent;content:"";top:19px;left:-14px;margin-left:inherit;margin-top:-7px;position:absolute}.jsoneditor-popover:before{border-right:7px solid transparent;border-left:7px solid transparent;content:"";display:block;left:50%;margin-left:-7px;position:absolute}.jsoneditor-text-errors tr.jump-to-line:hover{text-decoration:underline;cursor:pointer}.jsoneditor-schema-error:focus .jsoneditor-popover,.jsoneditor-schema-error:hover .jsoneditor-popover{display:block;animation:fade-in .3s linear 1,move-up .3s linear 1}@keyframes fade-in{from{opacity:0}to{opacity:1}}.jsoneditor .jsoneditor-validation-errors-container{max-height:130px;overflow-y:auto}.jsoneditor .jsoneditor-validation-errors{width:100%;overflow:hidden}.jsoneditor .jsoneditor-additional-errors{position:absolute;margin:auto;bottom:31px;left:calc(50% - 92px);color:grey;background-color:#ebebeb;padding:7px 15px;border-radius:8px}.jsoneditor .jsoneditor-additional-errors.visible{visibility:visible;opacity:1;transition:opacity 2s linear}.jsoneditor .jsoneditor-additional-errors.hidden{visibility:hidden;opacity:0;transition:visibility 0s 2s,opacity 2s linear}.jsoneditor .jsoneditor-text-errors{width:100%;border-collapse:collapse;border-top:1px solid #ffc700}.jsoneditor .jsoneditor-text-errors td{padding:3px 6px;vertical-align:middle}.jsoneditor .jsoneditor-text-errors td pre{margin:0;white-space:normal}.jsoneditor .jsoneditor-text-errors tr{background-color:#ffffab}.jsoneditor .jsoneditor-text-errors tr.parse-error{background-color:#ee2e2e70}.jsoneditor-text-errors .jsoneditor-schema-error{border:none;width:24px;height:24px;padding:0;margin:0 4px 0 0;cursor:pointer}.jsoneditor-text-errors tr .jsoneditor-schema-error{background:url(img/jsoneditor-icons.svg) -168px -48px}.jsoneditor-text-errors tr.parse-error .jsoneditor-schema-error{background:url(img/jsoneditor-icons.svg) -25px 0}.fadein{-webkit-animation:fadein .3s;animation:fadein .3s;-moz-animation:fadein .3s;-o-animation:fadein .3s}@keyframes fadein{0%{opacity:0}100%{opacity:1}}.jsoneditor-contextmenu-root{position:relative;width:0;height:0}.jsoneditor-contextmenu{position:absolute;box-sizing:content-box;z-index:99}.jsoneditor-contextmenu .jsoneditor-menu{position:relative;left:0;top:0;width:128px;height:auto;background:#fff;border:1px solid #d3d3d3;box-shadow:2px 2px 12px rgba(128,128,128,.3);list-style:none;margin:0;padding:0}.jsoneditor-contextmenu .jsoneditor-menu button{position:relative;padding:0 4px 0 0;margin:0;width:128px;height:auto;border:none;cursor:pointer;color:#4d4d4d;background:0 0;font-size:10pt;font-family:arial,sans-serif;box-sizing:border-box;text-align:left}.jsoneditor-contextmenu .jsoneditor-menu button::-moz-focus-inner{padding:0;border:0}.jsoneditor-contextmenu .jsoneditor-menu button.jsoneditor-default{width:96px}.jsoneditor-contextmenu .jsoneditor-menu button.jsoneditor-expand{float:right;width:32px;height:24px;border-left:1px solid #e5e5e5}.jsoneditor-contextmenu .jsoneditor-menu li{overflow:hidden}.jsoneditor-contextmenu .jsoneditor-menu li ul{display:none;position:relative;left:-10px;top:0;border:none;box-shadow:inset 0 0 10px rgba(128,128,128,.5);padding:0 10px;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.jsoneditor-contextmenu .jsoneditor-menu li ul .jsoneditor-icon{margin-left:24px}.jsoneditor-contextmenu .jsoneditor-menu li ul li button{padding-left:24px;animation:all ease-in-out 1s}.jsoneditor-contextmenu .jsoneditor-menu li button .jsoneditor-expand{position:absolute;top:0;right:0;width:24px;height:24px;padding:0;margin:0 4px 0 0;background:url(img/jsoneditor-icons.svg) 0 -72px}.jsoneditor-contextmenu .jsoneditor-icon{position:absolute;top:0;left:0;width:24px;height:24px;border:none;padding:0;margin:0;background-image:url(img/jsoneditor-icons.svg)}.jsoneditor-contextmenu .jsoneditor-text{padding:4px 0 4px 24px;word-wrap:break-word}.jsoneditor-contextmenu .jsoneditor-text.jsoneditor-right-margin{padding-right:24px}.jsoneditor-contextmenu .jsoneditor-separator{height:0;border-top:1px solid #e5e5e5;padding-top:5px;margin-top:5px}.jsoneditor-contextmenu button.jsoneditor-remove .jsoneditor-icon{background-position:-24px 0}.jsoneditor-contextmenu button.jsoneditor-append .jsoneditor-icon{background-position:0 0}.jsoneditor-contextmenu button.jsoneditor-insert .jsoneditor-icon{background-position:0 0}.jsoneditor-contextmenu button.jsoneditor-duplicate .jsoneditor-icon{background-position:-48px 0}.jsoneditor-contextmenu button.jsoneditor-sort-asc .jsoneditor-icon{background-position:-168px 0}.jsoneditor-contextmenu button.jsoneditor-sort-desc .jsoneditor-icon{background-position:-192px 0}.jsoneditor-contextmenu button.jsoneditor-transform .jsoneditor-icon{background-position:-216px 0}.jsoneditor-contextmenu button.jsoneditor-extract .jsoneditor-icon{background-position:0 -24px}.jsoneditor-contextmenu button.jsoneditor-type-string .jsoneditor-icon{background-position:-144px 0}.jsoneditor-contextmenu button.jsoneditor-type-auto .jsoneditor-icon{background-position:-120px 0}.jsoneditor-contextmenu button.jsoneditor-type-object .jsoneditor-icon{background-position:-72px 0}.jsoneditor-contextmenu button.jsoneditor-type-array .jsoneditor-icon{background-position:-96px 0}.jsoneditor-contextmenu button.jsoneditor-type-modes .jsoneditor-icon{background-image:none;width:6px}.jsoneditor-contextmenu li,.jsoneditor-contextmenu ul{box-sizing:content-box;position:relative}.jsoneditor-contextmenu .jsoneditor-menu button:focus,.jsoneditor-contextmenu .jsoneditor-menu button:hover{color:#1a1a1a;background-color:#f5f5f5;outline:0}.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected,.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected:focus,.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected:hover{color:#fff;background-color:#ee422e}.jsoneditor-contextmenu .jsoneditor-menu li ul li button:focus,.jsoneditor-contextmenu .jsoneditor-menu li ul li button:hover{background-color:#f5f5f5}.jsoneditor-modal{max-width:95%;border-radius:2px!important;padding:45px 15px 15px 15px!important;box-shadow:2px 2px 12px rgba(128,128,128,.3);color:#4d4d4d;line-height:1.3em}.jsoneditor-modal.jsoneditor-modal-transform{width:600px!important}.jsoneditor-modal .pico-modal-header{position:absolute;box-sizing:border-box;top:0;left:0;width:100%;padding:0 10px;height:30px;line-height:30px;font-family:arial,sans-serif;font-size:11pt;background:#3883fa;color:#fff}.jsoneditor-modal table{width:100%}.jsoneditor-modal table td{padding:3px 0}.jsoneditor-modal table td.jsoneditor-modal-input{text-align:right;padding-right:0;white-space:nowrap}.jsoneditor-modal table td.jsoneditor-modal-actions{padding-top:15px}.jsoneditor-modal table th{vertical-align:middle}.jsoneditor-modal p:first-child{margin-top:0}.jsoneditor-modal a{color:#3883fa}.jsoneditor-modal .jsoneditor-jmespath-block{margin-bottom:10px}.jsoneditor-modal .pico-close{background:0 0!important;font-size:24px!important;top:7px!important;right:7px!important;color:#fff}.jsoneditor-modal input{padding:4px}.jsoneditor-modal input[type=text]{cursor:inherit}.jsoneditor-modal input[disabled]{background:#d3d3d3;color:grey}.jsoneditor-modal .jsoneditor-select-wrapper{position:relative;display:inline-block}.jsoneditor-modal .jsoneditor-select-wrapper:after{content:"";width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:6px solid #666;position:absolute;right:8px;top:14px;pointer-events:none}.jsoneditor-modal select{padding:3px 24px 3px 10px;min-width:180px;max-width:350px;-webkit-appearance:none;-moz-appearance:none;appearance:none;text-indent:0;text-overflow:"";font-size:10pt;line-height:1.5em}.jsoneditor-modal select::-ms-expand{display:none}.jsoneditor-modal .jsoneditor-button-group input{padding:4px 10px;margin:0;border-radius:0;border-left-style:none}.jsoneditor-modal .jsoneditor-button-group input.jsoneditor-button-first{border-top-left-radius:3px;border-bottom-left-radius:3px;border-left-style:solid}.jsoneditor-modal .jsoneditor-button-group input.jsoneditor-button-last{border-top-right-radius:3px;border-bottom-right-radius:3px}.jsoneditor-modal .jsoneditor-transform-preview{background:#f5f5f5;height:200px}.jsoneditor-modal .jsoneditor-transform-preview.jsoneditor-error{color:#ee422e}.jsoneditor-modal .jsoneditor-jmespath-wizard{line-height:1.2em;width:100%;padding:0;border-radius:3px}.jsoneditor-modal .jsoneditor-jmespath-label{font-weight:700;color:#1e90ff;margin-top:20px;margin-bottom:5px}.jsoneditor-modal .jsoneditor-jmespath-wizard-table{width:100%}.jsoneditor-modal .jsoneditor-jmespath-wizard-label{font-style:italic;margin:4px 0 2px 0}.jsoneditor-modal .jsoneditor-inline{position:relative;display:inline-block;width:100%;padding-top:2px;padding-bottom:2px}.jsoneditor-modal .jsoneditor-inline:not(:last-child){padding-right:2px}.jsoneditor-modal .jsoneditor-jmespath-filter{display:flex;flex-wrap:wrap}.jsoneditor-modal .jsoneditor-jmespath-filter-field{width:180px}.jsoneditor-modal .jsoneditor-jmespath-filter-relation{width:100px}.jsoneditor-modal .jsoneditor-jmespath-filter-value{min-width:180px;flex:1}.jsoneditor-modal .jsoneditor-jmespath-sort-field{width:170px}.jsoneditor-modal .jsoneditor-jmespath-sort-order{width:150px}.jsoneditor-modal .jsoneditor-jmespath-select-fields{width:100%}.jsoneditor-modal .selectr-selected{border-color:#d3d3d3;padding:4px 28px 4px 8px}.jsoneditor-modal .selectr-selected .selectr-tag{background-color:#3883fa;border-radius:5px}.jsoneditor-modal table td,.jsoneditor-modal table th{text-align:left;vertical-align:top;font-weight:400;color:#4d4d4d;border-spacing:0;border-collapse:collapse}.jsoneditor-modal #query,.jsoneditor-modal input,.jsoneditor-modal select,.jsoneditor-modal textarea{background:#fff;border:1px solid #d3d3d3;color:#4d4d4d;border-radius:3px;padding:4px}.jsoneditor-modal,.jsoneditor-modal #query,.jsoneditor-modal input,.jsoneditor-modal option,.jsoneditor-modal select,.jsoneditor-modal table td,.jsoneditor-modal table th,.jsoneditor-modal textarea{font-size:10.5pt;font-family:arial,sans-serif}.jsoneditor-modal #query,.jsoneditor-modal .jsoneditor-transform-preview{font-family:"dejavu sans mono","droid sans mono",consolas,monaco,"lucida console","courier new",courier,monospace,sans-serif;font-size:10pt;width:100%;box-sizing:border-box}.jsoneditor-modal input[type=button],.jsoneditor-modal input[type=submit]{background:#f5f5f5;padding:4px 20px}.jsoneditor-modal input,.jsoneditor-modal select{cursor:pointer}.jsoneditor-modal .jsoneditor-button-group.jsoneditor-button-group-value-asc input.jsoneditor-button-asc,.jsoneditor-modal .jsoneditor-button-group.jsoneditor-button-group-value-desc input.jsoneditor-button-desc{background:#3883fa;border-color:#3883fa;color:#fff}.jsoneditor-menu{width:100%;height:35px;padding:2px;margin:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;background-color:#3883fa;border-bottom:1px solid #3883fa}.jsoneditor-menu>.jsoneditor-modes>button,.jsoneditor-menu>button{width:26px;height:26px;margin:2px;padding:0;border-radius:2px;border:1px solid transparent;background:transparent url(img/jsoneditor-icons.svg);color:#fff;opacity:.8;font-family:arial,sans-serif;font-size:10pt;float:left}.jsoneditor-menu>.jsoneditor-modes>button:hover,.jsoneditor-menu>button:hover{background-color:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.4)}.jsoneditor-menu>.jsoneditor-modes>button:active,.jsoneditor-menu>.jsoneditor-modes>button:focus,.jsoneditor-menu>button:active,.jsoneditor-menu>button:focus{background-color:rgba(255,255,255,.3)}.jsoneditor-menu>.jsoneditor-modes>button:disabled,.jsoneditor-menu>button:disabled{opacity:.5;background-color:transparent;border:none}.jsoneditor-menu>button.jsoneditor-collapse-all{background-position:0 -96px}.jsoneditor-menu>button.jsoneditor-expand-all{background-position:0 -120px}.jsoneditor-menu>button.jsoneditor-sort{background-position:-120px -96px}.jsoneditor-menu>button.jsoneditor-transform{background-position:-144px -96px}.jsoneditor.jsoneditor-mode-form>.jsoneditor-menu>button.jsoneditor-sort,.jsoneditor.jsoneditor-mode-form>.jsoneditor-menu>button.jsoneditor-transform,.jsoneditor.jsoneditor-mode-view>.jsoneditor-menu>button.jsoneditor-sort,.jsoneditor.jsoneditor-mode-view>.jsoneditor-menu>button.jsoneditor-transform{display:none}.jsoneditor-menu>button.jsoneditor-undo{background-position:-24px -96px}.jsoneditor-menu>button.jsoneditor-undo:disabled{background-position:-24px -120px}.jsoneditor-menu>button.jsoneditor-redo{background-position:-48px -96px}.jsoneditor-menu>button.jsoneditor-redo:disabled{background-position:-48px -120px}.jsoneditor-menu>button.jsoneditor-compact{background-position:-72px -96px}.jsoneditor-menu>button.jsoneditor-format{background-position:-72px -120px}.jsoneditor-menu>button.jsoneditor-repair{background-position:-96px -96px}.jsoneditor-menu>.jsoneditor-modes{display:inline-block;float:left}.jsoneditor-menu>.jsoneditor-modes>button{background-image:none;width:auto;padding-left:6px;padding-right:6px}.jsoneditor-menu>.jsoneditor-modes>button.jsoneditor-separator,.jsoneditor-menu>button.jsoneditor-separator{margin-left:10px}.jsoneditor-menu a{font-family:arial,sans-serif;font-size:10pt;color:#fff;opacity:.8;vertical-align:middle}.jsoneditor-menu a:hover{opacity:1}.jsoneditor-menu a.jsoneditor-poweredBy{font-size:8pt;position:absolute;right:0;top:0;padding:10px}.jsoneditor-search{font-family:arial,sans-serif;position:absolute;right:4px;top:4px;border-collapse:collapse;border-spacing:0;display:flex}.jsoneditor-search input{color:#1a1a1a;width:120px;border:none;outline:0;margin:1px;line-height:20px}.jsoneditor-search button{width:16px;height:24px;padding:0;margin:0;border:none;background:url(img/jsoneditor-icons.svg);vertical-align:top}.jsoneditor-search button:hover{background-color:transparent}.jsoneditor-search button.jsoneditor-refresh{width:18px;background-position:-99px -73px}.jsoneditor-search button.jsoneditor-next{cursor:pointer;background-position:-124px -73px}.jsoneditor-search button.jsoneditor-next:hover{background-position:-124px -49px}.jsoneditor-search button.jsoneditor-previous{cursor:pointer;background-position:-148px -73px;margin-right:2px}.jsoneditor-search button.jsoneditor-previous:hover{background-position:-148px -49px}.jsoneditor-results{font-family:arial,sans-serif;color:#fff;padding-right:5px;line-height:26px}.jsoneditor-frame{border:1px solid transparent;background-color:#fff;padding:0 2px;margin:0}.jsoneditor .autocomplete.dropdown{position:absolute;background:#fff;box-shadow:2px 2px 12px rgba(128,128,128,.3);border:1px solid #d3d3d3;z-index:100;overflow-x:hidden;overflow-y:auto;cursor:default;margin:0;padding:5px;text-align:left;outline:0;font-family:"dejavu sans mono","droid sans mono",consolas,monaco,"lucida console","courier new",courier,monospace,sans-serif;font-size:10pt}.jsoneditor .autocomplete.dropdown .item{color:#333}.jsoneditor .autocomplete.dropdown .item.hover{background-color:#ddd}.jsoneditor .autocomplete.hint{color:#aaa;top:4px;left:4px}.jsoneditor-treepath{padding:0 5px;overflow:hidden;white-space:nowrap;outline:0}.jsoneditor-treepath.show-all{word-wrap:break-word;white-space:normal;position:absolute;background-color:#ebebeb;z-index:999;box-shadow:2px 2px 12px rgba(128,128,128,.3)}.jsoneditor-treepath.show-all span.jsoneditor-treepath-show-all-btn{display:none}.jsoneditor-treepath div.jsoneditor-contextmenu-root{position:absolute;left:0}.jsoneditor-treepath .jsoneditor-treepath-show-all-btn{position:absolute;background-color:#ebebeb;left:0;height:20px;padding:0 3px;cursor:pointer}.jsoneditor-treepath .jsoneditor-treepath-element{margin:1px;font-family:arial,sans-serif;font-size:10pt}.jsoneditor-treepath .jsoneditor-treepath-seperator{margin:2px;font-size:9pt;font-family:arial,sans-serif}.jsoneditor-treepath span.jsoneditor-treepath-element:hover,.jsoneditor-treepath span.jsoneditor-treepath-seperator:hover{cursor:pointer;text-decoration:underline}.jsoneditor-statusbar{line-height:26px;height:26px;color:grey;background-color:#ebebeb;border-top:1px solid #d3d3d3;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-size:10pt}.jsoneditor-statusbar>.jsoneditor-curserinfo-val{margin-right:12px}.jsoneditor-statusbar>.jsoneditor-curserinfo-count{margin-left:4px}.jsoneditor-statusbar>.jsoneditor-validation-error-icon{float:right;width:24px;height:24px;padding:0;margin-top:1px;background:url(img/jsoneditor-icons.svg) -168px -48px;cursor:pointer}.jsoneditor-statusbar>.jsoneditor-validation-error-count{float:right;margin:0 4px 0 0;cursor:pointer}.jsoneditor-statusbar>.jsoneditor-parse-error-icon{float:right;width:24px;height:24px;padding:0;margin:1px;background:url(img/jsoneditor-icons.svg) -25px 0}.jsoneditor-statusbar .jsoneditor-array-info a{color:inherit}div.jsoneditor-statusbar>.jsoneditor-curserinfo-label,div.jsoneditor-statusbar>.jsoneditor-size-info{margin:0 4px}.jsoneditor-navigation-bar{width:100%;height:26px;line-height:26px;padding:0;margin:0;border-bottom:1px solid #d3d3d3;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;color:grey;background-color:#ebebeb;overflow:hidden;font-family:arial,sans-serif;font-size:10pt}/*! + * Selectr 2.4.0 + * https://github.com/Mobius1/Selectr + * + * Released under the MIT license + */.selectr-container{position:relative}.selectr-container li{list-style:none}.selectr-hidden{position:absolute;overflow:hidden;clip:rect(0,0,0,0);width:1px;height:1px;margin:-1px;padding:0;border:0 none}.selectr-visible{position:absolute;left:0;top:0;width:100%;height:100%;opacity:0;z-index:11}.selectr-desktop.multiple .selectr-visible{display:none}.selectr-desktop.multiple.native-open .selectr-visible{top:100%;min-height:200px!important;height:auto;opacity:1;display:block}.selectr-container.multiple.selectr-mobile .selectr-selected{z-index:0}.selectr-selected{position:relative;z-index:1;box-sizing:border-box;width:100%;padding:7px 28px 7px 14px;cursor:pointer;border:1px solid #999;border-radius:3px;background-color:#fff}.selectr-selected::before{position:absolute;top:50%;right:10px;width:0;height:0;content:'';-o-transform:rotate(0) translate3d(0,-50%,0);-ms-transform:rotate(0) translate3d(0,-50%,0);-moz-transform:rotate(0) translate3d(0,-50%,0);-webkit-transform:rotate(0) translate3d(0,-50%,0);transform:rotate(0) translate3d(0,-50%,0);border-width:4px 4px 0 4px;border-style:solid;border-color:#6c7a86 transparent transparent}.selectr-container.native-open .selectr-selected::before,.selectr-container.open .selectr-selected::before{border-width:0 4px 4px 4px;border-style:solid;border-color:transparent transparent #6c7a86}.selectr-label{display:none;overflow:hidden;width:100%;white-space:nowrap;text-overflow:ellipsis}.selectr-placeholder{color:#6c7a86}.selectr-tags{margin:0;padding:0;white-space:normal}.has-selected .selectr-tags{margin:0 0 -2px}.selectr-tag{list-style:none;position:relative;float:left;padding:2px 25px 2px 8px;margin:0 2px 2px 0;cursor:default;color:#fff;border:medium none;border-radius:10px;background:#acb7bf none repeat scroll 0 0}.selectr-container.multiple.has-selected .selectr-selected{padding:5px 28px 5px 5px}.selectr-options-container{position:absolute;z-index:10000;top:calc(100% - 1px);left:0;display:none;box-sizing:border-box;width:100%;border-width:0 1px 1px;border-style:solid;border-color:transparent #999 #999;border-radius:0 0 3px 3px;background-color:#fff}.selectr-container.open .selectr-options-container{display:block}.selectr-input-container{position:relative;display:none}.selectr-clear,.selectr-input-clear,.selectr-tag-remove{position:absolute;top:50%;right:22px;width:20px;height:20px;padding:0;cursor:pointer;-o-transform:translate3d(0,-50%,0);-ms-transform:translate3d(0,-50%,0);-moz-transform:translate3d(0,-50%,0);-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0);border:medium none;background-color:transparent;z-index:11}.selectr-clear,.selectr-input-clear{display:none}.selectr-container.has-selected .selectr-clear,.selectr-input-container.active .selectr-input-clear{display:block}.selectr-selected .selectr-tag-remove{right:2px}.selectr-clear::after,.selectr-clear::before,.selectr-input-clear::after,.selectr-input-clear::before,.selectr-tag-remove::after,.selectr-tag-remove::before{position:absolute;top:5px;left:9px;width:2px;height:10px;content:' ';background-color:#6c7a86}.selectr-tag-remove::after,.selectr-tag-remove::before{top:4px;width:3px;height:12px;background-color:#fff}.selectr-clear:before,.selectr-input-clear::before,.selectr-tag-remove::before{-o-transform:rotate(45deg);-ms-transform:rotate(45deg);-moz-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg)}.selectr-clear:after,.selectr-input-clear::after,.selectr-tag-remove::after{-o-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.selectr-input-container.active,.selectr-input-container.active .selectr-clear{display:block}.selectr-input{top:5px;left:5px;box-sizing:border-box;width:calc(100% - 30px);margin:10px 15px;padding:7px 30px 7px 9px;border:1px solid #999;border-radius:3px}.selectr-notice{display:none;box-sizing:border-box;width:100%;padding:8px 16px;border-top:1px solid #999;border-radius:0 0 3px 3px;background-color:#fff}.selectr-container.notice .selectr-notice{display:block}.selectr-container.notice .selectr-selected{border-radius:3px 3px 0 0}.selectr-options{position:relative;top:calc(100% + 2px);display:none;overflow-x:auto;overflow-y:scroll;max-height:200px;margin:0;padding:0}.selectr-container.notice .selectr-options-container,.selectr-container.open .selectr-input-container,.selectr-container.open .selectr-options{display:block}.selectr-option{position:relative;display:block;padding:5px 20px;list-style:outside none none;cursor:pointer;font-weight:400}.selectr-options.optgroups>.selectr-option{padding-left:25px}.selectr-optgroup{font-weight:700;padding:0}.selectr-optgroup--label{font-weight:700;margin-top:10px;padding:5px 15px}.selectr-match{text-decoration:underline}.selectr-option.selected{background-color:#ddd}.selectr-option.active{color:#fff;background-color:#5897fb}.selectr-option.disabled{opacity:.4}.selectr-option.excluded{display:none}.selectr-container.open .selectr-selected{border-color:#999 #999 transparent #999;border-radius:3px 3px 0 0}.selectr-container.open .selectr-selected::after{-o-transform:rotate(180deg) translate3d(0,50%,0);-ms-transform:rotate(180deg) translate3d(0,50%,0);-moz-transform:rotate(180deg) translate3d(0,50%,0);-webkit-transform:rotate(180deg) translate3d(0,50%,0);transform:rotate(180deg) translate3d(0,50%,0)}.selectr-disabled{opacity:.6}.has-selected .selectr-placeholder,.selectr-empty{display:none}.has-selected .selectr-label{display:block}.taggable .selectr-selected{padding:4px 28px 4px 4px}.taggable .selectr-selected::after{display:table;content:" ";clear:both}.taggable .selectr-label{width:auto}.taggable .selectr-tags{float:left;display:block}.taggable .selectr-placeholder{display:none}.input-tag{float:left;min-width:90px;width:auto}.selectr-tag-input{border:medium none;padding:3px 10px;width:100%;font-family:inherit;font-weight:inherit;font-size:inherit}.selectr-input-container.loading::after{position:absolute;top:50%;right:20px;width:20px;height:20px;content:'';-o-transform:translate3d(0,-50%,0);-ms-transform:translate3d(0,-50%,0);-moz-transform:translate3d(0,-50%,0);-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0);-o-transform-origin:50% 0 0;-ms-transform-origin:50% 0 0;-moz-transform-origin:50% 0 0;-webkit-transform-origin:50% 0 0;transform-origin:50% 0 0;-moz-animation:.5s linear 0s normal forwards infinite running spin;-webkit-animation:.5s linear 0s normal forwards infinite running spin;animation:.5s linear 0s normal forwards infinite running spin;border-width:3px;border-style:solid;border-color:#aaa #ddd #ddd;border-radius:50%}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0) translate3d(0,-50%,0);transform:rotate(0) translate3d(0,-50%,0)}100%{-webkit-transform:rotate(360deg) translate3d(0,-50%,0);transform:rotate(360deg) translate3d(0,-50%,0)}}@keyframes spin{0%{-webkit-transform:rotate(0) translate3d(0,-50%,0);transform:rotate(0) translate3d(0,-50%,0)}100%{-webkit-transform:rotate(360deg) translate3d(0,-50%,0);transform:rotate(360deg) translate3d(0,-50%,0)}}.selectr-container.open.inverted .selectr-selected{border-color:transparent #999 #999;border-radius:0 0 3px 3px}.selectr-container.inverted .selectr-options-container{border-width:1px 1px 0;border-color:#999 #999 transparent;border-radius:3px 3px 0 0;background-color:#fff}.selectr-container.inverted .selectr-options-container{top:auto;bottom:calc(100% - 1px)}.selectr-container ::-webkit-input-placeholder{color:#6c7a86;opacity:1}.selectr-container ::-moz-placeholder{color:#6c7a86;opacity:1}.selectr-container :-ms-input-placeholder{color:#6c7a86;opacity:1}.selectr-container ::placeholder{color:#6c7a86;opacity:1} \ No newline at end of file diff --git a/dataforge-vis-spatial-gdml/src/jsMain/web/index.html b/dataforge-vis-spatial-gdml/src/jsMain/web/index.html index 2455997a..f99f2803 100644 --- a/dataforge-vis-spatial-gdml/src/jsMain/web/index.html +++ b/dataforge-vis-spatial-gdml/src/jsMain/web/index.html @@ -11,6 +11,7 @@ integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> + diff --git a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt index 37e45cda..019a8856 100644 --- a/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt +++ b/dataforge-vis-spatial-gdml/src/jvmMain/kotlin/hep/dataforge/vis/spatial/gdml/testMain.kt @@ -15,30 +15,17 @@ fun main() { val xml = GDML.format.parse(GDML.serializer(), xmlReader) val visual = xml.toVisual { lUnit = LUnit.CM - volumeAction = { volume -> - when { - volume.name.startsWith("ecal01lay") -> GDMLTransformer.Action.REJECT - volume.name.startsWith("ecal") -> GDMLTransformer.Action.CACHE - volume.name.startsWith("UPBL") -> GDMLTransformer.Action.REJECT - volume.name.startsWith("USCL") -> GDMLTransformer.Action.REJECT - volume.name.startsWith("U") -> GDMLTransformer.Action.CACHE - volume.name.startsWith("VPBL") -> GDMLTransformer.Action.REJECT - volume.name.startsWith("VSCL") -> GDMLTransformer.Action.REJECT - volume.name.startsWith("V") -> GDMLTransformer.Action.CACHE - else -> GDMLTransformer.Action.ACCEPT - } - } solidConfiguration = { parent, solid -> - if (parent.physVolumes.isNotEmpty()) { - opacity = 0.3 - } - if (solid.name.startsWith("Coil") + if (parent.physVolumes.isNotEmpty() + || solid.name.startsWith("Coil") || solid.name.startsWith("Yoke") || solid.name.startsWith("Magnet") || solid.name.startsWith("Pole") ) { - opacity = 0.3 + useStyle("opaque") { + opacity = 0.3 + } } } diff --git a/dataforge-vis-spatial/build.gradle.kts b/dataforge-vis-spatial/build.gradle.kts index 1e2f96b0..51c7108b 100644 --- a/dataforge-vis-spatial/build.gradle.kts +++ b/dataforge-vis-spatial/build.gradle.kts @@ -33,6 +33,7 @@ kotlin { implementation(npm("element-resize-event")) implementation(npm("inspire-tree","6.0.1")) implementation(npm("inspire-tree-dom","4.0.6")) + implementation(npm("jsoneditor")) } } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index 18faaee2..5d5b0d2a 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -4,18 +4,16 @@ package hep.dataforge.vis.spatial import hep.dataforge.io.ConfigSerializer import hep.dataforge.io.NameSerializer -import hep.dataforge.meta.Config -import hep.dataforge.meta.Meta -import hep.dataforge.meta.MetaBuilder -import hep.dataforge.meta.MetaItem +import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName +import hep.dataforge.names.plus import hep.dataforge.vis.common.AbstractVisualObject +import hep.dataforge.vis.common.MutableVisualGroup import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient import kotlinx.serialization.UseSerializers /** @@ -34,21 +32,22 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua /** * Recursively search for defined template in the parent */ - val template: VisualObject3D + val prototype: VisualObject3D get() = (parent as? VisualGroup3D)?.getTemplate(templateName) ?: error("Template with name $templateName not found in $parent") - override fun getStyle(name: Name): Meta? = null + override fun getStyle(name: Name): Meta? = (parent as VisualGroup?)?.getStyle(name) override fun setStyle(name: Name, meta: Meta) { + (parent as VisualGroup?)?.setStyle(name, meta) //do nothing } override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { - super.getProperty(name, false) ?: template.getProperty(name, false) ?: parent?.getProperty(name, inherit) + super.getProperty(name, false) ?: prototype.getProperty(name, false) ?: parent?.getProperty(name, inherit) } else { - super.getProperty(name, false) ?: template.getProperty(name, false) + super.getProperty(name, false) ?: prototype.getProperty(name, false) } } @@ -58,49 +57,56 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua } override val children: Map - get() = (template as? VisualGroup)?.children?.mapValues { + get() = (prototype as? MutableVisualGroup)?.children?.mapValues { ProxyChild(it.key.asName()) } ?: emptyMap() - private data class ProxyChangeListeners(val owner: Any?, val callback: (Name, VisualObject?) -> Unit) - - @Transient - private val listeners = HashSet() - - override fun onChildrenChange(owner: Any?, action: (Name, VisualObject?) -> Unit) { - listeners.add(ProxyChangeListeners(owner, action)) - } - - override fun removeChildrenChangeListener(owner: Any?) { - listeners.removeAll { it.owner == owner } - } - - override fun set(name: Name, child: VisualObject?) { - error("Content change not supported for proxy") - } - private val propertyCache: HashMap = HashMap() - private fun Config.attachListener(obj: VisualObject) { - onChange(this@Proxy) { name, before, after -> - listeners.forEach { listener -> - listener.callback(name, obj) - } - } - } + inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup { + + override val children: Map + get() = ((prototype as? MutableVisualGroup)?.get(name) as? MutableVisualGroup) + ?.children + ?.mapValues { (key, _) -> + ProxyChild( + name + key.asName() + ) + } + ?: emptyMap() + + override fun getStyle(name: Name): Meta? = this@Proxy.getStyle(name) + + override fun setStyle(name: Name, meta: Meta) { + this@Proxy.setStyle(name, meta) + } + + val prototype: VisualObject + get() = (this@Proxy.prototype as? VisualGroup)?.get(name) + ?: error("Prototype with name $name not found in ${this@Proxy}") - inner class ProxyChild(val name: Name) : AbstractVisualObject() { override var properties: Config? get() = propertyCache[name] set(value) { if (value == null) { - propertyCache.remove(name)?.removeListener(this@Proxy) + propertyCache.remove(name) } else { - propertyCache[name] = value.apply { - attachListener(this@ProxyChild) - } + propertyCache[name] = value } } + + override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { + return if (inherit) { + properties?.get(name) + ?: parent?.getProperty(name, inherit) + ?: actualStyles[name] + ?: prototype.getProperty(name, inherit) + } else { + properties?.get(name) + ?: actualStyles[name] + ?: prototype.getProperty(name, inherit) + } + } } } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt index 2d5089e8..02886ed9 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Visual3DPlugin.kt @@ -37,10 +37,10 @@ class Visual3DPlugin(meta: Meta) : AbstractPlugin(meta) { contextual(Point2DSerializer) contextual(NameSerializer) contextual(NameTokenSerializer) - contextual(MetaSerializer) + contextual(Meta::class, MetaSerializer) contextual(ConfigSerializer) - polymorphic(VisualObject::class,VisualObject3D::class) { + polymorphic(VisualObject::class, VisualObject3D::class) { VisualGroup3D::class with VisualGroup3D.serializer() Proxy::class with Proxy.serializer() Composite::class with Composite.serializer() diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt index d0057f0c..e2ccbd25 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualGroup3D.kt @@ -2,27 +2,29 @@ Point3DSerializer::class, ConfigSerializer::class, NameTokenSerializer::class, - NameSerializer::class + NameSerializer::class, + MetaSerializer::class ) package hep.dataforge.vis.spatial import hep.dataforge.io.ConfigSerializer +import hep.dataforge.io.MetaSerializer import hep.dataforge.io.NameSerializer import hep.dataforge.meta.Config import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.set -import hep.dataforge.names.* +import hep.dataforge.names.Name +import hep.dataforge.names.NameToken +import hep.dataforge.names.asName +import hep.dataforge.names.isEmpty import hep.dataforge.vis.common.AbstractVisualGroup -import hep.dataforge.vis.common.AbstractVisualObject -import hep.dataforge.vis.common.VisualGroup +import hep.dataforge.vis.common.MutableVisualGroup import hep.dataforge.vis.common.VisualObject import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers -import kotlin.collections.component1 -import kotlin.collections.component2 import kotlin.collections.set @Serializable @@ -37,32 +39,8 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { } //FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed - public override var properties: Config? = null - - private val styles = HashMap() - - override fun getStyle(name: Name): Meta? = styles[name] - - override fun setStyle(name: Name, meta: Meta) { - fun VisualObject.applyStyle(name: Name, meta: Meta) { - if (style.contains(name.toString())) { - //full update - //TODO do a fine grained update - if(this is AbstractVisualObject){ - styleChanged() - } else { - propertyChanged(EmptyName) - } - } - if (this is VisualGroup) { - this.children.forEach { (_, child) -> - child.applyStyle(name, meta) - } - } - } - styles[name] = meta - applyStyle(name, meta) - } + override var properties: Config? = null + override val styles = HashMap() override var position: Point3D? = null override var rotation: Point3D? = null @@ -87,10 +65,10 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { childrenChanged(token.asName(), child) } - /** - * TODO add special static group to hold statics without propagation - */ - override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child) +// /** +// * TODO add special static group to hold statics without propagation +// */ +// override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child) override fun createGroup(name: Name): VisualGroup3D { return when { @@ -125,10 +103,10 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D { /** * A fix for serialization bug that writes all proper parents inside the tree after deserialization */ -fun VisualGroup.attachChildren() { +fun MutableVisualGroup.attachChildren() { this.children.values.forEach { it.parent = this - (it as? VisualGroup)?.attachChildren() + (it as? MutableVisualGroup)?.attachChildren() } if (this is VisualGroup3D) { templates?.apply { diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index ed6acd9c..e2c78e34 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -9,9 +9,11 @@ import hep.dataforge.names.plus import hep.dataforge.output.Output import hep.dataforge.vis.common.Colors.rgbToString import hep.dataforge.vis.common.VisualObject +import hep.dataforge.vis.spatial.VisualObject3D.Companion.COLOR_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.MATERIAL_KEY +import hep.dataforge.vis.spatial.VisualObject3D.Companion.OPACITY_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.SELECTED_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY import kotlinx.serialization.UseSerializers @@ -40,6 +42,9 @@ interface VisualObject3D : VisualObject { val DETAIL_KEY = "detail".asName() val LAYER_KEY = "layer".asName() + val COLOR_KEY = MATERIAL_KEY + "color" + val OPACITY_KEY = MATERIAL_KEY + "opacity" + val x = "x".asName() val y = "y".asName() val z = "z".asName() @@ -109,11 +114,9 @@ var VisualObject.material: Meta? set(value) = setProperty(MATERIAL_KEY, value) var VisualObject.opacity: Double - get() = material?.get("opacity").double ?: 1.0 + get() = getProperty(OPACITY_KEY).double ?: 1.0 set(value) { - material = (material?.builder() ?: MetaBuilder()).apply { - "opacity" to value - } + setProperty(OPACITY_KEY, value) } var VisualObject.visible: Boolean? @@ -125,15 +128,15 @@ var VisualObject.selected: Boolean? set(value) = setProperty(SELECTED_KEY, value) fun VisualObject.color(rgb: Int) { - material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgbToString(rgb) } + setProperty(COLOR_KEY, rgbToString(rgb)) } fun VisualObject.color(rgb: String) { - material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb } + setProperty(COLOR_KEY, rgb) } var VisualObject.color: String? - get() = material["color"].string + get() = getProperty(COLOR_KEY).string set(value) { if (value != null) { color(value) diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeProxyFactory.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeProxyFactory.kt index ad9ac987..45f8a9bb 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeProxyFactory.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/three/ThreeProxyFactory.kt @@ -20,7 +20,7 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory { } override fun invoke(obj: Proxy): Object3D { - val template = obj.template + val template = obj.prototype val cachedObject = cache.getOrPut(template) { three.buildObject3D(template) } @@ -45,11 +45,6 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory { } } - obj.onChildrenChange(this) { name, propertyHolder -> - val child = object3D.findChild(name) - (child as? Mesh)?.updateProperties(propertyHolder) - } - return object3D } } \ No newline at end of file diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsVisualTree.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsVisualTree.kt index 191e06ab..2d86b7f4 100644 --- a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsVisualTree.kt +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsVisualTree.kt @@ -10,7 +10,6 @@ import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.getProperty import hep.dataforge.vis.spatial.Proxy -import hep.dataforge.vis.spatial.selected import hep.dataforge.vis.spatial.visible import org.w3c.dom.HTMLElement import kotlin.js.json @@ -40,7 +39,7 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { obj, name - fun generateNodeConfig(item: VisualObject, fullName: Name): NodeConfig { val title = item.getProperty("title").string ?: fullName.last()?.toString() ?: "root" val className = if (item is Proxy) { - item.template::class.toString() + item.prototype::class.toString() } else { item::class.toString() }.replace("class ", "") @@ -88,15 +87,15 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { obj, name - map[rootNode.id] = this rootNode.fillChildren(this, EmptyName) - inspireTree.on("node.selected") { node: TreeNode, isLoadEvent: Boolean -> - if (!isLoadEvent) { - map[node.id]?.selected = node.selected() - } - } - - inspireTree.on("node.deselect") { node: TreeNode -> - map[node.id]?.selected = node.selected() - } +// inspireTree.on("node.selected") { node: TreeNode, isLoadEvent: Boolean -> +// if (!isLoadEvent) { +// map[node.id]?.selected = node.selected() +// } +// } +// +// inspireTree.on("node.deselect") { node: TreeNode -> +// map[node.id]?.selected = node.selected() +// } inspireTree.on("node.checked") { node: TreeNode, isLoadEvent: Boolean -> if (!isLoadEvent) { diff --git a/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsonEditor.kt b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsonEditor.kt new file mode 100644 index 00000000..1e3abd3c --- /dev/null +++ b/dataforge-vis-spatial/src/jsMain/kotlin/hep/dataforge/vis/spatial/tree/jsonEditor.kt @@ -0,0 +1,185 @@ +@file:Suppress( + "INTERFACE_WITH_SUPERCLASS", + "OVERRIDING_FINAL_MEMBER", + "RETURN_TYPE_MISMATCH_ON_OVERRIDE", + "CONFLICTING_OVERLOADS", + "EXTERNAL_DELEGATION" +) + +package hep.dataforge.vis.spatial.tree + +import org.w3c.dom.HTMLElement + +external interface Node { + var field: String + var value: String? get() = definedExternally; set(value) = definedExternally + var path: dynamic +} + +external interface NodeName { + var path: Array + var type: dynamic /* 'object' | 'array' */ + var size: Number +} + +external interface ValidationError { + var path: dynamic + var message: String +} + +external interface Template { + var text: String + var title: String + var className: String? get() = definedExternally; set(value) = definedExternally + var field: String + var value: Any +} + +external interface `T$6` { + var startFrom: Number + var options: Array +} + +external interface AutoCompleteOptions { + var confirmKeys: Array? get() = definedExternally; set(value) = definedExternally + var caseSensitive: Boolean? get() = definedExternally; set(value) = definedExternally +// var getOptions: AutoCompleteOptionsGetter? get() = definedExternally; set(value) = definedExternally +} + +external interface SelectionPosition { + var row: Number + var column: Number +} + +external interface SerializableNode { + var value: Any + var path: dynamic +} + +external interface Color { + var rgba: Array + var hsla: Array + var rgbString: String + var rgbaString: String + var hslString: String + var hslaString: String + var hex: String +} + +//external interface `T$0` { +// var field: Boolean +// var value: Boolean +//} +// +//external interface `T$1` { +// @nativeGetter +// operator fun get(key: String): String? +// +// @nativeSetter +// operator fun set(key: String, value: String) +//} + +//external interface Languages { +// @nativeGetter +// operator fun get(lang: String): `T$1`? +// +// @nativeSetter +// operator fun set(lang: String, value: `T$1`) +//} + +external interface JSONEditorOptions { +// var ace: AceAjax.Ace? get() = definedExternally; set(value) = definedExternally +// var ajv: Ajv? get() = definedExternally; set(value) = definedExternally + var onChange: (() -> Unit)? get() = definedExternally; set(value) = definedExternally + var onChangeJSON: ((json: Any) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onChangeText: ((jsonString: String) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onEditable: ((node: Node) -> dynamic)? get() = definedExternally; set(value) = definedExternally + var onError: ((error: Error) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onModeChange: ((newMode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */, oldMode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */) -> Unit)? get() = definedExternally; set(value) = definedExternally + var onNodeName: ((nodeName: NodeName) -> String?)? get() = definedExternally; set(value) = definedExternally + var onValidate: ((json: Any) -> dynamic)? get() = definedExternally; set(value) = definedExternally + var escapeUnicode: Boolean? get() = definedExternally; set(value) = definedExternally + var sortObjectKeys: Boolean? get() = definedExternally; set(value) = definedExternally + var history: Boolean? get() = definedExternally; set(value) = definedExternally + var mode: dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */ + var modes: Array? get() = definedExternally; set(value) = definedExternally + var name: String? get() = definedExternally; set(value) = definedExternally + var schema: Any? get() = definedExternally; set(value) = definedExternally + var schemaRefs: Any? get() = definedExternally; set(value) = definedExternally + var search: Boolean? get() = definedExternally; set(value) = definedExternally + var indentation: Number? get() = definedExternally; set(value) = definedExternally + var theme: String? get() = definedExternally; set(value) = definedExternally + var templates: Array