New layout

This commit is contained in:
Alexander Nozik 2019-10-09 12:38:39 +03:00
parent 9f157a80b9
commit 0fbad16be6
13 changed files with 161 additions and 176 deletions

View File

@ -27,7 +27,7 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
override fun getStyle(name: Name): Meta? = styleSheet[name]
override fun addStyle(name: Name, meta: Meta) {
override fun addStyle(name: Name, meta: Meta, apply: Boolean) {
fun VisualObject.applyStyle(name: Name, meta: Meta) {
if (styles.contains(name)) {
//full update
@ -45,7 +45,9 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
}
}
styleSheet[name] = meta
applyStyle(name, meta)
if (apply) {
applyStyle(name, meta)
}
}

View File

@ -41,7 +41,7 @@ interface VisualGroup : Provider, Iterable<VisualObject>, VisualObject {
/**
* Add or replace style with given name
*/
fun addStyle(name: Name, meta: Meta)
fun addStyle(name: Name, meta: Meta, apply: Boolean = true)
operator fun get(name: Name): VisualObject? {
return when {

View File

@ -1,4 +1,4 @@
package hep.dataforge.vis.hmr
package hep.dataforge.vis
import kotlin.browser.document
import kotlin.dom.hasClass

View File

@ -1,6 +1,4 @@
package hep.dataforge.vis.hmr
import kotlinext.js.objectAssign
package hep.dataforge.vis
inline fun <T : Any> jsObject(builder: T.() -> Unit): T {
val obj: T = js("({})") as T

View File

@ -69,7 +69,7 @@ class GDMLTransformer(val root: GDML) {
internal fun finalize(final: VisualGroup3D): VisualGroup3D {
final.templates = templates
styleCache.forEach {
final.addStyle(it.key, it.value)
final.addStyle(it.key, it.value, false)
}
final.rotationOrder = RotationOrder.ZXY
onFinish(this@GDMLTransformer)

View File

@ -1,36 +1,26 @@
package hep.dataforge.vis.spatial.gdml.demo
import hep.dataforge.context.Global
import hep.dataforge.vis.common.VisualGroup
import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.ApplicationBase
import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY
import hep.dataforge.vis.spatial.Visual3DPlugin
import hep.dataforge.vis.spatial.VisualGroup3D
import hep.dataforge.vis.spatial.VisualObject3D
import hep.dataforge.vis.spatial.attachChildren
import hep.dataforge.vis.spatial.editor.propertyEditor
import hep.dataforge.vis.spatial.editor.threeOutputConfig
import hep.dataforge.vis.spatial.editor.visualObjectTree
import hep.dataforge.vis.spatial.gdml.GDMLTransformer
import hep.dataforge.vis.spatial.gdml.LUnit
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.transform.RemoveSingleChild
import hep.dataforge.vis.spatial.transform.UnRef
import hep.dataforge.vis.spatial.transform.transformInPlace
import hep.dataforge.vis.spatial.editor.propertyEditor
import hep.dataforge.vis.spatial.editor.render
import hep.dataforge.vis.spatial.editor.toTree
import kotlinx.html.InputType
import hep.dataforge.vis.startApplication
import kotlinx.html.dom.append
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.DragEvent
import org.w3c.dom.HTMLDivElement
import org.w3c.dom.HTMLElement
import org.w3c.dom.events.Event
import org.w3c.files.FileList
import org.w3c.files.FileReader
import org.w3c.files.get
@ -43,33 +33,27 @@ private class GDMLDemoApp : ApplicationBase() {
/**
* Handle mouse drag according to https://www.html5rocks.com/en/tutorials/file/dndfiles/
*/
private fun handleDragOver(event: Event) {
private fun handleDragOver(event: DragEvent) {
event.stopPropagation()
event.preventDefault()
event.asDynamic().dataTransfer.dropEffect = "copy"
event.dataTransfer?.dropEffect = "copy"
}
/**
* Load data from text file
*/
private fun loadData(event: Event, block: (name: String, data: String) -> Unit) {
private fun loadData(event: DragEvent, block: (name: String, data: String) -> Unit) {
event.stopPropagation()
event.preventDefault()
val file = (event.asDynamic().dataTransfer.files as FileList)[0]
val file = (event.dataTransfer?.files as FileList)[0]
?: throw RuntimeException("Failed to load file")
FileReader().apply {
onload = {
val string = result as String
// try {
block(file.name, string)
// } catch (ex: Exception) {
// console.error(ex)
// }
}
readAsText(file)
}
@ -102,52 +86,22 @@ private class GDMLDemoApp : ApplicationBase() {
}
}
fun setupLayers(element: Element, output: ThreeOutput) {
element.clear()
element.append {
ul("list-group") {
(0..9).forEach { layer ->
li("list-group-item") {
+"layer $layer"
input(type = InputType.checkBox).apply {
if (layer == 0) {
checked = true
}
onchange = {
if (checked) {
output.camera.layers.enable(layer)
} else {
output.camera.layers.disable(layer)
}
}
}
}
}
}
}
}
private val gdmlConfiguration: GDMLTransformer.() -> Unit = {
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.CACHE
}
}
solidConfiguration = { parent, solid ->
if (
solid.name.startsWith("Coil")
|| solid.name.startsWith("Yoke")
|| solid.name.startsWith("Magnet")
solid.name.startsWith("Yoke")
|| solid.name.startsWith("Pole")
|| parent.physVolumes.isNotEmpty()
) {
@ -193,17 +147,13 @@ private class GDMLDemoApp : ApplicationBase() {
//(visual as? VisualGroup3D)?.transformInPlace(UnRef, RemoveSingleChild)
message("Rendering")
val output = three.output(canvas as HTMLElement)
//output.camera.layers.enable(1)
output.camera.layers.set(0)
setupLayers(layers, output)
val output = three.output(canvas as HTMLElement)
if (visual is VisualGroup) {
visual.toTree(editor::propertyEditor).render(tree as HTMLElement) {
showCheckboxes = false
}
}
output.camera.layers.set(0)
layers.threeOutputConfig(output)
tree.visualObjectTree(visual, editor::propertyEditor)
output.render(visual)
message(null)
@ -211,8 +161,8 @@ private class GDMLDemoApp : ApplicationBase() {
}
(document.getElementById("drop_zone") as? HTMLDivElement)?.apply {
addEventListener("dragover", { handleDragOver(it) }, false)
addEventListener("drop", { loadData(it, action) }, false)
addEventListener("dragover", { handleDragOver(it as DragEvent) }, false)
addEventListener("drop", { loadData(it as DragEvent, action) }, false)
}
}

View File

@ -29,45 +29,12 @@
<div class="container-fluid">
<div class="row">
<div class="col-9" id="canvas"></div>
<div class="col-3">
<div id="editor"></div>
<div class="accordion" id="accordion">
<div class="card">
<div class="card-header" id="layers-header">
<h2 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#layers-body"
aria-expanded="true" aria-controls="layers-body">
Layers
</button>
</h2>
</div>
<div id="layers-body" class="collapse show" aria-labelledby="layers-header"
data-parent="#accordion">
<div class="card-body">
<div id="layers"></div>
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="tree-header">
<h2 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse"
data-target="#tree-body" aria-expanded="false" aria-controls="tree-body">
Object tree
</button>
</h2>
</div>
<div id="tree-body" class="collapse" aria-labelledby="tree-header" data-parent="#accordion">
<div class="card-body">
<div id="tree"></div>
</div>
</div>
</div>
</div>
<div class="col-lg-3" id="tree"></div>
<div class="col-lg-6">
<div class="row" id="layers"></div>
<div class="row container" id="canvas"></div>
</div>
<div class="col-lg-3" id="editor"></div>
</div>
</div>

View File

@ -5,8 +5,14 @@ package hep.dataforge.vis.spatial
import hep.dataforge.io.ConfigSerializer
import hep.dataforge.io.NameSerializer
import hep.dataforge.meta.*
import hep.dataforge.names.*
import hep.dataforge.vis.common.*
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.UseSerializers
import kotlin.collections.component1
@ -35,16 +41,21 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
override fun getStyle(name: Name): Meta? = (parent as VisualGroup?)?.getStyle(name)
override fun addStyle(name: Name, meta: Meta) {
(parent as VisualGroup?)?.addStyle(name, meta)
override fun addStyle(name: Name, meta: Meta, apply: Boolean) {
(parent as VisualGroup?)?.addStyle(name, meta, apply)
//do nothing
}
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
return if (inherit) {
super.getProperty(name, false) ?: prototype.getProperty(name, false) ?: parent?.getProperty(name, inherit)
properties?.get(name)
?: mergedStyles[name]
?: prototype.getProperty(name, false)
?: parent?.getProperty(name, inherit)
} else {
super.getProperty(name, false) ?: prototype.getProperty(name, false)
properties?.get(name)
?: mergedStyles[name]
?: prototype.getProperty(name, false)
}
}
@ -93,8 +104,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
override fun getStyle(name: Name): Meta? = this@Proxy.getStyle(name)
override fun addStyle(name: Name, meta: Meta) {
this@Proxy.addStyle(name, meta)
override fun addStyle(name: Name, meta: Meta, apply: Boolean) {
this@Proxy.addStyle(name, meta, apply)
}
override var properties: Config?
@ -118,8 +129,8 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
return if (inherit) {
properties?.get(name)
?: mergedStyles[name]
?: parent?.getProperty(name, inherit)
?: prototype.getProperty(name, inherit)
?: parent?.getProperty(name, inherit)
} else {
properties?.get(name)
?: mergedStyles[name]

View File

@ -0,0 +1,15 @@
package hep.dataforge.vis.spatial.editor
import kotlinx.html.TagConsumer
import kotlinx.html.js.div
import kotlinx.html.js.h3
import org.w3c.dom.HTMLElement
inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
div("card w-100") {
div("card-body") {
h3(classes = "card-title") { +title }
block()
}
}
}

View File

@ -9,21 +9,19 @@ 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.jsObject
import hep.dataforge.vis.spatial.Proxy
import hep.dataforge.vis.spatial.visible
import org.w3c.dom.HTMLElement
import info.laht.threekt.loaders.Cache.clear
import kotlinx.html.div
import kotlinx.html.dom.append
import org.w3c.dom.Element
import kotlin.js.json
operator fun Name.plus(other: NameToken): Name = Name(tokens + other)
fun InspireTree.render(element: HTMLElement, block: DomConfig.() -> Unit = {}) {
val config = (json(
"target" to element
) as DomConfig).apply(block)
InspireTreeDOM(this, config)
}
internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
private fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
val config = (json(
"checkbox" to json(
"autoCheckChildren" to false
@ -32,7 +30,7 @@ internal fun createInspireTree(block: Config.() -> Unit = {}): InspireTree {
return InspireTree(config)
}
fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }): InspireTree {
private fun VisualObject.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }): InspireTree {
val map = HashMap<String, VisualObject>()
@ -67,15 +65,17 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }):
}
fun TreeNode.fillChildren(group: VisualGroup, groupName: Name) {
group.children.forEach { (token, obj) ->
if(! token.body.startsWith("@")) {
val name = groupName + token
val nodeConfig = generateNodeConfig(obj, name)
val childNode = addChild(nodeConfig)
map[childNode.id] = obj
if (obj is VisualGroup) {
childNode.fillChildren(obj, name)
fun TreeNode.fillChildren(group: VisualObject, groupName: Name) {
if(group is VisualGroup) {
group.children.forEach { (token, obj) ->
if (!token.body.startsWith("@")) {
val name = groupName + token
val nodeConfig = generateNodeConfig(obj, name)
val childNode = addChild(nodeConfig)
map[childNode.id] = obj
if (obj is VisualGroup) {
childNode.fillChildren(obj, name)
}
}
}
}
@ -121,3 +121,16 @@ fun VisualGroup.toTree(onFocus: (VisualObject?, String?) -> Unit = { _, _ -> }):
return inspireTree
}
fun Element.visualObjectTree(group: VisualObject, onFocus: (VisualObject?, String?) -> Unit) {
clear()
append {
card("Visual object tree") {
val domConfig = jsObject<DomConfig> {
target = div()
showCheckboxes = false
}
InspireTreeDOM(group.toTree(onFocus), domConfig)
}
}
}

View File

@ -0,0 +1,37 @@
package hep.dataforge.vis.spatial.editor
import hep.dataforge.vis.spatial.three.ThreeOutput
import kotlinx.html.InputType
import kotlinx.html.dom.append
import kotlinx.html.js.div
import kotlinx.html.js.input
import kotlinx.html.js.label
import org.w3c.dom.Element
import kotlin.dom.clear
fun Element.threeOutputConfig(output: ThreeOutput) {
clear()
append {
card("Layers"){
div("row") {
(0..11).forEach { layer ->
div("col-1") {
label { +layer.toString() }
input(type = InputType.checkBox).apply {
if (layer == 0) {
checked = true
}
onchange = {
if (checked) {
output.camera.layers.enable(layer)
} else {
output.camera.layers.disable(layer)
}
}
}
}
}
}
}
}
}

View File

@ -2,10 +2,9 @@ package hep.dataforge.vis.spatial.editor
import hep.dataforge.io.toJson
import hep.dataforge.meta.*
import hep.dataforge.names.toName
import hep.dataforge.vis.common.VisualObject
import hep.dataforge.vis.common.findStyle
import hep.dataforge.vis.hmr.jsObject
import hep.dataforge.vis.jsObject
import hep.dataforge.vis.spatial.Material3D.Companion.COLOR_KEY
import hep.dataforge.vis.spatial.Material3D.Companion.OPACITY_KEY
import hep.dataforge.vis.spatial.VisualObject3D.Companion.VISIBLE_KEY
@ -15,11 +14,11 @@ import hep.dataforge.vis.spatial.prototype
import hep.dataforge.vis.spatial.visible
import kotlinx.html.dom.append
import kotlinx.html.js.div
import kotlinx.html.js.h3
import kotlinx.html.js.h4
import org.w3c.dom.Element
import kotlin.dom.clear
//FIXME something rotten in JS-Meta converter
fun Meta.toDynamic() = JSON.parse<dynamic>(toJson().toString())
@ -27,41 +26,34 @@ fun Element.propertyEditor(item: VisualObject?, name: String?) {
clear()
if (item != null) {
append {
div("card") {
div("card-body") {
h3(classes = "card-title") { +"Properties" }
}.apply {
val config = (item.properties ?: item.prototype?.properties) ?: EmptyMeta
val metaToEdit = config.builder().apply {
VISIBLE_KEY to (item.visible ?: true)
COLOR_KEY to (item.color ?: "#ffffff")
OPACITY_KEY to (item.opacity ?: 1.0)
}
//FIXME something rotten in JS-Meta converter
val dMeta: dynamic = metaToEdit.toDynamic()
//jsObject.material.color != null
val options: JSONEditorOptions = jsObject{
mode = "form"
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
}
JSONEditor(this, options, dMeta)
card("Properties") {
val config = (item.properties ?: item.prototype?.properties) ?: EmptyMeta
val metaToEdit = config.builder().apply {
VISIBLE_KEY to (item.visible ?: true)
COLOR_KEY to (item.color ?: "#ffffff")
OPACITY_KEY to (item.opacity ?: 1.0)
}
val dMeta: dynamic = metaToEdit.toDynamic()
val options: JSONEditorOptions = jsObject {
mode = "form"
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
}
JSONEditor(div(), options, dMeta)
}
div("card") {
div("card-body") {
h3(classes = "card-title") { +"Styles" }
}
item.styles.forEach { style ->
val styleMeta = item.findStyle(style)
h4 { +style.toString() }
if (styleMeta != null) {
div("container").apply {
val options: JSONEditorOptions = jsObject{
mode = "view"
val styles = item.styles
if (styles.isNotEmpty()) {
card("Styles") {
item.styles.forEach { style ->
val styleMeta = item.findStyle(style)
h4("container") { +style.toString() }
if (styleMeta != null) {
div("container").apply {
val options: JSONEditorOptions = jsObject {
mode = "view"
}
JSONEditor(this, options, styleMeta.toDynamic())
}
JSONEditor(this, options, styleMeta.toDynamic())
}
}
}

View File

@ -1,10 +1,10 @@
package hep.dataforge.vis.spatial.demo
import hep.dataforge.context.ContextBuilder
import hep.dataforge.vis.ApplicationBase
import hep.dataforge.vis.common.Colors
import hep.dataforge.vis.hmr.ApplicationBase
import hep.dataforge.vis.hmr.startApplication
import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.startApplication
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive