Tree editor tweaks

This commit is contained in:
Alexander Nozik 2019-09-29 22:11:09 +03:00
parent 4fa2e50777
commit c5f14fb5e7
9 changed files with 126 additions and 65 deletions

View File

@ -174,4 +174,9 @@ object Colors {
const val whitesmoke = 0xF5F5F5 const val whitesmoke = 0xF5F5F5
const val yellow = 0xFFFF00 const val yellow = 0xFFFF00
const val yellowgreen = 0x9ACD32 const val yellowgreen = 0x9ACD32
fun rgbToString(rgb: Int): String {
val string = rgb.toString(16)
return "#" + string.substring(string.length - 6)
}
} }

View File

@ -2,6 +2,8 @@ package hep.dataforge.vis.spatial.gdml
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.buildMeta import hep.dataforge.meta.buildMeta
import hep.dataforge.names.toName
import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.spatial.VisualGroup3D import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.material import hep.dataforge.vis.spatial.material
@ -36,10 +38,10 @@ class GDMLTransformer(val root: GDML) {
val materialColor = materialCache.getOrPut(material) { val materialColor = materialCache.getOrPut(material) {
buildMeta { buildMeta {
"color" to random.nextInt(0, Int.MAX_VALUE) "color" to Colors.rgbToString(random.nextInt(0, Int.MAX_VALUE))
} }
} }
obj.setProperty("gdml.material".toName(), material.name)
obj.material = materialColor obj.material = materialColor
obj.solidConfiguration(parent, solid) obj.solidConfiguration(parent, solid)
} }

View File

@ -1,10 +1,7 @@
package hep.dataforge.vis.spatial.gdml.demo package hep.dataforge.vis.spatial.gdml.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import hep.dataforge.vis.common.VisualGroup import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.hmr.ApplicationBase import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
@ -14,11 +11,15 @@ import hep.dataforge.vis.spatial.gdml.toVisual
import hep.dataforge.vis.spatial.three.ThreeOutput import hep.dataforge.vis.spatial.three.ThreeOutput
import hep.dataforge.vis.spatial.three.ThreePlugin import hep.dataforge.vis.spatial.three.ThreePlugin
import hep.dataforge.vis.spatial.three.output import hep.dataforge.vis.spatial.three.output
import hep.dataforge.vis.spatial.tree.propertyEditor
import hep.dataforge.vis.spatial.tree.render import hep.dataforge.vis.spatial.tree.render
import hep.dataforge.vis.spatial.tree.toTree import hep.dataforge.vis.spatial.tree.toTree
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.dom.append import kotlinx.html.dom.append
import kotlinx.html.js.* import kotlinx.html.js.input
import kotlinx.html.js.li
import kotlinx.html.js.p
import kotlinx.html.js.ul
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.HTMLDivElement import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
@ -150,43 +151,6 @@ private class GDMLDemoApp : ApplicationBase() {
} }
fun showEditor(item: VisualObject?, name: String?) {
val element = document.getElementById("editor") ?: error("Element with id 'canvas' not found on page")
element.clear()
if (item != null) {
element.append {
div("card") {
div("card-body") {
h3(classes = "card-title") { +(name ?: "") }
form {
div("form-group") {
label {
+"Color: "
}
input(InputType.color, classes = "form-control").apply {
onchange = { event ->
item.color(value)
}
}
}
div("form-group form-check") {
input(InputType.checkBox, classes = "form-check-input").apply {
this.value = item.material?.get("color").string ?: ""
onchange = { event ->
item.visible = checked
Unit
}
}
label("form-check-label") { +"Visible" }
}
}
}
}
}
}
}
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
val context = Global.context("demo") {} val context = Global.context("demo") {}
@ -196,6 +160,7 @@ private class GDMLDemoApp : ApplicationBase() {
val canvas = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page") val canvas = document.getElementById("canvas") ?: error("Element with id 'canvas' not found on page")
val layers = document.getElementById("layers") ?: error("Element with id 'layers' not found on page") val layers = document.getElementById("layers") ?: error("Element with id 'layers' not found on page")
val tree = document.getElementById("tree") ?: error("Element with id 'tree' not found on page") val tree = document.getElementById("tree") ?: error("Element with id 'tree' not found on page")
val editor = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
canvas.clear() canvas.clear()
val action: (name: String, data: String) -> Unit = { name, data -> val action: (name: String, data: String) -> Unit = { name, data ->
@ -224,7 +189,7 @@ private class GDMLDemoApp : ApplicationBase() {
setupLayers(layers, output) setupLayers(layers, output)
if (visual is VisualGroup) { if (visual is VisualGroup) {
visual.toTree(::showEditor).render(tree as HTMLElement) { visual.toTree(editor::propertyEditor).render(tree as HTMLElement) {
showCheckboxes = true showCheckboxes = true
} }
} }

View File

@ -85,11 +85,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
inner class ProxyChild(val name: Name) : AbstractVisualObject() { inner class ProxyChild(val name: Name) : AbstractVisualObject() {
override var properties: Config? override var properties: Config?
get() = propertyCache.getOrPut(name) { get() = propertyCache[name]
Config().apply {
attachListener(this@ProxyChild)
}
}
set(value) { set(value) {
if (value == null) { if (value == null) {
propertyCache.remove(name)?.removeListener(this@Proxy) propertyCache.remove(name)?.removeListener(this@Proxy)
@ -99,7 +95,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
} }
} }
} }
} }
} }

