forked from kscience/visionforge
Tree editor tweaks
This commit is contained in:
parent
4fa2e50777
commit
c5f14fb5e7
@ -174,4 +174,9 @@ object Colors {
|
||||
const val whitesmoke = 0xF5F5F5
|
||||
const val yellow = 0xFFFF00
|
||||
const val yellowgreen = 0x9ACD32
|
||||
|
||||
fun rgbToString(rgb: Int): String {
|
||||
val string = rgb.toString(16)
|
||||
return "#" + string.substring(string.length - 6)
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
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.VisualObject3D
|
||||
import hep.dataforge.vis.spatial.material
|
||||
@ -36,10 +38,10 @@ class GDMLTransformer(val root: GDML) {
|
||||
|
||||
val materialColor = materialCache.getOrPut(material) {
|
||||
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.solidConfiguration(parent, solid)
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
package hep.dataforge.vis.spatial.gdml.demo
|
||||
|
||||
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.VisualObject
|
||||
import hep.dataforge.vis.hmr.ApplicationBase
|
||||
import hep.dataforge.vis.hmr.startApplication
|
||||
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.ThreePlugin
|
||||
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.toTree
|
||||
import kotlinx.html.InputType
|
||||
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.HTMLDivElement
|
||||
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>) {
|
||||
|
||||
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 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 editor = document.getElementById("editor") ?: error("Element with id 'editor' not found on page")
|
||||
canvas.clear()
|
||||
|
||||
val action: (name: String, data: String) -> Unit = { name, data ->
|
||||
@ -224,7 +189,7 @@ private class GDMLDemoApp : ApplicationBase() {
|
||||
setupLayers(layers, output)
|
||||
|
||||
if (visual is VisualGroup) {
|
||||
visual.toTree(::showEditor).render(tree as HTMLElement) {
|
||||
visual.toTree(editor::propertyEditor).render(tree as HTMLElement) {
|
||||
showCheckboxes = true
|
||||
}
|
||||
}
|
||||
|
@ -85,11 +85,7 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
|
||||
|
||||
inner class ProxyChild(val name: Name) : AbstractVisualObject() {
|
||||
override var properties: Config?
|
||||
get() = propertyCache.getOrPut(name) {
|
||||
Config().apply {
|
||||
attachListener(this@ProxyChild)
|
||||
}
|
||||
}
|
||||
get() = propertyCache[name]
|
||||
set(value) {
|
||||
if (value == null) {
|
||||
propertyCache.remove(name)?.removeListener(this@Proxy)
|
||||
@ -99,7 +95,6 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import hep.dataforge.io.NameSerializer
|
||||
import hep.dataforge.meta.*
|
||||
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.common.asName
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
||||
@ -124,13 +125,21 @@ var VisualObject.selected: Boolean?
|
||||
set(value) = setProperty(SELECTED_KEY, value)
|
||||
|
||||
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) {
|
||||
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) {
|
||||
material = buildMeta(builder)
|
||||
}
|
||||
|
@ -32,15 +32,14 @@ class ThreeOutput(val three: ThreePlugin, val meta: Meta = EmptyMeta) : Output<V
|
||||
|
||||
val camera = three.buildCamera(meta["camera"].node ?: EmptyMeta)
|
||||
|
||||
fun attach(element: HTMLElement, computeWidth: HTMLElement.() -> Int = { this.offsetWidth }) {
|
||||
fun attach(element: HTMLElement) {
|
||||
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 {
|
||||
setClearColor(Colors.skyblue, 1)
|
||||
setSize(width, height)
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
element.appendChild(renderer.domElement)
|
||||
|
||||
elementResizeEvent(element) {
|
||||
renderer.setSize(element.offsetWidth, element.offsetWidth)
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,9 @@ class ThreeProxyFactory(val three: ThreePlugin) : ThreeFactory<Proxy> {
|
||||
}
|
||||
}
|
||||
|
||||
obj.onChildrenChange(object3D) { name, propertyHolder ->
|
||||
(object3D.findChild(name) as? Mesh)?.updateProperties(propertyHolder)
|
||||
obj.onChildrenChange(this) { name, propertyHolder ->
|
||||
val child = object3D.findChild(name)
|
||||
(child as? Mesh)?.updateProperties(propertyHolder)
|
||||
}
|
||||
|
||||
return object3D
|
||||
|
@ -9,6 +9,7 @@ import hep.dataforge.names.NameToken
|
||||
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
|
||||
@ -32,13 +33,24 @@ internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
|
||||
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>()
|
||||
|
||||
fun generateNodeConfig(item: VisualObject, fullName: Name): NodeConfig {
|
||||
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(
|
||||
"children" to if ((item as? VisualGroup)?.children?.isEmpty() != false) {
|
||||
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)
|
||||
@ -93,14 +105,14 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?)->Unit = {obj,name->}):
|
||||
}
|
||||
|
||||
inspireTree.on("node.unchecked") { node: TreeNode ->
|
||||
if(!node.indeterminate()){
|
||||
if (!node.indeterminate()) {
|
||||
map[node.id]?.visible = node.checked()
|
||||
}
|
||||
}
|
||||
|
||||
inspireTree.on("node.focused") { node: TreeNode, isLoadEvent: Boolean ->
|
||||
if (!isLoadEvent) {
|
||||
onFocus(map[node.id],node.id)
|
||||
onFocus(map[node.id], node.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user