View File

@ -6,6 +6,7 @@ import hep.dataforge.io.NameSerializer
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.output.Output import hep.dataforge.output.Output
import hep.dataforge.vis.common.Colors.rgbToString
import hep.dataforge.vis.common.VisualObject import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.asName import hep.dataforge.vis.common.asName
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
@ -124,13 +125,21 @@ var VisualObject.selected: Boolean?
set(value) = setProperty(SELECTED_KEY, value) set(value) = setProperty(SELECTED_KEY, value)
fun VisualObject.color(rgb: Int) { fun VisualObject.color(rgb: Int) {
material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb } material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgbToString(rgb) }
} }
fun VisualObject.color(rgb: String) { fun VisualObject.color(rgb: String) {
material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb } material = (material?.builder() ?: MetaBuilder()).apply { "color" to rgb }
} }
var VisualObject.color: String?
get() = material["color"].string
set(value) {
if (value != null) {
color(value)
}
}
fun VisualObject3D.material(builder: MetaBuilder.() -> Unit) { fun VisualObject3D.material(builder: MetaBuilder.() -> Unit) {
material = buildMeta(builder) material = buildMeta(builder)
} }

View File

@ -32,15 +32,14 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
val camera = three.buildCamera(meta["camera"].node ?: EmptyMeta) val camera = three.buildCamera(meta["camera"].node ?: EmptyMeta)
fun attach(element: HTMLElement, computeWidth: HTMLElement.() -> Int = { this.offsetWidth }) { fun attach(element: HTMLElement) {
element.clear() element.clear()
val width by meta.number(computeWidth(element)).int
val height: Int = (width / camera.aspect).toInt() camera.aspect = 1.0
val renderer = WebGLRenderer { antialias = true }.apply { val renderer = WebGLRenderer { antialias = true }.apply {
setClearColor(Colors.skyblue, 1) setClearColor(Colors.skyblue, 1)
setSize(width, height)
} }
three.addControls(camera, renderer.domElement, meta["controls"].node ?: EmptyMeta) three.addControls(camera, renderer.domElement, meta["controls"].node ?: EmptyMeta)
@ -52,13 +51,19 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
renderer.render(scene, camera) renderer.render(scene, camera)
} }
element.appendChild(renderer.domElement)
elementResizeEvent(element) { elementResizeEvent(element) {
renderer.setSize(element.offsetWidth, element.offsetWidth)
camera.updateProjectionMatrix() camera.updateProjectionMatrix()
val newWidth = computeWidth(element)
renderer.setSize(newWidth, (newWidth / camera.aspect).toInt())
} }
element.appendChild(renderer.domElement) // val width by meta.number(element.offsetWidth).int
// val height by meta.number(element.offsetHeight).int
// val size = min(width, height)
// renderer.setSize(size, size)
renderer.setSize(element.offsetWidth, element.offsetWidth)
animate() animate()
} }

View File

@ -45,8 +45,9 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
} }
} }
obj.onChildrenChange(object3D) { name, propertyHolder -> obj.onChildrenChange(this) { name, propertyHolder ->
(object3D.findChild(name) as? Mesh)?.updateProperties(propertyHolder) val child = object3D.findChild(name)
(child as? Mesh)?.updateProperties(propertyHolder)
} }
return object3D return object3D

View File

@ -9,6 +9,7 @@ import hep.dataforge.names.NameToken
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.getProperty import hep.dataforge.vis.common.getProperty
import hep.dataforge.vis.spatial.Proxy
import hep.dataforge.vis.spatial.selected import hep.dataforge.vis.spatial.selected
import hep.dataforge.vis.spatial.visible import hep.dataforge.vis.spatial.visible
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
@ -32,13 +33,24 @@ internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
return InspireTree(config) return InspireTree(config)
} }
fun VisualGroup.toTree(onFocus: (VisualObject?, String?)->Unit = {obj,name->}): InspireTree { fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { obj, name -> }): InspireTree {
val map = HashMap<String, VisualObject>() val map = HashMap<String, VisualObject>()
fun generateNodeConfig(item: VisualObject, fullName: Name): NodeConfig { fun generateNodeConfig(item: VisualObject, fullName: Name): NodeConfig {
val title = item.getProperty("title").string ?: fullName.last()?.toString() ?: "root" val title = item.getProperty("title").string ?: fullName.last()?.toString() ?: "root"
val text = "$title[${item::class.toString().replace("class ","")}]" val className = if (item is Proxy) {
item.template::class.toString()
} else {
item::class.toString()
}.replace("class ", "")
val text: String = if (title.startsWith("@")) {
"[$className}]"
} else {
"$title[$className}]"
}
return json( return json(
"children" to if ((item as? VisualGroup)?.children?.isEmpty() != false) { "children" to if ((item as? VisualGroup)?.children?.isEmpty() != false) {
emptyArray<NodeConfig>() emptyArray<NodeConfig>()
@ -68,7 +80,7 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?)->Unit = {obj,name->}):
} }
} }
val inspireTree = createInspireTree{ val inspireTree = createInspireTree {
} }
val nodeConfig = generateNodeConfig(this, EmptyName) val nodeConfig = generateNodeConfig(this, EmptyName)
@ -93,14 +105,14 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?)->Unit = {obj,name->}):
} }
inspireTree.on("node.unchecked") { node: TreeNode -> inspireTree.on("node.unchecked") { node: TreeNode ->
if(!node.indeterminate()){ if (!node.indeterminate()) {
map[node.id]?.visible = node.checked() map[node.id]?.visible = node.checked()
} }
} }
inspireTree.on("node.focused") { node: TreeNode, isLoadEvent: Boolean -> inspireTree.on("node.focused") { node: TreeNode, isLoadEvent: Boolean ->
if (!isLoadEvent) { if (!isLoadEvent) {
onFocus(map[node.id],node.id) onFocus(map[node.id], node.id)
} }
} }

View File

@ -0,0 +1,67 @@
package hep.dataforge.vis.spatial.tree
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.spatial.color
import hep.dataforge.vis.spatial.opacity
import hep.dataforge.vis.spatial.visible
import kotlinx.html.InputType
import kotlinx.html.dom.append
import kotlinx.html.js.*
import org.w3c.dom.Element
import kotlin.dom.clear
fun Element.propertyEditor(item: VisualObject?, name: String?) {
clear()
if (item != null) {
append {
div("card") {
div("card-body") {
h3(classes = "card-title") { +(name ?: "") }
form {
div("form-group row") {
label("col-form-label col-4") {
+"Color: "
}
input(InputType.color, classes = "form-control col-8") {
value = item.color ?: "#ffffff"
}.apply {
onInputFunction = {
item.color = value
}
}
}
div("form-group row") {
label("col-form-label col-4") {
+"Opacity: "
}
input(InputType.range, classes = "form-control col-8") {
min = "0.0"
max = "1.0"
step = "0.1"
value = item.opacity.toString()
}.apply {
onInputFunction = {
item.opacity = value.toDouble()
}
}
}
div("form-group row") {
label("col-form-label col-4") { +"Visible: " }
div("col-8") {
div("form-check") {
input(InputType.checkBox, classes = "form-check-input").apply {
this.checked = item.visible ?: true
onInputFunction = {
item.visible = checked
}
}
}
}
}
}
}
}
}
}
}