Readme update #25 #26
@ -1,13 +1,10 @@
|
|||||||
import scientifik.useSerialization
|
import scientifik.fx
|
||||||
|
import scientifik.serialization
|
||||||
|
|
||||||
val dataforgeVersion by extra("0.1.5-dev-6")
|
val dataforgeVersion by extra("0.1.7")
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
val kotlinVersion = "1.3.61"
|
val toolsVersion = "0.4.2"
|
||||||
val toolsVersion = "0.3.2"
|
|
||||||
|
|
||||||
kotlin("jvm") version kotlinVersion apply false
|
|
||||||
id("kotlin-dce-js") version kotlinVersion apply false
|
|
||||||
id("scientifik.mpp") version toolsVersion apply false
|
id("scientifik.mpp") version toolsVersion apply false
|
||||||
id("scientifik.jvm") version toolsVersion apply false
|
id("scientifik.jvm") version toolsVersion apply false
|
||||||
id("scientifik.js") version toolsVersion apply false
|
id("scientifik.js") version toolsVersion apply false
|
||||||
@ -21,21 +18,23 @@ allprojects {
|
|||||||
maven("https://dl.bintray.com/pdvrieze/maven")
|
maven("https://dl.bintray.com/pdvrieze/maven")
|
||||||
maven("http://maven.jzy3d.org/releases")
|
maven("http://maven.jzy3d.org/releases")
|
||||||
maven("https://kotlin.bintray.com/js-externals")
|
maven("https://kotlin.bintray.com/js-externals")
|
||||||
|
maven("https://kotlin.bintray.com/kotlin-js-wrappers/")
|
||||||
// maven("https://dl.bintray.com/gbaldeck/kotlin")
|
// maven("https://dl.bintray.com/gbaldeck/kotlin")
|
||||||
// maven("https://dl.bintray.com/rjaros/kotlin")
|
// maven("https://dl.bintray.com/rjaros/kotlin")
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "hep.dataforge"
|
group = "hep.dataforge"
|
||||||
version = "0.1.1-dev"
|
version = "0.1.3-dev"
|
||||||
}
|
|
||||||
|
|
||||||
subprojects{
|
|
||||||
this.useSerialization()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val githubProject by extra("dataforge-vis")
|
val githubProject by extra("dataforge-vis")
|
||||||
val bintrayRepo by extra("dataforge")
|
val bintrayRepo by extra("dataforge")
|
||||||
|
val fxVersion by extra("14")
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply(plugin = "scientifik.publish")
|
apply(plugin = "scientifik.publish")
|
||||||
|
serialization()
|
||||||
|
afterEvaluate {
|
||||||
|
fx(scientifik.FXModule.CONTROLS, version = fxVersion)
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,50 +1,47 @@
|
|||||||
import org.openjfx.gradle.JavaFXOptions
|
|
||||||
import scientifik.useSerialization
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("scientifik.mpp")
|
||||||
id("org.openjfx.javafxplugin")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion: String by rootProject.extra
|
val dataforgeVersion: String by rootProject.extra
|
||||||
//val kvisionVersion: String by rootProject.extra("2.0.0-M1")
|
//val kvisionVersion: String by rootProject.extra("2.0.0-M1")
|
||||||
|
|
||||||
useSerialization()
|
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvm{
|
|
||||||
withJava()
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain{
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("hep.dataforge:dataforge-output:$dataforgeVersion")
|
api("hep.dataforge:dataforge-output:$dataforgeVersion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmMain{
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("no.tornado:tornadofx:1.7.19")
|
api("no.tornado:tornadofx:1.7.20")
|
||||||
//api("no.tornado:tornadofx-controlsfx:0.1.1")
|
//api("no.tornado:tornadofx-controlsfx:0.1.1")
|
||||||
api("de.jensd:fontawesomefx-fontawesome:4.7.0-11"){
|
api("de.jensd:fontawesomefx-fontawesome:4.7.0-11") {
|
||||||
exclude(group = "org.openjfx")
|
exclude(group = "org.openjfx")
|
||||||
}
|
}
|
||||||
api("de.jensd:fontawesomefx-commons:11.0"){
|
api("de.jensd:fontawesomefx-commons:11.0") {
|
||||||
exclude(group = "org.openjfx")
|
exclude(group = "org.openjfx")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsMain{
|
jsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
api("hep.dataforge:dataforge-output-html:$dataforgeVersion")
|
||||||
//api(npm("bootstrap","4.4.1"))
|
|
||||||
implementation(npm("jsoneditor"))
|
//React, React DOM + Wrappers (chapter 3)
|
||||||
implementation(npm("file-saver"))
|
api("org.jetbrains:kotlin-react:16.13.0-pre.94-kotlin-1.3.70")
|
||||||
|
api("org.jetbrains:kotlin-react-dom:16.13.0-pre.94-kotlin-1.3.70")
|
||||||
|
api(npm("react", "16.13.0"))
|
||||||
|
api(npm("react-dom", "16.13.0"))
|
||||||
|
|
||||||
|
//Kotlin Styled (chapter 3)
|
||||||
|
api("org.jetbrains:kotlin-styled:1.0.0-pre.94-kotlin-1.3.70")
|
||||||
|
api(npm("styled-components"))
|
||||||
|
api(npm("inline-style-prefixer"))
|
||||||
|
|
||||||
|
api(npm("source-map-resolve","0.6.0"))
|
||||||
|
api(npm("file-saver","2.0.2"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<JavaFXOptions> {
|
|
||||||
modules("javafx.controls")
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.meta.MetaItem
|
import hep.dataforge.meta.MetaItem
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
@ -20,6 +20,17 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
|
|||||||
*/
|
*/
|
||||||
abstract override val children: Map<NameToken, VisualObject>
|
abstract override val children: Map<NameToken, VisualObject>
|
||||||
|
|
||||||
|
abstract override var styleSheet: StyleSheet?
|
||||||
|
protected set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update or create stylesheet
|
||||||
|
*/
|
||||||
|
fun styleSheet(block: StyleSheet.() -> Unit) {
|
||||||
|
val res = styleSheet ?: StyleSheet(this).also { styleSheet = it }
|
||||||
|
res.block()
|
||||||
|
}
|
||||||
|
|
||||||
override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) {
|
override fun propertyChanged(name: Name, before: MetaItem<*>?, after: MetaItem<*>?) {
|
||||||
super.propertyChanged(name, before, after)
|
super.propertyChanged(name, before, after)
|
||||||
forEach {
|
forEach {
|
||||||
@ -37,7 +48,12 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
|
|||||||
* Add listener for children change
|
* Add listener for children change
|
||||||
*/
|
*/
|
||||||
override fun onChildrenChange(owner: Any?, action: (Name, VisualObject?) -> Unit) {
|
override fun onChildrenChange(owner: Any?, action: (Name, VisualObject?) -> Unit) {
|
||||||
structureChangeListeners.add(StructureChangeListeners(owner, action))
|
structureChangeListeners.add(
|
||||||
|
StructureChangeListeners(
|
||||||
|
owner,
|
||||||
|
action
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,12 +84,41 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
|
|||||||
* Add a static child. Statics could not be found by name, removed or replaced
|
* Add a static child. Statics could not be found by name, removed or replaced
|
||||||
*/
|
*/
|
||||||
protected open fun addStatic(child: VisualObject) =
|
protected open fun addStatic(child: VisualObject) =
|
||||||
setChild(NameToken("@static(${child.hashCode()})"), child)
|
set(NameToken("@static(${child.hashCode()})").asName(), child)
|
||||||
|
|
||||||
|
protected abstract fun createGroup(): AbstractVisualGroup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this node as parent for given node
|
||||||
|
*/
|
||||||
|
protected fun attach(child: VisualObject) {
|
||||||
|
if (child.parent == null) {
|
||||||
|
child.parent = this
|
||||||
|
} else if (child.parent !== this) {
|
||||||
|
error("Can't reassign existing parent for $child")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively create a child group
|
* Recursively create a child group
|
||||||
*/
|
*/
|
||||||
protected abstract fun createGroup(name: Name): MutableVisualGroup
|
private fun createGroups(name: Name): AbstractVisualGroup {
|
||||||
|
return when {
|
||||||
|
name.isEmpty() -> error("Should be unreachable")
|
||||||
|
name.length == 1 -> {
|
||||||
|
val token = name.first()!!
|
||||||
|
when (val current = children[token]) {
|
||||||
|
null -> createGroup().also { child ->
|
||||||
|
attach(child)
|
||||||
|
setChild(token, child)
|
||||||
|
}
|
||||||
|
is AbstractVisualGroup -> current
|
||||||
|
else -> error("Can't create group with name $name because it exists and not a group")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> createGroups(name.first()!!.asName()).createGroups(name.cutFirst())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add named or unnamed child to the group. If key is null the child is considered unnamed. Both key and value are not
|
* Add named or unnamed child to the group. If key is null the child is considered unnamed. Both key and value are not
|
||||||
@ -91,16 +136,17 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup
|
|||||||
if (child == null) {
|
if (child == null) {
|
||||||
removeChild(token)
|
removeChild(token)
|
||||||
} else {
|
} else {
|
||||||
|
attach(child)
|
||||||
setChild(token, child)
|
setChild(token, child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
//TODO add safety check
|
//TODO add safety check
|
||||||
val parent = (get(name.cutLast()) as? MutableVisualGroup) ?: createGroup(name.cutLast())
|
val parent = (get(name.cutLast()) as? MutableVisualGroup) ?: createGroups(name.cutLast())
|
||||||
parent[name.last()!!.asName()] = child
|
parent[name.last()!!.asName()] = child
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
structureChangeListeners.forEach { it.callback(name, child) }
|
childrenChanged(name, child)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,9 +1,10 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.vis.common.VisualObject.Companion.STYLE_KEY
|
import hep.dataforge.values.Value
|
||||||
|
import hep.dataforge.vis.VisualObject.Companion.STYLE_KEY
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
internal data class PropertyListener(
|
internal data class PropertyListener(
|
||||||
@ -14,7 +15,7 @@ internal data class PropertyListener(
|
|||||||
abstract class AbstractVisualObject : VisualObject {
|
abstract class AbstractVisualObject : VisualObject {
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
override var parent: VisualObject? = null
|
override var parent: VisualGroup? = null
|
||||||
|
|
||||||
protected abstract var properties: Config?
|
protected abstract var properties: Config?
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ abstract class AbstractVisualObject : VisualObject {
|
|||||||
get() = properties?.get(STYLE_KEY).stringList
|
get() = properties?.get(STYLE_KEY).stringList
|
||||||
set(value) {
|
set(value) {
|
||||||
//val allStyles = (field + value).distinct()
|
//val allStyles = (field + value).distinct()
|
||||||
setProperty(STYLE_KEY, value)
|
setProperty(STYLE_KEY, Value.of(value))
|
||||||
updateStyles(value)
|
updateStyles(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ abstract class AbstractVisualObject : VisualObject {
|
|||||||
private var styleCache: Meta? = null
|
private var styleCache: Meta? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect all styles for this object in a laminate
|
* Collect all styles for this object in a single cached meta
|
||||||
*/
|
*/
|
||||||
protected val mergedStyles: Meta
|
protected val mergedStyles: Meta
|
||||||
get() = styleCache ?: findAllStyles().merge().also {
|
get() = styleCache ?: findAllStyles().merge().also {
|
@ -1,6 +1,9 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.get
|
||||||
|
import hep.dataforge.meta.number
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.values.int
|
import hep.dataforge.values.int
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@ -234,7 +237,7 @@ object Colors {
|
|||||||
/**
|
/**
|
||||||
* Convert three bytes representing color to Meta
|
* Convert three bytes representing color to Meta
|
||||||
*/
|
*/
|
||||||
fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = buildMeta {
|
fun rgbToMeta(r: UByte, g: UByte, b: UByte): Meta = Meta {
|
||||||
RED_KEY put r.toInt()
|
RED_KEY put r.toInt()
|
||||||
GREEN_KEY put g.toInt()
|
GREEN_KEY put g.toInt()
|
||||||
BLUE_KEY put b.toInt()
|
BLUE_KEY put b.toInt()
|
@ -0,0 +1,31 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Config
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("group")
|
||||||
|
class SimpleVisualGroup : AbstractVisualGroup() {
|
||||||
|
|
||||||
|
override var styleSheet: StyleSheet? = null
|
||||||
|
|
||||||
|
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
||||||
|
override var properties: Config? = null
|
||||||
|
|
||||||
|
@SerialName("children")
|
||||||
|
private val _children = HashMap<NameToken, VisualObject>()
|
||||||
|
override val children: Map<NameToken, VisualObject> get() = _children
|
||||||
|
|
||||||
|
override fun removeChild(token: NameToken) {
|
||||||
|
_children.remove(token)?.apply { parent = null }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setChild(token: NameToken, child: VisualObject) {
|
||||||
|
_children[token] = child
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createGroup(): SimpleVisualGroup = SimpleVisualGroup()
|
||||||
|
}
|
@ -1,18 +1,19 @@
|
|||||||
@file:UseSerializers(MetaSerializer::class)
|
@file:UseSerializers(MetaSerializer::class)
|
||||||
|
|
||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.MetaSerializer
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.builtins.MapSerializer
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container for styles
|
* A container for styles
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class StyleSheet() {
|
class StyleSheet private constructor(private val styleMap: MutableMap<String, Meta> = LinkedHashMap()) {
|
||||||
@Transient
|
@Transient
|
||||||
internal var owner: VisualObject? = null
|
internal var owner: VisualObject? = null
|
||||||
|
|
||||||
@ -20,12 +21,10 @@ class StyleSheet() {
|
|||||||
this.owner = owner
|
this.owner = owner
|
||||||
}
|
}
|
||||||
|
|
||||||
private val styleMap = HashMap<String, Meta>()
|
|
||||||
|
|
||||||
val items: Map<String, Meta> get() = styleMap
|
val items: Map<String, Meta> get() = styleMap
|
||||||
|
|
||||||
operator fun get(key: String): Meta? {
|
operator fun get(key: String): Meta? {
|
||||||
return styleMap[key] ?: (owner?.parent as? VisualGroup)?.styleSheet?.get(key)
|
return styleMap[key] ?: owner?.parent?.styleSheet?.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,20 +45,23 @@ class StyleSheet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(key: String, builder: MetaBuilder.() -> Unit) {
|
operator fun set(key: String, builder: MetaBuilder.() -> Unit) {
|
||||||
val newStyle = get(key)?.let { buildMeta(it, builder) } ?: buildMeta(builder)
|
val newStyle = get(key)?.edit(builder) ?: Meta(builder)
|
||||||
set(key, newStyle.seal())
|
set(key, newStyle.seal())
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object: KSerializer<StyleSheet>{
|
@Serializer(StyleSheet::class)
|
||||||
override val descriptor: SerialDescriptor
|
companion object : KSerializer<StyleSheet> {
|
||||||
get() = TODO("Not yet implemented")
|
private val mapSerializer = MapSerializer(String.serializer(), MetaSerializer)
|
||||||
|
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
|
||||||
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): StyleSheet {
|
override fun deserialize(decoder: Decoder): StyleSheet {
|
||||||
TODO("Not yet implemented")
|
val map = mapSerializer.deserialize(decoder)
|
||||||
|
return StyleSheet(map as? MutableMap<String, Meta> ?: LinkedHashMap(map))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, obj: StyleSheet) {
|
override fun serialize(encoder: Encoder, value: StyleSheet) {
|
||||||
TODO("Not yet implemented")
|
mapSerializer.serialize(encoder, value.items)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.context.*
|
import hep.dataforge.context.*
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
@ -31,7 +31,8 @@ class Visual(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
override val tag: PluginTag = PluginTag(name = "visual", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag(name = "visual", group = PluginTag.DATAFORGE_GROUP)
|
||||||
override val type: KClass<out Visual> = Visual::class
|
override val type: KClass<out Visual> = Visual::class
|
||||||
|
|
||||||
override fun invoke(meta: Meta, context: Context): Visual = Visual(meta)
|
override fun invoke(meta: Meta, context: Context): Visual =
|
||||||
|
Visual(meta)
|
||||||
|
|
||||||
const val VISUAL_FACTORY_TYPE = "visual.factory"
|
const val VISUAL_FACTORY_TYPE = "visual.factory"
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.provider.Provider
|
import hep.dataforge.provider.Provider
|
||||||
@ -6,7 +6,8 @@ import hep.dataforge.provider.Provider
|
|||||||
/**
|
/**
|
||||||
* Represents a group of [VisualObject] instances
|
* Represents a group of [VisualObject] instances
|
||||||
*/
|
*/
|
||||||
interface VisualGroup : Provider, Iterable<VisualObject>, VisualObject {
|
interface VisualGroup : Provider, Iterable<VisualObject>,
|
||||||
|
VisualObject {
|
||||||
/**
|
/**
|
||||||
* A map of top level named children
|
* A map of top level named children
|
||||||
*/
|
*/
|
@ -1,11 +1,15 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.Configurable
|
||||||
|
import hep.dataforge.meta.Laminate
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
import hep.dataforge.vis.VisualObject.Companion.TYPE
|
||||||
|
import kotlinx.serialization.PolymorphicSerializer
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
//private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
//private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
||||||
@ -21,24 +25,19 @@ interface VisualObject : Configurable {
|
|||||||
* The parent object of this one. If null, this one is a root.
|
* The parent object of this one. If null, this one is a root.
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
var parent: VisualObject?
|
var parent: VisualGroup?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All properties including styles and prototypes if present, but without inheritance
|
* All properties including styles and prototypes if present, but without inheritance
|
||||||
*/
|
*/
|
||||||
fun allProperties(): Laminate
|
fun allProperties(): Laminate
|
||||||
|
|
||||||
/**
|
|
||||||
* Set property for this object
|
|
||||||
*/
|
|
||||||
fun setProperty(name: Name, value: Any?) {
|
|
||||||
config[name] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get property including or excluding parent properties
|
* Get property including or excluding parent properties
|
||||||
*/
|
*/
|
||||||
fun getProperty(name: Name, inherit: Boolean = true): MetaItem<*>?
|
fun getProperty(name: Name, inherit: Boolean): MetaItem<*>?
|
||||||
|
|
||||||
|
override fun getProperty(name: Name): MetaItem<*>? = getProperty(name, true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger property invalidation event. If [name] is empty, notify that the whole object is changed
|
* Trigger property invalidation event. If [name] is empty, notify that the whole object is changed
|
||||||
@ -66,6 +65,10 @@ interface VisualObject : Configurable {
|
|||||||
const val TYPE = "visual"
|
const val TYPE = "visual"
|
||||||
val STYLE_KEY = "@style".asName()
|
val STYLE_KEY = "@style".asName()
|
||||||
|
|
||||||
|
private val VISUAL_OBJECT_SERIALIZER = PolymorphicSerializer(VisualObject::class)
|
||||||
|
|
||||||
|
fun serializer() = VISUAL_OBJECT_SERIALIZER
|
||||||
|
|
||||||
//const val META_KEY = "@meta"
|
//const val META_KEY = "@meta"
|
||||||
//const val TAGS_KEY = "@tags"
|
//const val TAGS_KEY = "@tags"
|
||||||
|
|
||||||
@ -77,11 +80,6 @@ interface VisualObject : Configurable {
|
|||||||
*/
|
*/
|
||||||
fun VisualObject.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = getProperty(key.toName(), inherit)
|
fun VisualObject.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = getProperty(key.toName(), inherit)
|
||||||
|
|
||||||
/**
|
|
||||||
* Set [VisualObject] property using key as a String
|
|
||||||
*/
|
|
||||||
fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(), value)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
||||||
*/
|
*/
|
@ -1,4 +1,4 @@
|
|||||||
package hep.dataforge.vis.common
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
@ -105,8 +105,8 @@ fun VisualObject.int(default: Int, name: Name? = null, inherited: Boolean = fals
|
|||||||
|
|
||||||
|
|
||||||
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, name: Name? = null, inherited: Boolean = false) =
|
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, name: Name? = null, inherited: Boolean = false) =
|
||||||
VisualObjectDelegateWrapper(this, name, default, inherited) {
|
VisualObjectDelegateWrapper(this, name, default, inherited) { item ->
|
||||||
item -> item.string?.let { enumValueOf<E>(it) }
|
item.string?.let { enumValueOf<E>(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
//merge properties
|
//merge properties
|
@ -1,22 +0,0 @@
|
|||||||
package hep.dataforge.vis.common
|
|
||||||
|
|
||||||
import hep.dataforge.descriptors.ValueDescriptor
|
|
||||||
import hep.dataforge.meta.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension property to access the "widget" key of [ValueDescriptor]
|
|
||||||
*/
|
|
||||||
var ValueDescriptor.widget: Meta
|
|
||||||
get() = this.config["widget"].node?: EmptyMeta
|
|
||||||
set(value) {
|
|
||||||
this.config["widget"] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension property to access the "widget.type" key of [ValueDescriptor]
|
|
||||||
*/
|
|
||||||
var ValueDescriptor.widgetType: String?
|
|
||||||
get() = this["widget.type"].string
|
|
||||||
set(value) {
|
|
||||||
this.config["widget.type"] = value
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.isEmpty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return nearest selectable parent [Name]
|
||||||
|
*/
|
||||||
|
tailrec fun Name.selectable(): Name? = when {
|
||||||
|
isEmpty() -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
last()?.body?.startsWith("@") != true -> {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
cutLast().selectable()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package hep.dataforge.vis
|
||||||
|
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||||
|
import hep.dataforge.values.asValue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension property to access the "widget" key of [ValueDescriptor]
|
||||||
|
*/
|
||||||
|
var ValueDescriptor.widget: Meta
|
||||||
|
get() = getProperty("widget").node ?: Meta.EMPTY
|
||||||
|
set(value) {
|
||||||
|
setProperty("widget", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension property to access the "widget.type" key of [ValueDescriptor]
|
||||||
|
*/
|
||||||
|
var ValueDescriptor.widgetType: String?
|
||||||
|
get() = getProperty("widget.type").string
|
||||||
|
set(value) {
|
||||||
|
setProperty("widget.type", value?.asValue())
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package hep.dataforge.js
|
||||||
|
|
||||||
|
import kotlinx.html.*
|
||||||
|
import kotlinx.html.js.div
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.*
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun RBuilder.card(title: String, crossinline block: RBuilder.() -> Unit) {
|
||||||
|
div("card w-100") {
|
||||||
|
div("card-body") {
|
||||||
|
h3(classes = "card-title") { +title }
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun TagConsumer<HTMLElement>.accordion(id: String, elements: List<Pair<String, DIV.() -> Unit>>) {
|
||||||
|
div("container-fluid") {
|
||||||
|
div("accordion") {
|
||||||
|
this.id = id
|
||||||
|
elements.forEachIndexed { index, (title, builder) ->
|
||||||
|
val headerID = "${id}-${index}-heading"
|
||||||
|
val collapseID = "${id}-${index}-collapse"
|
||||||
|
div("card") {
|
||||||
|
div("card-header") {
|
||||||
|
this.id = headerID
|
||||||
|
h5("mb-0") {
|
||||||
|
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
attributes["data-toggle"] = "collapse"
|
||||||
|
attributes["data-target"] = "#$collapseID"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["aria-controls"] = collapseID
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("collapse") {
|
||||||
|
this.id = collapseID
|
||||||
|
attributes["aria-labelledby"] = headerID
|
||||||
|
attributes["data-parent"] = "#$id"
|
||||||
|
div("card-body", block = builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typealias AccordionBuilder = MutableList<Pair<String, DIV.() -> Unit>>
|
||||||
|
|
||||||
|
fun AccordionBuilder.entry(title: String, builder: DIV.() -> Unit) {
|
||||||
|
add(title to builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TagConsumer<HTMLElement>.accordion(id: String, builder: AccordionBuilder.() -> Unit) {
|
||||||
|
val list = ArrayList<Pair<String, DIV.() -> Unit>>().apply(builder)
|
||||||
|
accordion(id, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.accordion(id: String, elements: List<Pair<String, RDOMBuilder<DIV>.() -> Unit>>) {
|
||||||
|
div("container-fluid") {
|
||||||
|
div("accordion") {
|
||||||
|
attrs {
|
||||||
|
this.id = id
|
||||||
|
}
|
||||||
|
elements.forEachIndexed { index, (title, builder) ->
|
||||||
|
val headerID = "${id}-${index}-heading"
|
||||||
|
val collapseID = "${id}-${index}-collapse"
|
||||||
|
div("card") {
|
||||||
|
div("card-header") {
|
||||||
|
attrs {
|
||||||
|
this.id = headerID
|
||||||
|
}
|
||||||
|
h5("mb-0") {
|
||||||
|
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
attrs {
|
||||||
|
attributes["data-toggle"] = "collapse"
|
||||||
|
attributes["data-target"] = "#$collapseID"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["aria-controls"] = collapseID
|
||||||
|
}
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("collapse") {
|
||||||
|
attrs {
|
||||||
|
this.id = collapseID
|
||||||
|
attributes["aria-labelledby"] = headerID
|
||||||
|
attributes["data-parent"] = "#$id"
|
||||||
|
}
|
||||||
|
div("card-body", block = builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias RAccordionBuilder = MutableList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>
|
||||||
|
|
||||||
|
fun RAccordionBuilder.entry(title: String, builder: RDOMBuilder<DIV>.() -> Unit) {
|
||||||
|
add(title to builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.accordion(id: String, builder: RAccordionBuilder.() -> Unit) {
|
||||||
|
val list = ArrayList<Pair<String, RDOMBuilder<DIV>.() -> Unit>>().apply(builder)
|
||||||
|
accordion(id, list)
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package hep.dataforge.js
|
||||||
|
|
||||||
|
import react.RBuilder
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
fun <T> RBuilder.initState(init: () -> T): ReadWriteProperty<Any?, T> =
|
||||||
|
object : ReadWriteProperty<Any?, T> {
|
||||||
|
val pair = react.useState(init)
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
|
return pair.first
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
|
pair.second(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,280 @@
|
|||||||
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.meta.descriptors.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import hep.dataforge.names.plus
|
||||||
|
import hep.dataforge.values.*
|
||||||
|
import hep.dataforge.vis.widgetType
|
||||||
|
import kotlinx.html.ButtonType
|
||||||
|
import kotlinx.html.InputType
|
||||||
|
import kotlinx.html.classes
|
||||||
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
import org.w3c.dom.HTMLSelectElement
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.RBuilder
|
||||||
|
import react.RComponent
|
||||||
|
import react.RProps
|
||||||
|
import react.dom.*
|
||||||
|
import react.setState
|
||||||
|
|
||||||
|
interface ConfigEditorProps : RProps {
|
||||||
|
/**
|
||||||
|
* Root config object - always non null
|
||||||
|
*/
|
||||||
|
var root: Config
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full path to the displayed node in [root]. Could be empty
|
||||||
|
*/
|
||||||
|
var name: Name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root default
|
||||||
|
*/
|
||||||
|
var default: Meta?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root descriptor
|
||||||
|
*/
|
||||||
|
var descriptor: NodeDescriptor?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigEditorComponent : RComponent<ConfigEditorProps, TreeState>() {
|
||||||
|
|
||||||
|
override fun TreeState.init() {
|
||||||
|
expanded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun componentDidMount() {
|
||||||
|
props.root.onChange(this) { name, _, _ ->
|
||||||
|
if (name == props.name) {
|
||||||
|
forceUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun componentWillUnmount() {
|
||||||
|
props.root.removeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onClick: (Event) -> Unit = {
|
||||||
|
setState {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onValueChange: (Event) -> Unit = {
|
||||||
|
val value = when (val t = it.target) {
|
||||||
|
// (it.target as HTMLInputElement).value
|
||||||
|
is HTMLInputElement -> if (t.type == "checkbox") {
|
||||||
|
if (t.checked) True else False
|
||||||
|
} else {
|
||||||
|
t.value.asValue()
|
||||||
|
}
|
||||||
|
is HTMLSelectElement -> t.value.asValue()
|
||||||
|
else -> error("Unknown event target: $t")
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
props.root.setValue(props.name, value)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
console.error("Can't set config property ${props.name} to $value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val removeValue: (Event) -> Unit = {
|
||||||
|
props.root.remove(props.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO replace by separate components
|
||||||
|
private fun RBuilder.valueChooser(value: Value, descriptor: ValueDescriptor?) {
|
||||||
|
val type = descriptor?.type?.firstOrNull()
|
||||||
|
when {
|
||||||
|
type == ValueType.BOOLEAN -> {
|
||||||
|
input(type = InputType.checkBox, classes = "float-right") {
|
||||||
|
attrs {
|
||||||
|
defaultChecked = value.boolean
|
||||||
|
onChangeFunction = onValueChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type == ValueType.NUMBER -> input(type = InputType.number, classes = "float-right") {
|
||||||
|
attrs {
|
||||||
|
descriptor.attributes["step"].string?.let {
|
||||||
|
step = it
|
||||||
|
}
|
||||||
|
descriptor.attributes["min"].string?.let {
|
||||||
|
min = it
|
||||||
|
}
|
||||||
|
descriptor.attributes["max"].string?.let {
|
||||||
|
max = it
|
||||||
|
}
|
||||||
|
defaultValue = value.string
|
||||||
|
onChangeFunction = onValueChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptor?.allowedValues?.isNotEmpty() ?: false -> select("float-right") {
|
||||||
|
descriptor!!.allowedValues.forEach {
|
||||||
|
option {
|
||||||
|
+it.string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
multiple = false
|
||||||
|
onChangeFunction = onValueChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptor?.widgetType == "color" -> input(type = InputType.color, classes = "float-right") {
|
||||||
|
attrs {
|
||||||
|
defaultValue = value.string
|
||||||
|
onChangeFunction = onValueChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> input(type = InputType.text, classes = "float-right") {
|
||||||
|
attrs {
|
||||||
|
defaultValue = value.string
|
||||||
|
onChangeFunction = onValueChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun RBuilder.render() {
|
||||||
|
val item = props.root[props.name]
|
||||||
|
val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name)
|
||||||
|
val defaultItem = props.default?.get(props.name)
|
||||||
|
val actualItem = item ?: defaultItem ?: descriptorItem?.defaultItem()
|
||||||
|
val token = props.name.last()?.toString() ?: "Properties"
|
||||||
|
|
||||||
|
when (actualItem) {
|
||||||
|
is MetaItem.NodeItem -> {
|
||||||
|
div {
|
||||||
|
span("tree-caret") {
|
||||||
|
attrs {
|
||||||
|
if (state.expanded) {
|
||||||
|
classes += "tree-caret-down"
|
||||||
|
}
|
||||||
|
onClickFunction = onClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span("tree-label") {
|
||||||
|
+token
|
||||||
|
attrs {
|
||||||
|
if (item == null) {
|
||||||
|
classes += "tree-label-inactive"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.expanded) {
|
||||||
|
ul("tree") {
|
||||||
|
val keys = buildSet<NameToken> {
|
||||||
|
item?.node?.items?.keys?.let { addAll(it) }
|
||||||
|
defaultItem?.node?.items?.keys?.let { addAll(it) }
|
||||||
|
(descriptorItem as? NodeDescriptor)?.items?.keys?.forEach {
|
||||||
|
add(NameToken(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.forEach { token ->
|
||||||
|
li("tree-item") {
|
||||||
|
child(ConfigEditorComponent::class) {
|
||||||
|
attrs {
|
||||||
|
this.root = props.root
|
||||||
|
this.name = props.name + token
|
||||||
|
this.default = props.default
|
||||||
|
this.descriptor = props.descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is MetaItem.ValueItem -> {
|
||||||
|
div {
|
||||||
|
div("row") {
|
||||||
|
div("col") {
|
||||||
|
p("tree-label") {
|
||||||
|
+token
|
||||||
|
attrs {
|
||||||
|
if (item == null) {
|
||||||
|
classes += "tree-label-inactive"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("col") {
|
||||||
|
valueChooser(actualItem.value, descriptorItem as? ValueDescriptor)
|
||||||
|
}
|
||||||
|
div("col-auto") {
|
||||||
|
div("dropleft p-0") {
|
||||||
|
button(classes = "btn btn-outline-primary") {
|
||||||
|
attrs {
|
||||||
|
type = ButtonType.button
|
||||||
|
attributes["data-toggle"] = "dropdown"
|
||||||
|
attributes["aria-haspopup"] = "true"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["data-boundary"] = "viewport"
|
||||||
|
}
|
||||||
|
+"\u22ee"
|
||||||
|
}
|
||||||
|
div(classes = "dropdown-menu") {
|
||||||
|
button(classes = "btn btn-outline dropdown-item") {
|
||||||
|
+"Info"
|
||||||
|
}
|
||||||
|
if (item != null) {
|
||||||
|
button(classes = "btn btn-outline dropdown-item") {
|
||||||
|
+"""Clear"""
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
onClickFunction = removeValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null) {
|
||||||
|
render(this) {
|
||||||
|
child(ConfigEditorComponent::class) {
|
||||||
|
attrs {
|
||||||
|
root = config
|
||||||
|
name = Name.EMPTY
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.default = default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null) {
|
||||||
|
div {
|
||||||
|
child(ConfigEditorComponent::class) {
|
||||||
|
attrs {
|
||||||
|
root = config
|
||||||
|
name = Name.EMPTY
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.default = default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.configEditor(obj: Configurable, descriptor: NodeDescriptor? = obj.descriptor, default: Meta? = null) {
|
||||||
|
configEditor(obj.config, descriptor ?: obj.descriptor, default)
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.MetaItem
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import kotlinx.html.classes
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.RBuilder
|
||||||
|
import react.RComponent
|
||||||
|
import react.RProps
|
||||||
|
import react.dom.*
|
||||||
|
import react.setState
|
||||||
|
|
||||||
|
interface MetaViewerProps : RProps {
|
||||||
|
var name: NameToken
|
||||||
|
var meta: Meta
|
||||||
|
var descriptor: NodeDescriptor?
|
||||||
|
}
|
||||||
|
|
||||||
|
class MetaViewerComponent : RComponent<MetaViewerProps, TreeState>() {
|
||||||
|
|
||||||
|
override fun TreeState.init() {
|
||||||
|
expanded = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onClick: (Event) -> Unit = {
|
||||||
|
setState {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun RBuilder.render() {
|
||||||
|
div("d-inline-block text-truncate") {
|
||||||
|
if (props.meta.items.isNotEmpty()) {
|
||||||
|
span("tree-caret") {
|
||||||
|
attrs {
|
||||||
|
if (state.expanded) {
|
||||||
|
classes += "tree-caret-down"
|
||||||
|
}
|
||||||
|
onClickFunction = onClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label("tree-label") {
|
||||||
|
+props.name.toString()
|
||||||
|
}
|
||||||
|
ul("tree") {
|
||||||
|
props.meta.items.forEach { (token, item) ->
|
||||||
|
//val descriptor = props.
|
||||||
|
li {
|
||||||
|
when (item) {
|
||||||
|
is MetaItem.NodeItem -> {
|
||||||
|
child(MetaViewerComponent::class) {
|
||||||
|
attrs {
|
||||||
|
name = token
|
||||||
|
meta = item.node
|
||||||
|
descriptor = props.descriptor?.nodes?.get(token.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is MetaItem.ValueItem -> {
|
||||||
|
div("row") {
|
||||||
|
div("col") {
|
||||||
|
label("tree-label") {
|
||||||
|
+token.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("col") {
|
||||||
|
label {
|
||||||
|
+item.value.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
import hep.dataforge.js.card
|
||||||
|
import hep.dataforge.js.initState
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.plus
|
||||||
|
import hep.dataforge.names.startsWith
|
||||||
|
import hep.dataforge.vis.VisualGroup
|
||||||
|
import hep.dataforge.vis.VisualObject
|
||||||
|
import hep.dataforge.vis.isEmpty
|
||||||
|
import kotlinx.html.classes
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.*
|
||||||
|
import react.dom.*
|
||||||
|
|
||||||
|
interface ObjectTreeProps : RProps {
|
||||||
|
var name: Name
|
||||||
|
var selected: Name?
|
||||||
|
var obj: VisualObject
|
||||||
|
var clickCallback: (Name) -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TreeState : RState {
|
||||||
|
var expanded: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun RBuilder.objectTree(props: ObjectTreeProps): Unit {
|
||||||
|
var expanded: Boolean by initState{ props.selected?.startsWith(props.name) ?: false }
|
||||||
|
|
||||||
|
val onClick: (Event) -> Unit = {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.treeLabel(text: String) {
|
||||||
|
button(classes = "btn btn-link tree-label p-0") {
|
||||||
|
+text
|
||||||
|
attrs {
|
||||||
|
if (props.name == props.selected) {
|
||||||
|
classes += "tree-label-selected"
|
||||||
|
}
|
||||||
|
onClickFunction = { props.clickCallback(props.name) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val token = props.name.last()?.toString() ?: "World"
|
||||||
|
val obj = props.obj
|
||||||
|
|
||||||
|
//display as node if any child is visible
|
||||||
|
if (obj is VisualGroup) {
|
||||||
|
div("d-block text-truncate") {
|
||||||
|
if (obj.children.any { !it.key.body.startsWith("@") }) {
|
||||||
|
span("tree-caret") {
|
||||||
|
attrs {
|
||||||
|
if (expanded) {
|
||||||
|
classes += "tree-caret-down"
|
||||||
|
}
|
||||||
|
onClickFunction = onClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
treeLabel(token)
|
||||||
|
}
|
||||||
|
if (expanded) {
|
||||||
|
ul("tree") {
|
||||||
|
obj.children.entries
|
||||||
|
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
||||||
|
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
||||||
|
.forEach { (childToken, child) ->
|
||||||
|
li("tree-item") {
|
||||||
|
child(ObjectTree) {
|
||||||
|
attrs {
|
||||||
|
this.name = props.name + childToken
|
||||||
|
this.obj = child
|
||||||
|
this.selected = props.selected
|
||||||
|
this.clickCallback = props.clickCallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
div("d-block text-truncate") {
|
||||||
|
span("tree-leaf") {}
|
||||||
|
treeLabel(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ObjectTree: FunctionalComponent<ObjectTreeProps> = functionalComponent { props ->
|
||||||
|
objectTree(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.renderObjectTree(
|
||||||
|
visualObject: VisualObject,
|
||||||
|
clickCallback: (Name) -> Unit = {}
|
||||||
|
) = render(this) {
|
||||||
|
card("Object tree") {
|
||||||
|
child(ObjectTree) {
|
||||||
|
attrs {
|
||||||
|
this.name = Name.EMPTY
|
||||||
|
this.obj = visualObject
|
||||||
|
this.selected = null
|
||||||
|
this.clickCallback = clickCallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.objectTree(
|
||||||
|
visualObject: VisualObject,
|
||||||
|
selected: Name? = null,
|
||||||
|
clickCallback: (Name) -> Unit = {}
|
||||||
|
) {
|
||||||
|
child(ObjectTree) {
|
||||||
|
attrs {
|
||||||
|
this.name = Name.EMPTY
|
||||||
|
this.obj = visualObject
|
||||||
|
this.selected = selected
|
||||||
|
this.clickCallback = clickCallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
|||||||
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
import hep.dataforge.js.card
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.isEmpty
|
||||||
|
import hep.dataforge.vis.VisualObject
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.li
|
||||||
|
import react.dom.nav
|
||||||
|
import react.dom.ol
|
||||||
|
import react.dom.render
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
fun RBuilder.visualPropertyEditor(
|
||||||
|
path: Name,
|
||||||
|
item: VisualObject,
|
||||||
|
descriptor: NodeDescriptor? = item.descriptor,
|
||||||
|
default: Meta? = null
|
||||||
|
) {
|
||||||
|
card("Properties") {
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
nav {
|
||||||
|
attrs {
|
||||||
|
attributes["aria-label"] = "breadcrumb"
|
||||||
|
}
|
||||||
|
ol("breadcrumb") {
|
||||||
|
path.tokens.forEach { token ->
|
||||||
|
li("breadcrumb-item") {
|
||||||
|
+token.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configEditor(item, descriptor, default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.visualPropertyEditor(
|
||||||
|
path: Name,
|
||||||
|
item: VisualObject,
|
||||||
|
descriptor: NodeDescriptor? = item.descriptor,
|
||||||
|
default: Meta? = null
|
||||||
|
) = render(this) {
|
||||||
|
this.visualPropertyEditor(path, item, descriptor, default)
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
|
//val TextValueChooser = functionalComponent<ConfigEditorProps> {
|
||||||
|
//
|
||||||
|
// input(type = InputType.number, classes = "float-right") {
|
||||||
|
// attrs {
|
||||||
|
// defaultValue = value.string
|
||||||
|
// onChangeFunction = onValueChange
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
@ -1,61 +0,0 @@
|
|||||||
package hep.dataforge.vis.js.editor
|
|
||||||
|
|
||||||
import kotlinx.html.*
|
|
||||||
import kotlinx.html.js.div
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun TagConsumer<HTMLElement>.accordion(id: String, elements: Map<String, DIV.() -> Unit>) {
|
|
||||||
div("container-fluid") {
|
|
||||||
div("accordion") {
|
|
||||||
this.id = id
|
|
||||||
elements.entries.forEachIndexed { index, (title, builder) ->
|
|
||||||
val headerID = "${id}-${index}-heading"
|
|
||||||
val collapseID = "${id}-${index}-collapse"
|
|
||||||
div("card") {
|
|
||||||
div("card-header") {
|
|
||||||
this.id = headerID
|
|
||||||
h5("mb-0") {
|
|
||||||
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
|
||||||
attributes["data-toggle"] = "collapse"
|
|
||||||
attributes["data-target"] = "#$collapseID"
|
|
||||||
attributes["aria-expanded"] = "false"
|
|
||||||
attributes["aria-controls"] = collapseID
|
|
||||||
+title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div("collapse") {
|
|
||||||
this.id = collapseID
|
|
||||||
attributes["aria-labelledby"] = headerID
|
|
||||||
attributes["data-parent"] = "#$id"
|
|
||||||
div("card-body", block = builder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AccordionBuilder {
|
|
||||||
private val map = HashMap<String, DIV.() -> Unit>()
|
|
||||||
fun entry(title: String, block: DIV.() -> Unit) {
|
|
||||||
map[title] = block
|
|
||||||
}
|
|
||||||
|
|
||||||
fun build(consumer: TagConsumer<HTMLElement>, id: String) {
|
|
||||||
consumer.accordion(id, map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun TagConsumer<HTMLElement>.accordion(id: String, block: AccordionBuilder.() -> Unit) {
|
|
||||||
AccordionBuilder().apply(block).build(this, id)
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
package hep.dataforge.vis.js.editor
|
|
||||||
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.names.plus
|
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.isEmpty
|
|
||||||
import kotlinx.html.TagConsumer
|
|
||||||
import kotlinx.html.dom.append
|
|
||||||
import kotlinx.html.js.*
|
|
||||||
import org.w3c.dom.Element
|
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
import org.w3c.dom.HTMLSpanElement
|
|
||||||
import kotlin.dom.clear
|
|
||||||
|
|
||||||
fun Element.displayObjectTree(
|
|
||||||
obj: VisualObject,
|
|
||||||
clickCallback: (Name) -> Unit = {}
|
|
||||||
) {
|
|
||||||
clear()
|
|
||||||
append {
|
|
||||||
card("Object tree") {
|
|
||||||
subTree(Name.EMPTY, obj, clickCallback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun TagConsumer<HTMLElement>.subTree(
|
|
||||||
name: Name,
|
|
||||||
obj: VisualObject,
|
|
||||||
clickCallback: (Name) -> Unit
|
|
||||||
) {
|
|
||||||
val token = name.last()?.toString()?:"World"
|
|
||||||
|
|
||||||
//display as node if any child is visible
|
|
||||||
if (obj is VisualGroup && obj.children.keys.any { !it.body.startsWith("@") }) {
|
|
||||||
lateinit var toggle: HTMLSpanElement
|
|
||||||
div("d-inline-block text-truncate") {
|
|
||||||
toggle = span("objTree-caret")
|
|
||||||
label("objTree-label") {
|
|
||||||
+token
|
|
||||||
onClickFunction = { clickCallback(name) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val subtree = ul("objTree-subtree")
|
|
||||||
toggle.onclick = {
|
|
||||||
toggle.classList.toggle("objTree-caret-down")
|
|
||||||
subtree.apply {
|
|
||||||
//If expanded, add children dynamically
|
|
||||||
if (toggle.classList.contains("objTree-caret-down")) {
|
|
||||||
obj.children.entries
|
|
||||||
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
|
|
||||||
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
|
|
||||||
.forEach { (childToken, child) ->
|
|
||||||
append {
|
|
||||||
li().apply {
|
|
||||||
subTree(name + childToken, child, clickCallback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if not, clear them to conserve memory on very long lists
|
|
||||||
this.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
div("d-inline-block text-truncate") {
|
|
||||||
span("objTree-leaf")
|
|
||||||
label("objTree-label") {
|
|
||||||
+token
|
|
||||||
onClickFunction = { clickCallback(name) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
|||||||
@file:Suppress(
|
|
||||||
"INTERFACE_WITH_SUPERCLASS",
|
|
||||||
"OVERRIDING_FINAL_MEMBER",
|
|
||||||
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
|
|
||||||
"CONFLICTING_OVERLOADS",
|
|
||||||
"EXTERNAL_DELEGATION"
|
|
||||||
)
|
|
||||||
|
|
||||||
package hep.dataforge.vis.js.editor
|
|
||||||
|
|
||||||
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<String>
|
|
||||||
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<String>
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface AutoCompleteOptions {
|
|
||||||
var confirmKeys: Array<Number>? 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<Number>
|
|
||||||
var hsla: Array<Number>
|
|
||||||
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<dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */>? 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<Template>? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var autocomplete: AutoCompleteOptions? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var mainMenuBar: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var navigationBar: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var statusBar: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onTextSelectionChange: ((start: SelectionPosition, end: SelectionPosition, text: String) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onSelectionChange: ((start: SerializableNode, end: SerializableNode) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onEvent: ((node: Node, event: String) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var colorPicker: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var onColorPicker: ((parent: HTMLElement, color: String, onChange: (color: Color) -> Unit) -> Unit)? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var timestampTag: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var language: String? get() = definedExternally; set(value) = definedExternally
|
|
||||||
//var languages: Languages? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var modalAnchor: HTMLElement? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var enableSort: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var enableTransform: Boolean? get() = definedExternally; set(value) = definedExternally
|
|
||||||
var maxVisibleChilds: Number? get() = definedExternally; set(value) = definedExternally
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface JsonPath {
|
|
||||||
var path: dynamic
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface EditorSelection {
|
|
||||||
var start: SerializableNode
|
|
||||||
var end: SerializableNode
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface TextSelection {
|
|
||||||
var start: SelectionPosition
|
|
||||||
var end: SelectionPosition
|
|
||||||
var text: String
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsModule("jsoneditor")
|
|
||||||
@JsNonModule
|
|
||||||
external open class JSONEditor(
|
|
||||||
container: HTMLElement,
|
|
||||||
options: JSONEditorOptions? = definedExternally /* null */,
|
|
||||||
json: dynamic = definedExternally /* null */
|
|
||||||
) {
|
|
||||||
open fun collapseAll()
|
|
||||||
open fun destroy()
|
|
||||||
open fun expandAll()
|
|
||||||
open fun focus()
|
|
||||||
open fun get(): Any
|
|
||||||
open fun getMode(): dynamic /* 'tree' | 'view' | 'form' | 'code' | 'text' */
|
|
||||||
open fun getName(): String?
|
|
||||||
open fun getNodesByRange(start: JsonPath, end: JsonPath): Array<SerializableNode>
|
|
||||||
open fun getSelection(): EditorSelection
|
|
||||||
open fun getText(): String
|
|
||||||
open fun getTextSelection(): TextSelection
|
|
||||||
open fun refresh()
|
|
||||||
open fun set(json: Any)
|
|
||||||
open fun setMode(mode: String /* 'tree' */)
|
|
||||||
open fun setMode(mode: String /* 'view' */)
|
|
||||||
open fun setMode(mode: String /* 'form' */)
|
|
||||||
open fun setMode(mode: String /* 'code' */)
|
|
||||||
open fun setMode(mode: String /* 'text' */)
|
|
||||||
open fun setName(name: String? = definedExternally /* null */)
|
|
||||||
open fun setSchema(schema: Any?, schemaRefs: Any? = definedExternally /* null */)
|
|
||||||
open fun setSelection(start: JsonPath, end: JsonPath)
|
|
||||||
open fun setText(jsonString: String)
|
|
||||||
open fun setTextSelection(start: SelectionPosition, end: SelectionPosition)
|
|
||||||
open fun update(json: Any)
|
|
||||||
open fun updateText(jsonString: String)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var VALID_OPTIONS: Array<String>
|
|
||||||
// var ace: AceAjax.Ace
|
|
||||||
// var Ajv: Ajv
|
|
||||||
var VanillaPicker: Any
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
package hep.dataforge.vis.js.editor
|
|
||||||
|
|
||||||
import hep.dataforge.io.toJson
|
|
||||||
import hep.dataforge.js.jsObject
|
|
||||||
import hep.dataforge.meta.DynamicMeta
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.update
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.names.isEmpty
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.findStyle
|
|
||||||
import kotlinx.html.dom.append
|
|
||||||
import kotlinx.html.js.*
|
|
||||||
import org.w3c.dom.Element
|
|
||||||
import kotlin.collections.forEach
|
|
||||||
import kotlin.collections.isNotEmpty
|
|
||||||
import kotlin.collections.set
|
|
||||||
import kotlin.dom.clear
|
|
||||||
|
|
||||||
//FIXME something rotten in JS-Meta converter
|
|
||||||
fun Meta.toDynamic() = JSON.parse<dynamic>(toJson().toString())
|
|
||||||
|
|
||||||
//TODO add node descriptor instead of configuring property selector
|
|
||||||
fun Element.displayPropertyEditor(
|
|
||||||
name: Name,
|
|
||||||
item: VisualObject,
|
|
||||||
propertySelector: (VisualObject) -> Meta = { it.config }
|
|
||||||
) {
|
|
||||||
clear()
|
|
||||||
|
|
||||||
append {
|
|
||||||
card("Properties") {
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
nav {
|
|
||||||
attributes["aria-label"] = "breadcrumb"
|
|
||||||
ol("breadcrumb") {
|
|
||||||
name.tokens.forEach { token ->
|
|
||||||
li("breadcrumb-item") {
|
|
||||||
+token.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val dMeta: dynamic = propertySelector(item).toDynamic()
|
|
||||||
val options: JSONEditorOptions = jsObject {
|
|
||||||
mode = "form"
|
|
||||||
onChangeJSON = { item.config.update(DynamicMeta(it.asDynamic())) }
|
|
||||||
}
|
|
||||||
JSONEditor(div(), options, dMeta)
|
|
||||||
}
|
|
||||||
|
|
||||||
val styles = item.styles
|
|
||||||
if (styles.isNotEmpty()) {
|
|
||||||
card("Styles") {
|
|
||||||
item.styles.forEach { style ->
|
|
||||||
val styleMeta = item.findStyle(style)
|
|
||||||
h4("container") { +style }
|
|
||||||
if (styleMeta != null) {
|
|
||||||
div("container").apply {
|
|
||||||
val options: JSONEditorOptions = jsObject {
|
|
||||||
mode = "view"
|
|
||||||
}
|
|
||||||
JSONEditor(
|
|
||||||
this,
|
|
||||||
options,
|
|
||||||
styleMeta.toDynamic()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
7
dataforge-vis-common/src/jsMain/resources/css/bootstrap.min.css
vendored
Normal file
7
dataforge-vis-common/src/jsMain/resources/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,48 +1,48 @@
|
|||||||
.loader {
|
|
||||||
border: 16px solid #f3f3f3; /* Light grey */
|
|
||||||
border-top: 16px solid #3498db; /* Blue */
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove default bullets */
|
/* Remove default bullets */
|
||||||
ul, .objTree-subtree {
|
ul, .tree {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Style the caret/arrow */
|
/* Style the caret/arrow */
|
||||||
.objTree-caret {
|
.tree-caret {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none; /* Prevent text selection */
|
user-select: none; /* Prevent text selection */
|
||||||
}
|
}
|
||||||
|
|
||||||
.objTree-label {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the caret/arrow with a unicode, and style it */
|
/* Create the caret/arrow with a unicode, and style it */
|
||||||
.objTree-caret::before {
|
.tree-caret::before {
|
||||||
content: "\25B6";
|
content: "\25B6";
|
||||||
color: black;
|
color: black;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.objTree-leaf::before {
|
.tree-leaf{
|
||||||
|
user-select: none;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-leaf::before {
|
||||||
content: "\25C6";
|
content: "\25C6";
|
||||||
color: black;
|
color: black;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
|
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
|
||||||
.objTree-caret-down::before {
|
.tree-caret-down::before {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tree-label-inactive {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-label-selected{
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding{
|
||||||
|
padding: 0;
|
||||||
|
}
|
7
dataforge-vis-common/src/jsMain/resources/js/bootstrap.bundle.min.js
vendored
Normal file
7
dataforge-vis-common/src/jsMain/resources/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
dataforge-vis-common/src/jsMain/resources/js/jquery-3.4.1.min.js
vendored
Normal file
2
dataforge-vis-common/src/jsMain/resources/js/jquery-3.4.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,7 +1,6 @@
|
|||||||
package hep.dataforge.vis.fx
|
package hep.dataforge.vis
|
||||||
|
|
||||||
import hep.dataforge.context.*
|
import hep.dataforge.context.*
|
||||||
import hep.dataforge.meta.EmptyMeta
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.boolean
|
import hep.dataforge.meta.boolean
|
||||||
import javafx.application.Application
|
import javafx.application.Application
|
||||||
@ -20,7 +19,7 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* Plugin holding JavaFX application instance and its root stage
|
* Plugin holding JavaFX application instance and its root stage
|
||||||
*/
|
*/
|
||||||
class FXPlugin(meta: Meta = EmptyMeta) : AbstractPlugin(meta) {
|
class FXPlugin(meta: Meta = Meta.EMPTY) : AbstractPlugin(meta) {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
private val stages: ObservableSet<Stage> = FXCollections.observableSet()
|
private val stages: ObservableSet<Stage> = FXCollections.observableSet()
|
||||||
@ -96,7 +95,8 @@ class FXPlugin(meta: Meta = EmptyMeta) : AbstractPlugin(meta) {
|
|||||||
companion object : PluginFactory<FXPlugin> {
|
companion object : PluginFactory<FXPlugin> {
|
||||||
override val type: KClass<out FXPlugin> = FXPlugin::class
|
override val type: KClass<out FXPlugin> = FXPlugin::class
|
||||||
override val tag: PluginTag = PluginTag("vis.fx", group = PluginTag.DATAFORGE_GROUP)
|
override val tag: PluginTag = PluginTag("vis.fx", group = PluginTag.DATAFORGE_GROUP)
|
||||||
override fun invoke(meta: Meta, context: Context): FXPlugin = FXPlugin(meta)
|
override fun invoke(meta: Meta, context: Context): FXPlugin =
|
||||||
|
FXPlugin(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
@ -3,7 +3,7 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
@ -3,15 +3,15 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
|
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
|
||||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
|
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.descriptors.NodeDescriptor
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.vis.fx.dfIconView
|
import hep.dataforge.vis.dfIconView
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import javafx.scene.control.*
|
import javafx.scene.control.*
|
||||||
import javafx.scene.control.cell.TextFieldTreeTableCell
|
import javafx.scene.control.cell.TextFieldTreeTableCell
|
||||||
@ -128,7 +128,11 @@ class ConfigEditor(
|
|||||||
when (item) {
|
when (item) {
|
||||||
is FXMetaValue<Config> -> {
|
is FXMetaValue<Config> -> {
|
||||||
text = null
|
text = null
|
||||||
val chooser = ValueChooser.build(Global, item.valueProperty, item.descriptor) {
|
val chooser = ValueChooser.build(
|
||||||
|
Global,
|
||||||
|
item.valueProperty,
|
||||||
|
item.descriptor
|
||||||
|
) {
|
||||||
item.set(it)
|
item.set(it)
|
||||||
}
|
}
|
||||||
graphic = chooser.node
|
graphic = chooser.node
|
@ -1,9 +1,9 @@
|
|||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.descriptors.ItemDescriptor
|
|
||||||
import hep.dataforge.descriptors.NodeDescriptor
|
|
||||||
import hep.dataforge.descriptors.ValueDescriptor
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.meta.descriptors.ItemDescriptor
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
@ -174,10 +174,10 @@ private fun <M : MutableMeta<M>> M.createEmptyNode(token: NameToken, append: Boo
|
|||||||
val name = token.asName()
|
val name = token.asName()
|
||||||
val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1
|
val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1
|
||||||
val newName = name.withIndex(index.toString())
|
val newName = name.withIndex(index.toString())
|
||||||
set(newName, EmptyMeta)
|
set(newName, Meta.EMPTY)
|
||||||
get(newName).node!!
|
get(newName).node!!
|
||||||
} else {
|
} else {
|
||||||
this.setNode(token.asName(), EmptyMeta)
|
this.setNode(token.asName(), Meta.EMPTY)
|
||||||
//FIXME possible concurrency bug
|
//FIXME possible concurrency bug
|
||||||
get(token).node!!
|
get(token).node!!
|
||||||
}
|
}
|
||||||
@ -211,9 +211,9 @@ fun <M : MutableMeta<M>> FXMetaNode<M>.addValue(key: String) {
|
|||||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addNode(key: String) {
|
fun <M : MutableMeta<M>> FXMetaNode<M>.addNode(key: String) {
|
||||||
val parent = getOrCreateNode()
|
val parent = getOrCreateNode()
|
||||||
if (descriptor?.multiple == true) {
|
if (descriptor?.multiple == true) {
|
||||||
parent.append(key, EmptyMeta)
|
parent.append(key, Meta.EMPTY)
|
||||||
} else {
|
} else {
|
||||||
parent[key] = EmptyMeta
|
parent[key] = Meta.EMPTY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,18 +14,23 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.vis.fx.dfIconView
|
import hep.dataforge.vis.dfIconView
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
||||||
import javafx.scene.control.TreeSortMode
|
import javafx.scene.control.TreeSortMode
|
||||||
import javafx.scene.control.TreeTableView
|
import javafx.scene.control.TreeTableView
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class MetaViewer(val rootNode: FXMetaNode<*>, title: String = "Meta viewer") : Fragment(title, dfIconView) {
|
class MetaViewer(val rootNode: FXMetaNode<*>, title: String = "Meta viewer") : Fragment(title,
|
||||||
constructor(meta: Meta, title: String = "Meta viewer"): this(FXMeta.root(meta),title = title)
|
dfIconView
|
||||||
|
) {
|
||||||
|
constructor(meta: Meta, title: String = "Meta viewer"): this(
|
||||||
|
FXMeta.root(
|
||||||
|
meta
|
||||||
|
),title = title)
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
center {
|
center {
|
@ -3,7 +3,7 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
@ -3,7 +3,7 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
|
|
@ -3,20 +3,19 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.context.Named
|
import hep.dataforge.context.Named
|
||||||
import hep.dataforge.descriptors.ValueDescriptor
|
|
||||||
import hep.dataforge.meta.EmptyMeta
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.provider.provideByType
|
import hep.dataforge.provider.provideByType
|
||||||
import hep.dataforge.values.Null
|
import hep.dataforge.values.Null
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import hep.dataforge.vis.common.widget
|
import hep.dataforge.vis.widget
|
||||||
import hep.dataforge.vis.common.widgetType
|
import hep.dataforge.vis.widgetType
|
||||||
import javafx.beans.property.ObjectProperty
|
import javafx.beans.property.ObjectProperty
|
||||||
import javafx.beans.value.ObservableValue
|
import javafx.beans.value.ObservableValue
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
@ -66,7 +65,7 @@ interface ValueChooser {
|
|||||||
|
|
||||||
@Type("hep.dataforge.vis.fx.valueChooserFactory")
|
@Type("hep.dataforge.vis.fx.valueChooserFactory")
|
||||||
interface Factory : Named {
|
interface Factory : Named {
|
||||||
operator fun invoke(meta: Meta = EmptyMeta): ValueChooser
|
operator fun invoke(meta: Meta = Meta.EMPTY): ValueChooser
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -108,8 +107,7 @@ interface ValueChooser {
|
|||||||
descriptor: ValueDescriptor? = null,
|
descriptor: ValueDescriptor? = null,
|
||||||
setter: (Value) -> Unit
|
setter: (Value) -> Unit
|
||||||
): ValueChooser {
|
): ValueChooser {
|
||||||
val chooser =
|
val chooser = build(context, descriptor)
|
||||||
build(context, descriptor)
|
|
||||||
chooser.setDisplayValue(value.value ?: Null)
|
chooser.setDisplayValue(value.value ?: Null)
|
||||||
value.onChange {
|
value.onChange {
|
||||||
chooser.setDisplayValue(it ?: Null)
|
chooser.setDisplayValue(it ?: Null)
|
@ -3,9 +3,9 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.descriptors.ValueDescriptor
|
import hep.dataforge.meta.descriptors.ValueDescriptor
|
||||||
import hep.dataforge.values.Null
|
import hep.dataforge.values.Null
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
@ -1,11 +1,11 @@
|
|||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.descriptors.NodeDescriptor
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.common.findStyle
|
import hep.dataforge.vis.findStyle
|
||||||
import javafx.beans.binding.Binding
|
import javafx.beans.binding.Binding
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
@ -1,7 +1,7 @@
|
|||||||
package hep.dataforge.vis.fx.editor
|
package hep.dataforge.vis.editor
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.VisualGroup
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.scene.control.SelectionMode
|
import javafx.scene.control.SelectionMode
|
||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
@ -1,12 +1,12 @@
|
|||||||
package hep.dataforge.vis.fx.demo
|
package hep.dataforge.vis.demo
|
||||||
|
|
||||||
import hep.dataforge.descriptors.NodeDescriptor
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.buildMeta
|
import hep.dataforge.meta.asConfig
|
||||||
import hep.dataforge.meta.toConfig
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.fx.editor.ConfigEditor
|
import hep.dataforge.vis.editor.ConfigEditor
|
||||||
import hep.dataforge.vis.fx.editor.FXMeta
|
import hep.dataforge.vis.editor.FXMeta
|
||||||
import hep.dataforge.vis.fx.editor.MetaViewer
|
import hep.dataforge.vis.editor.MetaViewer
|
||||||
import javafx.geometry.Orientation
|
import javafx.geometry.Orientation
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ class MetaEditorDemoApp : App(MetaEditorDemo::class)
|
|||||||
|
|
||||||
class MetaEditorDemo : View("Meta editor demo") {
|
class MetaEditorDemo : View("Meta editor demo") {
|
||||||
|
|
||||||
val meta = buildMeta {
|
val meta = Meta {
|
||||||
"aNode" put {
|
"aNode" put {
|
||||||
"innerNode" put {
|
"innerNode" put {
|
||||||
"innerValue" put true
|
"innerValue" put true
|
||||||
@ -23,33 +23,35 @@ class MetaEditorDemo : View("Meta editor demo") {
|
|||||||
"b" put 223
|
"b" put 223
|
||||||
"c" put "StringValue"
|
"c" put "StringValue"
|
||||||
}
|
}
|
||||||
}.toConfig()
|
}.asConfig()
|
||||||
|
|
||||||
val descriptor = NodeDescriptor {
|
val descriptor = NodeDescriptor {
|
||||||
node("aNode") {
|
defineNode("aNode") {
|
||||||
info = "A root demo node"
|
info = "A root demo node"
|
||||||
value("b") {
|
defineValue("b") {
|
||||||
info = "b number value"
|
info = "b number value"
|
||||||
type(ValueType.NUMBER)
|
type(ValueType.NUMBER)
|
||||||
}
|
}
|
||||||
node("otherNode") {
|
defineNode("otherNode") {
|
||||||
value("otherValue") {
|
defineValue("otherValue") {
|
||||||
type(ValueType.BOOLEAN)
|
type(ValueType.BOOLEAN)
|
||||||
default(false)
|
default(false)
|
||||||
info = "default value"
|
info = "default value"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value("multiple"){
|
defineValue("multiple") {
|
||||||
info = "A sns value"
|
info = "A sns value"
|
||||||
multiple = true
|
multiple = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val rootNode = FXMeta.root(meta,descriptor)
|
private val rootNode = FXMeta.root(meta, descriptor)
|
||||||
|
|
||||||
override val root =
|
override val root =
|
||||||
splitpane(Orientation.HORIZONTAL, MetaViewer(rootNode).root, ConfigEditor(rootNode).root)
|
splitpane(Orientation.HORIZONTAL, MetaViewer(rootNode).root, ConfigEditor(
|
||||||
|
rootNode
|
||||||
|
).root)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
@ -7,7 +7,7 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-vis-spatial"))
|
api(project(":dataforge-vis-spatial"))
|
||||||
api("scientifik:gdml:0.1.6")
|
api("scientifik:gdml:0.1.7")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ package hep.dataforge.vis.spatial.gdml
|
|||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaBuilder
|
import hep.dataforge.meta.MetaBuilder
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vis.common.useStyle
|
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||||
|
import hep.dataforge.vis.useStyle
|
||||||
import scientifik.gdml.*
|
import scientifik.gdml.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
|
|
||||||
fun VisualObject3D.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
|
fun VisualObject3D.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
|
||||||
styleCache.getOrPut(name.toName()) {
|
styleCache.getOrPut(name.toName()) {
|
||||||
buildMeta(builder)
|
Meta(builder)
|
||||||
}
|
}
|
||||||
useStyle(name)
|
useStyle(name)
|
||||||
}
|
}
|
||||||
@ -69,7 +69,13 @@ class GDMLTransformer(val root: GDML) {
|
|||||||
var onFinish: GDMLTransformer.() -> Unit = {}
|
var onFinish: GDMLTransformer.() -> Unit = {}
|
||||||
|
|
||||||
internal fun finalize(final: VisualGroup3D): VisualGroup3D {
|
internal fun finalize(final: VisualGroup3D): VisualGroup3D {
|
||||||
final.prototypes = proto
|
//final.prototypes = proto
|
||||||
|
final.prototypes {
|
||||||
|
proto.children.forEach { (token, item) ->
|
||||||
|
item.parent = null
|
||||||
|
set(token.asName(), item)
|
||||||
|
}
|
||||||
|
}
|
||||||
styleCache.forEach {
|
styleCache.forEach {
|
||||||
final.styleSheet {
|
final.styleSheet {
|
||||||
define(it.key.toString(), it.value)
|
define(it.key.toString(), it.value)
|
||||||
|
@ -4,8 +4,8 @@ package hep.dataforge.vis.spatial.gdml
|
|||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.vis.common.get
|
import hep.dataforge.vis.get
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.set
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.World.ONE
|
import hep.dataforge.vis.spatial.World.ONE
|
||||||
import hep.dataforge.vis.spatial.World.ZERO
|
import hep.dataforge.vis.spatial.World.ZERO
|
||||||
|
@ -1,43 +1,39 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml
|
package hep.dataforge.vis.spatial.gdml
|
||||||
|
|
||||||
|
import hep.dataforge.vis.spatial.stringify
|
||||||
import nl.adaptivity.xmlutil.StAXReader
|
import nl.adaptivity.xmlutil.StAXReader
|
||||||
import org.junit.Test
|
import org.junit.jupiter.api.Test
|
||||||
import scientifik.gdml.GDML
|
import scientifik.gdml.GDML
|
||||||
import java.io.File
|
|
||||||
import java.net.URL
|
|
||||||
import kotlin.test.Ignore
|
|
||||||
|
|
||||||
class TestConvertor {
|
class TestConvertor {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
fun testBMNGeometry() {
|
fun testBMNGeometry() {
|
||||||
val url = URL("https://drive.google.com/open?id=1w5e7fILMN83JGgB8WANJUYm8OW2s0WVO")
|
val stream = javaClass.getResourceAsStream("/gdml/BM@N.gdml")
|
||||||
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\BM@N.gdml")
|
|
||||||
val stream = if (file.exists()) {
|
|
||||||
file.inputStream()
|
|
||||||
} else {
|
|
||||||
url.openStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
val xmlReader = StAXReader(stream, "UTF-8")
|
|
||||||
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
|
||||||
xml.toVisual()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
fun testCubes() {
|
|
||||||
val file = File("D:\\Work\\Projects\\gdml.kt\\gdml-source\\cubes.gdml ")
|
|
||||||
val stream = if (file.exists()) {
|
|
||||||
file.inputStream()
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val xmlReader = StAXReader(stream, "UTF-8")
|
val xmlReader = StAXReader(stream, "UTF-8")
|
||||||
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
val visual = xml.toVisual()
|
val visual = xml.toVisual()
|
||||||
println(visual)
|
println(visual.stringify())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCubes() {
|
||||||
|
val stream = javaClass.getResourceAsStream("/gdml/cubes.gdml")
|
||||||
|
|
||||||
|
val xmlReader = StAXReader(stream, "UTF-8")
|
||||||
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
|
val visual = xml.toVisual()
|
||||||
|
// println(visual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSimple() {
|
||||||
|
val stream = javaClass.getResourceAsStream("/gdml/simple1.gdml")
|
||||||
|
|
||||||
|
val xmlReader = StAXReader(stream, "UTF-8")
|
||||||
|
val xml = GDML.format.parse(GDML.serializer(), xmlReader)
|
||||||
|
val visual = xml.toVisual()
|
||||||
|
println(visual.stringify())
|
||||||
}
|
}
|
||||||
}
|
}
|
5601
dataforge-vis-spatial-gdml/src/jvmTest/resources/gdml/BM@N.gdml
Normal file
5601
dataforge-vis-spatial-gdml/src/jvmTest/resources/gdml/BM@N.gdml
Normal file
File diff suppressed because it is too large
Load Diff
254
dataforge-vis-spatial-gdml/src/jvmTest/resources/gdml/cubes.gdml
Normal file
254
dataforge-vis-spatial-gdml/src/jvmTest/resources/gdml/cubes.gdml
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
<gdml>
|
||||||
|
<define>
|
||||||
|
<position name="center" x="0.0" y="0.0" z="0.0" unit="cm"/>
|
||||||
|
<position name="box_position" x="25.0" y="50.0" z="75.0" unit="cm"/>
|
||||||
|
<rotation name="Rot0" x="0.0" y="0.0" z="0.0" unit="deg"/>
|
||||||
|
<rotation name="Rot1" x="0.0" y="0.0" z="60.0" unit="deg"/>
|
||||||
|
<rotation name="Rot2" x="0.0" y="0.0" z="120.0" unit="deg"/>
|
||||||
|
<rotation name="Rot3" x="0.0" y="0.0" z="180.0" unit="deg"/>
|
||||||
|
<rotation name="Rot4" x="0.0" y="0.0" z="240.0" unit="deg"/>
|
||||||
|
<rotation name="Rot5" x="0.0" y="0.0" z="300.0" unit="deg"/>
|
||||||
|
<rotation name="Rot000" x="0.0" y="0.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos000" x="-50.0" y="-50.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot001" x="0.0" y="0.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos001" x="-50.0" y="-50.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot002" x="0.0" y="0.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos002" x="-50.0" y="-50.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot010" x="0.0" y="120.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos010" x="-50.0" y="0.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot011" x="0.0" y="120.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos011" x="-50.0" y="0.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot012" x="0.0" y="120.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos012" x="-50.0" y="0.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot020" x="0.0" y="240.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos020" x="-50.0" y="50.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot021" x="0.0" y="240.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos021" x="-50.0" y="50.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot022" x="0.0" y="240.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos022" x="-50.0" y="50.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot100" x="120.0" y="0.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos100" x="0.0" y="-50.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot101" x="120.0" y="0.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos101" x="0.0" y="-50.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot102" x="120.0" y="0.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos102" x="0.0" y="-50.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot110" x="120.0" y="120.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos110" x="0.0" y="0.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot111" x="120.0" y="120.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos111" x="0.0" y="0.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot112" x="120.0" y="120.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos112" x="0.0" y="0.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot120" x="120.0" y="240.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos120" x="0.0" y="50.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot121" x="120.0" y="240.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos121" x="0.0" y="50.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot122" x="120.0" y="240.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos122" x="0.0" y="50.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot200" x="240.0" y="0.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos200" x="50.0" y="-50.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot201" x="240.0" y="0.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos201" x="50.0" y="-50.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot202" x="240.0" y="0.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos202" x="50.0" y="-50.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot210" x="240.0" y="120.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos210" x="50.0" y="0.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot211" x="240.0" y="120.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos211" x="50.0" y="0.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot212" x="240.0" y="120.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos212" x="50.0" y="0.0" z="50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot220" x="240.0" y="240.0" z="0.0" unit="deg"/>
|
||||||
|
<position name="Pos220" x="50.0" y="50.0" z="-50.0" unit="cm"/>
|
||||||
|
<rotation name="Rot221" x="240.0" y="240.0" z="120.0" unit="deg"/>
|
||||||
|
<position name="Pos221" x="50.0" y="50.0" z="0.0" unit="cm"/>
|
||||||
|
<rotation name="Rot222" x="240.0" y="240.0" z="240.0" unit="deg"/>
|
||||||
|
<position name="Pos222" x="50.0" y="50.0" z="50.0" unit="cm"/>
|
||||||
|
</define>
|
||||||
|
<materials/>
|
||||||
|
<solids>
|
||||||
|
<tube aunit="degree" name="segment" rmax="20.0" z="5.0" rmin="17.0" startphi="0.0" deltaphi="60.0"/>
|
||||||
|
<box name="cave" x="200.0" y="200.0" z="200.0"/>
|
||||||
|
<box name="box" x="30.0" y="30.0" z="30.0"/>
|
||||||
|
</solids>
|
||||||
|
<structure>
|
||||||
|
<volume name="segment_vol">
|
||||||
|
<materialref ref="G4_WATER"/>
|
||||||
|
<solidref ref="segment"/>
|
||||||
|
</volume>
|
||||||
|
<volume name="composite">
|
||||||
|
<physvol name="segment_0">
|
||||||
|
<volumeref ref="segment_vol"/>
|
||||||
|
<positionref ref="center"/>
|
||||||
|
<rotationref ref="Rot0"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="segment_1">
|
||||||
|
<volumeref ref="segment_vol"/>
|
||||||
|
<positionref ref="center"/>
|
||||||
|
<rotationref ref="Rot1"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="segment_2">
|
||||||
|
<volumeref ref="segment_vol"/>
|
||||||
|
<positionref ref="center"/>
|
||||||
|
<rotationref ref="Rot2"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="segment_3">
|
||||||
|
<volumeref ref="segment_vol"/>
|
||||||
|
<positionref ref="center"/>
|
||||||
|
<rotationref ref="Rot3"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="segment_4">
|
||||||
|
<volumeref ref="segment_vol"/>
|
||||||
|
<positionref ref="center"/>
|
||||||
|
<rotationref ref="Rot4"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="segment_5">
|
||||||
|
<volumeref ref="segment_vol"/>
|
||||||
|
<positionref ref="center"/>
|
||||||
|
<rotationref ref="Rot5"/>
|
||||||
|
</physvol>
|
||||||
|
<materialref ref="G4_AIR"/>
|
||||||
|
<solidref ref="box"/>
|
||||||
|
</volume>
|
||||||
|
<volume name="world">
|
||||||
|
<physvol name="composite_000">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos000"/>
|
||||||
|
<rotationref ref="Rot000"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="composite_001">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos001"/>
|
||||||
|
<rotationref ref="Rot001"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="composite_002">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos002"/>
|
||||||
|
<rotationref ref="Rot002"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="composite_003">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos010"/>
|
||||||
|
<rotationref ref="Rot010"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="composite_004">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos011"/>
|
||||||
|
<rotationref ref="Rot011"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="composite_005">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos012"/>
|
||||||
|
<rotationref ref="Rot012"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol name="composite_006">
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos020"/>
|
||||||
|
<rotationref ref="Rot020"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos021"/>
|
||||||
|
<rotationref ref="Rot021"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos022"/>
|
||||||
|
<rotationref ref="Rot022"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos100"/>
|
||||||
|
<rotationref ref="Rot100"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos101"/>
|
||||||
|
<rotationref ref="Rot101"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos102"/>
|
||||||
|
<rotationref ref="Rot102"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos110"/>
|
||||||
|
<rotationref ref="Rot110"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos111"/>
|
||||||
|
<rotationref ref="Rot111"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos112"/>
|
||||||
|
<rotationref ref="Rot112"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos120"/>
|
||||||
|
<rotationref ref="Rot120"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos121"/>
|
||||||
|
<rotationref ref="Rot121"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos122"/>
|
||||||
|
<rotationref ref="Rot122"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos200"/>
|
||||||
|
<rotationref ref="Rot200"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos201"/>
|
||||||
|
<rotationref ref="Rot201"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos202"/>
|
||||||
|
<rotationref ref="Rot202"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos210"/>
|
||||||
|
<rotationref ref="Rot210"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos211"/>
|
||||||
|
<rotationref ref="Rot211"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos212"/>
|
||||||
|
<rotationref ref="Rot212"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos220"/>
|
||||||
|
<rotationref ref="Rot220"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos221"/>
|
||||||
|
<rotationref ref="Rot221"/>
|
||||||
|
</physvol>
|
||||||
|
<physvol>
|
||||||
|
<volumeref ref="composite"/>
|
||||||
|
<positionref ref="Pos222"/>
|
||||||
|
<rotationref ref="Rot222"/>
|
||||||
|
</physvol>
|
||||||
|
<materialref ref="G4_AIR"/>
|
||||||
|
<solidref ref="cave"/>
|
||||||
|
</volume>
|
||||||
|
</structure>
|
||||||
|
<setup name="Default" version="1.0">
|
||||||
|
<world ref="world"/>
|
||||||
|
</setup>
|
||||||
|
</gdml>
|
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd">
|
||||||
|
<define/>
|
||||||
|
<materials>
|
||||||
|
<material name="Vacuum" Z="1">
|
||||||
|
<D unit="g/cm3" value="0"/>
|
||||||
|
<atom unit="g/mole" value="0"/>
|
||||||
|
</material>
|
||||||
|
<material name="Al" Z="13">
|
||||||
|
<D unit="g/cm3" value="2.7000000000000002"/>
|
||||||
|
<atom unit="g/mole" value="26.98"/>
|
||||||
|
</material>
|
||||||
|
</materials>
|
||||||
|
<solids>
|
||||||
|
<box name="R" x="50" y="50" z="10" lunit="cm"/>
|
||||||
|
</solids>
|
||||||
|
<structure>
|
||||||
|
<volume name="R">
|
||||||
|
<materialref ref="Vacuum"/>
|
||||||
|
<solidref ref="R"/>
|
||||||
|
</volume>
|
||||||
|
</structure>
|
||||||
|
<setup name="default" version="1.0">
|
||||||
|
<world ref="R"/>
|
||||||
|
</setup>
|
||||||
|
</gdml>
|
@ -1,17 +1,16 @@
|
|||||||
import org.openjfx.gradle.JavaFXOptions
|
import scientifik.serialization
|
||||||
import scientifik.useSerialization
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("scientifik.mpp")
|
||||||
id("org.openjfx.javafxplugin")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useSerialization()
|
serialization()
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvm {
|
js {
|
||||||
withJava()
|
useCommonJs()
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -32,14 +31,9 @@ kotlin {
|
|||||||
jsMain {
|
jsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
// api(project(":wrappers"))
|
// api(project(":wrappers"))
|
||||||
implementation(npm("three", "0.106.2"))
|
implementation(npm("three", "0.114.0"))
|
||||||
implementation(npm("@hi-level/three-csg", "1.0.6"))
|
implementation(npm("three-csg-ts", "1.0.1"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<JavaFXOptions> {
|
|
||||||
modules("javafx.controls")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -2,15 +2,11 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.float
|
import hep.dataforge.meta.float
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.*
|
||||||
import hep.dataforge.vis.common.VisualFactory
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.set
|
|
||||||
import hep.dataforge.vis.spatial.Box.Companion.TYPE_NAME
|
import hep.dataforge.vis.spatial.Box.Companion.TYPE_NAME
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@ -29,7 +25,6 @@ class Box(
|
|||||||
override var rotation: Point3D? = null
|
override var rotation: Point3D? = null
|
||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
//TODO add helper for color configuration
|
//TODO add helper for color configuration
|
||||||
@ -69,7 +64,7 @@ class Box(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun VisualGroup3D.box(
|
inline fun MutableVisualGroup.box(
|
||||||
xSize: Number,
|
xSize: Number,
|
||||||
ySize: Number,
|
ySize: Number,
|
||||||
zSize: Number,
|
zSize: Number,
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.*
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -23,7 +22,7 @@ class Composite(
|
|||||||
val compositeType: CompositeType,
|
val compositeType: CompositeType,
|
||||||
val first: VisualObject3D,
|
val first: VisualObject3D,
|
||||||
val second: VisualObject3D
|
val second: VisualObject3D
|
||||||
) : AbstractVisualObject(), VisualObject3D {
|
) : AbstractVisualObject(), VisualObject3D, VisualGroup {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
first.parent = this
|
first.parent = this
|
||||||
@ -34,11 +33,16 @@ class Composite(
|
|||||||
override var rotation: Point3D? = null
|
override var rotation: Point3D? = null
|
||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
|
override val children: Map<NameToken, VisualObject>
|
||||||
|
get() = mapOf(NameToken("first") to first, NameToken("second") to second)
|
||||||
|
|
||||||
|
override val styleSheet: StyleSheet?
|
||||||
|
get() = null
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun VisualGroup3D.composite(
|
inline fun MutableVisualGroup.composite(
|
||||||
type: CompositeType,
|
type: CompositeType,
|
||||||
name: String = "",
|
name: String = "",
|
||||||
builder: VisualGroup3D.() -> Unit
|
builder: VisualGroup3D.() -> Unit
|
||||||
@ -50,24 +54,24 @@ inline fun VisualGroup3D.composite(
|
|||||||
it.config.update(group.config)
|
it.config.update(group.config)
|
||||||
//it.material = group.material
|
//it.material = group.material
|
||||||
|
|
||||||
if(group.position!=null) {
|
if (group.position != null) {
|
||||||
it.position = group.position
|
it.position = group.position
|
||||||
}
|
}
|
||||||
if(group.rotation!=null) {
|
if (group.rotation != null) {
|
||||||
it.rotation = group.rotation
|
it.rotation = group.rotation
|
||||||
}
|
}
|
||||||
if(group.scale!=null) {
|
if (group.scale != null) {
|
||||||
it.scale = group.scale
|
it.scale = group.scale
|
||||||
}
|
}
|
||||||
set(name, it)
|
set(name, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.union(name: String = "", builder: VisualGroup3D.() -> Unit) =
|
inline fun MutableVisualGroup.union(name: String = "", builder: VisualGroup3D.() -> Unit) =
|
||||||
composite(CompositeType.UNION, name, builder = builder)
|
composite(CompositeType.UNION, name, builder = builder)
|
||||||
|
|
||||||
fun VisualGroup3D.subtract(name: String = "", builder: VisualGroup3D.() -> Unit) =
|
inline fun MutableVisualGroup.subtract(name: String = "", builder: VisualGroup3D.() -> Unit) =
|
||||||
composite(CompositeType.SUBTRACT, name, builder = builder)
|
composite(CompositeType.SUBTRACT, name, builder = builder)
|
||||||
|
|
||||||
fun VisualGroup3D.intersect(name: String = "", builder: VisualGroup3D.() -> Unit) =
|
inline fun MutableVisualGroup.intersect(name: String = "", builder: VisualGroup3D.() -> Unit) =
|
||||||
composite(CompositeType.INTERSECT, name, builder = builder)
|
composite(CompositeType.INTERSECT, name, builder = builder)
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -25,7 +25,6 @@ class ConeSegment(
|
|||||||
var angle: Float = PI2
|
var angle: Float = PI2
|
||||||
) : AbstractVisualObject(), VisualObject3D, Shape {
|
) : AbstractVisualObject(), VisualObject3D, Shape {
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
@ -76,7 +75,7 @@ class ConeSegment(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun VisualGroup3D.cylinder(
|
inline fun MutableVisualGroup.cylinder(
|
||||||
r: Number,
|
r: Number,
|
||||||
height: Number,
|
height: Number,
|
||||||
name: String = "",
|
name: String = "",
|
||||||
@ -88,7 +87,7 @@ inline fun VisualGroup3D.cylinder(
|
|||||||
).apply(block).also { set(name, it) }
|
).apply(block).also { set(name, it) }
|
||||||
|
|
||||||
|
|
||||||
inline fun VisualGroup3D.cone(
|
inline fun MutableVisualGroup.cone(
|
||||||
bottomRadius: Number,
|
bottomRadius: Number,
|
||||||
height: Number,
|
height: Number,
|
||||||
upperRadius: Number = 0.0,
|
upperRadius: Number = 0.0,
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -14,7 +14,6 @@ import kotlinx.serialization.UseSerializers
|
|||||||
@SerialName("3d.convex")
|
@SerialName("3d.convex")
|
||||||
class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
@ -26,7 +25,7 @@ class Convex(val points: List<Point3D>) : AbstractVisualObject(), VisualObject3D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun VisualGroup3D.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}) =
|
inline fun MutableVisualGroup.convex(name: String = "", action: ConvexBuilder.() -> Unit = {}) =
|
||||||
ConvexBuilder().apply(action).build().also { set(name, it) }
|
ConvexBuilder().apply(action).build().also { set(name, it) }
|
||||||
|
|
||||||
class ConvexBuilder {
|
class ConvexBuilder {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
@file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class)
|
@file:UseSerializers(Point2DSerializer::class, Point3DSerializer::class)
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -45,7 +45,6 @@ class Extruded(
|
|||||||
var layers: MutableList<Layer> = ArrayList()
|
var layers: MutableList<Layer> = ArrayList()
|
||||||
) : AbstractVisualObject(), VisualObject3D, Shape {
|
) : AbstractVisualObject(), VisualObject3D, Shape {
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
@ -113,5 +112,5 @@ class Extruded(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.extrude(name: String = "", action: Extruded.() -> Unit = {}) =
|
fun MutableVisualGroup.extrude(name: String = "", action: Extruded.() -> Unit = {}) =
|
||||||
Extruded().apply(action).also { set(name, it) }
|
Extruded().apply(action).also { set(name, it) }
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.EmptyMeta
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,7 +13,7 @@ interface GeometryBuilder<T : Any> {
|
|||||||
* @param normal optional external normal to the face
|
* @param normal optional external normal to the face
|
||||||
* @param meta optional additional platform-specific parameters like color or texture index
|
* @param meta optional additional platform-specific parameters like color or texture index
|
||||||
*/
|
*/
|
||||||
fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = EmptyMeta)
|
fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D? = null, meta: Meta = Meta.EMPTY)
|
||||||
|
|
||||||
fun build(): T
|
fun build(): T
|
||||||
}
|
}
|
||||||
@ -25,7 +24,7 @@ fun GeometryBuilder<*>.face4(
|
|||||||
vertex3: Point3D,
|
vertex3: Point3D,
|
||||||
vertex4: Point3D,
|
vertex4: Point3D,
|
||||||
normal: Point3D? = null,
|
normal: Point3D? = null,
|
||||||
meta: Meta = EmptyMeta
|
meta: Meta = Meta.EMPTY
|
||||||
) {
|
) {
|
||||||
face(vertex1, vertex2, vertex3, normal, meta)
|
face(vertex1, vertex2, vertex3, normal, meta)
|
||||||
face(vertex1, vertex3, vertex4, normal, meta)
|
face(vertex1, vertex3, vertex4, normal, meta)
|
||||||
|
@ -2,19 +2,17 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("3d.label")
|
@SerialName("3d.label")
|
||||||
class Label3D(var text: String, var fontSize: Double, var fontFamily: String) : AbstractVisualObject(),
|
class Label3D(var text: String, var fontSize: Double, var fontFamily: String) : AbstractVisualObject(), VisualObject3D {
|
||||||
VisualObject3D {
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
@ -23,7 +21,7 @@ class Label3D(var text: String, var fontSize: Double, var fontFamily: String) :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.label(
|
fun MutableVisualGroup.label(
|
||||||
text: String,
|
text: String,
|
||||||
fontSize: Number = 20,
|
fontSize: Number = 20,
|
||||||
fontFamily: String = "Arial",
|
fontFamily: String = "Arial",
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.descriptors.NodeDescriptor
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.values.asValue
|
||||||
|
import hep.dataforge.vis.Colors
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_COLOR_KEY
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_OPACITY_KEY
|
||||||
|
import hep.dataforge.vis.widgetType
|
||||||
|
|
||||||
class Material3D(override val config: Config) : Specific {
|
class Material3D : Scheme() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primary web-color for the material
|
* Primary web-color for the material
|
||||||
@ -32,8 +34,7 @@ class Material3D(override val config: Config) : Specific {
|
|||||||
*/
|
*/
|
||||||
var wireframe by boolean(false, WIREFRAME_KEY)
|
var wireframe by boolean(false, WIREFRAME_KEY)
|
||||||
|
|
||||||
companion object : Specification<Material3D> {
|
companion object : SchemeSpec<Material3D>(::Material3D) {
|
||||||
override fun wrap(config: Config): Material3D = Material3D(config)
|
|
||||||
|
|
||||||
val MATERIAL_KEY = "material".asName()
|
val MATERIAL_KEY = "material".asName()
|
||||||
internal val COLOR_KEY = "color".asName()
|
internal val COLOR_KEY = "color".asName()
|
||||||
@ -44,21 +45,26 @@ class Material3D(override val config: Config) : Specific {
|
|||||||
internal val WIREFRAME_KEY = "wireframe".asName()
|
internal val WIREFRAME_KEY = "wireframe".asName()
|
||||||
val MATERIAL_WIREFRAME_KEY = MATERIAL_KEY + WIREFRAME_KEY
|
val MATERIAL_WIREFRAME_KEY = MATERIAL_KEY + WIREFRAME_KEY
|
||||||
|
|
||||||
val descriptor = NodeDescriptor {
|
val descriptor by lazy {
|
||||||
value(VisualObject3D.VISIBLE_KEY) {
|
//must be lazy to avoid initialization bug
|
||||||
type(ValueType.BOOLEAN)
|
NodeDescriptor {
|
||||||
default(true)
|
defineValue(COLOR_KEY) {
|
||||||
}
|
|
||||||
node(MATERIAL_KEY) {
|
|
||||||
value(COLOR_KEY) {
|
|
||||||
type(ValueType.STRING, ValueType.NUMBER)
|
type(ValueType.STRING, ValueType.NUMBER)
|
||||||
default("#ffffff")
|
default("#ffffff")
|
||||||
|
widgetType = "color"
|
||||||
}
|
}
|
||||||
value(OPACITY_KEY) {
|
defineValue(OPACITY_KEY) {
|
||||||
type(ValueType.NUMBER)
|
type(ValueType.NUMBER)
|
||||||
default(1.0)
|
default(1.0)
|
||||||
|
configure {
|
||||||
|
"attributes" to {
|
||||||
|
this["min"] = 0.0
|
||||||
|
this["max"] = 1.0
|
||||||
|
this["step"] = 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
value(WIREFRAME_KEY) {
|
defineValue(WIREFRAME_KEY) {
|
||||||
type(ValueType.BOOLEAN)
|
type(ValueType.BOOLEAN)
|
||||||
default(false)
|
default(false)
|
||||||
}
|
}
|
||||||
@ -71,14 +77,14 @@ class Material3D(override val config: Config) : Specific {
|
|||||||
* Set color as web-color
|
* Set color as web-color
|
||||||
*/
|
*/
|
||||||
fun VisualObject3D.color(webColor: String) {
|
fun VisualObject3D.color(webColor: String) {
|
||||||
setProperty(MATERIAL_COLOR_KEY, webColor)
|
setProperty(MATERIAL_COLOR_KEY, webColor.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set color as integer
|
* Set color as integer
|
||||||
*/
|
*/
|
||||||
fun VisualObject3D.color(rgb: Int) {
|
fun VisualObject3D.color(rgb: Int) {
|
||||||
setProperty(MATERIAL_COLOR_KEY, rgb)
|
setProperty(MATERIAL_COLOR_KEY, rgb.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualObject3D.color(r: UByte, g: UByte, b: UByte) = setProperty(
|
fun VisualObject3D.color(r: UByte, g: UByte, b: UByte) = setProperty(
|
||||||
@ -92,7 +98,7 @@ fun VisualObject3D.color(r: UByte, g: UByte, b: UByte) = setProperty(
|
|||||||
var VisualObject3D.color: String?
|
var VisualObject3D.color: String?
|
||||||
get() = getProperty(MATERIAL_COLOR_KEY)?.let { Colors.fromMeta(it) }
|
get() = getProperty(MATERIAL_COLOR_KEY)?.let { Colors.fromMeta(it) }
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(MATERIAL_COLOR_KEY, value)
|
setProperty(MATERIAL_COLOR_KEY, value?.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
val VisualObject3D.material: Material3D?
|
val VisualObject3D.material: Material3D?
|
||||||
@ -110,5 +116,5 @@ fun VisualObject3D.material(builder: Material3D.() -> Unit) {
|
|||||||
var VisualObject3D.opacity: Double?
|
var VisualObject3D.opacity: Double?
|
||||||
get() = getProperty(MATERIAL_OPACITY_KEY).double
|
get() = getProperty(MATERIAL_OPACITY_KEY).double
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(MATERIAL_OPACITY_KEY, value)
|
setProperty(MATERIAL_OPACITY_KEY, value?.asValue())
|
||||||
}
|
}
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.meta.number
|
import hep.dataforge.meta.number
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -16,7 +16,6 @@ import kotlinx.serialization.UseSerializers
|
|||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("3d.line")
|
@SerialName("3d.line")
|
||||||
class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject3D {
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
@ -32,5 +31,5 @@ class PolyLine(var points: List<Point3D>) : AbstractVisualObject(), VisualObject
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VisualGroup3D.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) =
|
fun MutableVisualGroup.polyline(vararg points: Point3D, name: String = "", action: PolyLine.() -> Unit = {}) =
|
||||||
PolyLine(points.toList()).apply(action).also { set(name, it) }
|
PolyLine(points.toList()).apply(action).also { set(name, it) }
|
@ -1,18 +1,13 @@
|
|||||||
@file:UseSerializers(Point3DSerializer::class, NameSerializer::class, ConfigSerializer::class)
|
@file:UseSerializers(Point3DSerializer::class)
|
||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.io.serialization.NameSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.meta.Laminate
|
import hep.dataforge.meta.Laminate
|
||||||
import hep.dataforge.meta.MetaItem
|
import hep.dataforge.meta.MetaItem
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.vis.*
|
||||||
import hep.dataforge.names.asName
|
|
||||||
import hep.dataforge.names.plus
|
|
||||||
import hep.dataforge.vis.common.*
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
@ -26,7 +21,9 @@ import kotlin.collections.set
|
|||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("3d.proxy")
|
@SerialName("3d.proxy")
|
||||||
class Proxy private constructor(val templateName: Name) : AbstractVisualObject(), VisualGroup, VisualObject3D {
|
class Proxy private constructor(
|
||||||
|
val templateName: Name
|
||||||
|
) : AbstractVisualObject(), VisualGroup, VisualObject3D {
|
||||||
|
|
||||||
constructor(parent: VisualGroup3D, templateName: Name) : this(templateName) {
|
constructor(parent: VisualGroup3D, templateName: Name) : this(templateName) {
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
@ -36,7 +33,6 @@ class Proxy private constructor(val templateName: Name) : AbstractVisualObject()
|
|||||||
override var rotation: Point3D? = null
|
override var rotation: Point3D? = null
|
||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,10 +40,12 @@ class Proxy private constructor(val templateName: Name) : AbstractVisualObject()
|
|||||||
*/
|
*/
|
||||||
val prototype: VisualObject3D
|
val prototype: VisualObject3D
|
||||||
get() = (parent as? VisualGroup3D)?.getPrototype(templateName)
|
get() = (parent as? VisualGroup3D)?.getPrototype(templateName)
|
||||||
?: error("Template with name $templateName not found in $parent")
|
?: error("Prototype with name $templateName not found in $parent")
|
||||||
|
|
||||||
override val styleSheet: StyleSheet
|
override val styleSheet: StyleSheet
|
||||||
get() = (parent as? VisualGroup)?.styleSheet ?: StyleSheet(this)
|
get() = parent?.styleSheet ?: StyleSheet(
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||||
return if (inherit) {
|
return if (inherit) {
|
||||||
@ -89,7 +87,8 @@ class Proxy private constructor(val templateName: Name) : AbstractVisualObject()
|
|||||||
|
|
||||||
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
|
//override fun findAllStyles(): Laminate = Laminate((styles + prototype.styles).mapNotNull { findStyle(it) })
|
||||||
|
|
||||||
inner class ProxyChild(val name: Name) : AbstractVisualObject(), VisualGroup {
|
inner class ProxyChild(val name: Name) : AbstractVisualObject(),
|
||||||
|
VisualGroup {
|
||||||
|
|
||||||
val prototype: VisualObject get() = prototypeFor(name)
|
val prototype: VisualObject get() = prototypeFor(name)
|
||||||
|
|
||||||
@ -155,20 +154,18 @@ val VisualObject.prototype: VisualObject
|
|||||||
/**
|
/**
|
||||||
* Create ref for existing prototype
|
* Create ref for existing prototype
|
||||||
*/
|
*/
|
||||||
inline fun VisualGroup3D.ref(
|
fun VisualGroup3D.ref(
|
||||||
templateName: Name,
|
templateName: Name,
|
||||||
name: String = "",
|
name: String = ""
|
||||||
block: Proxy.() -> Unit = {}
|
): Proxy = Proxy(this, templateName).also { set(name, it) }
|
||||||
) = Proxy(this, templateName).apply(block).also { set(name, it) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new proxy wrapping given object and automatically adding it to the prototypes
|
* Add new proxy wrapping given object and automatically adding it to the prototypes
|
||||||
*/
|
*/
|
||||||
fun VisualGroup3D.proxy(
|
fun VisualGroup3D.proxy(
|
||||||
templateName: Name,
|
name: String,
|
||||||
obj: VisualObject3D,
|
obj: VisualObject3D,
|
||||||
name: String = "",
|
templateName: Name = name.toName()
|
||||||
block: Proxy.() -> Unit = {}
|
|
||||||
): Proxy {
|
): Proxy {
|
||||||
val existing = getPrototype(templateName)
|
val existing = getPrototype(templateName)
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
@ -178,5 +175,14 @@ fun VisualGroup3D.proxy(
|
|||||||
} else if (existing != obj) {
|
} else if (existing != obj) {
|
||||||
error("Can't add different prototype on top of existing one")
|
error("Can't add different prototype on top of existing one")
|
||||||
}
|
}
|
||||||
return ref(templateName, name, block)
|
return ref(templateName, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun VisualGroup3D.proxyGroup(
|
||||||
|
name: String,
|
||||||
|
templateName: Name = name.toName(),
|
||||||
|
block: MutableVisualGroup.() -> Unit
|
||||||
|
): Proxy {
|
||||||
|
val group = VisualGroup3D().apply(block)
|
||||||
|
return proxy(name, group, templateName)
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -23,7 +23,6 @@ class Sphere(
|
|||||||
var theta: Float = PI.toFloat()
|
var theta: Float = PI.toFloat()
|
||||||
) : AbstractVisualObject(), VisualObject3D, Shape {
|
) : AbstractVisualObject(), VisualObject3D, Shape {
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override var position: Point3D? = null
|
override var position: Point3D? = null
|
||||||
@ -61,7 +60,7 @@ class Sphere(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun VisualGroup3D.sphere(
|
inline fun MutableVisualGroup.sphere(
|
||||||
radius: Number,
|
radius: Number,
|
||||||
phi: Number = 2 * PI,
|
phi: Number = 2 * PI,
|
||||||
theta: Number = PI,
|
theta: Number = PI,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
@file:UseSerializers(Point3DSerializer::class)
|
@file:UseSerializers(Point3DSerializer::class)
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.common.set
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.set
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
@ -29,7 +29,6 @@ class Tube(
|
|||||||
override var rotation: Point3D? = null
|
override var rotation: Point3D? = null
|
||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -129,7 +128,7 @@ class Tube(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun VisualGroup3D.tube(
|
inline fun MutableVisualGroup.tube(
|
||||||
r: Number,
|
r: Number,
|
||||||
height: Number,
|
height: Number,
|
||||||
innerRadius: Number = 0f,
|
innerRadius: Number = 0f,
|
||||||
|
@ -4,14 +4,13 @@ import hep.dataforge.context.AbstractPlugin
|
|||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.context.PluginFactory
|
import hep.dataforge.context.PluginFactory
|
||||||
import hep.dataforge.context.PluginTag
|
import hep.dataforge.context.PluginTag
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.io.serialization.MetaSerializer
|
|
||||||
import hep.dataforge.io.serialization.NameSerializer
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vis.common.Visual
|
import hep.dataforge.vis.SimpleVisualGroup
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.Visual
|
||||||
|
import hep.dataforge.vis.VisualObject
|
||||||
|
import kotlinx.serialization.UnstableDefault
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
import kotlinx.serialization.modules.SerializersModule
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
@ -39,29 +38,29 @@ class Visual3D(meta: Meta) : AbstractPlugin(meta) {
|
|||||||
val serialModule = SerializersModule {
|
val serialModule = SerializersModule {
|
||||||
contextual(Point3DSerializer)
|
contextual(Point3DSerializer)
|
||||||
contextual(Point2DSerializer)
|
contextual(Point2DSerializer)
|
||||||
contextual(NameSerializer)
|
|
||||||
contextual(NameTokenSerializer)
|
|
||||||
contextual(MetaSerializer)
|
|
||||||
contextual(ConfigSerializer)
|
|
||||||
|
|
||||||
polymorphic(VisualObject::class, VisualObject3D::class) {
|
polymorphic(VisualObject::class, VisualObject3D::class) {
|
||||||
VisualGroup3D::class with VisualGroup3D.serializer()
|
subclass(SimpleVisualGroup.serializer())
|
||||||
Proxy::class with Proxy.serializer()
|
subclass(VisualGroup3D.serializer())
|
||||||
Composite::class with Composite.serializer()
|
subclass(Proxy.serializer())
|
||||||
Tube::class with Tube.serializer()
|
subclass(Composite.serializer())
|
||||||
Box::class with Box.serializer()
|
subclass(Tube.serializer())
|
||||||
Convex::class with Convex.serializer()
|
subclass(Box.serializer())
|
||||||
Extruded::class with Extruded.serializer()
|
subclass(Convex.serializer())
|
||||||
addSubclass(PolyLine.serializer())
|
subclass(Extruded.serializer())
|
||||||
addSubclass(Label3D.serializer())
|
subclass(PolyLine.serializer())
|
||||||
|
subclass(Label3D.serializer())
|
||||||
|
subclass(Sphere.serializer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val json = Json(
|
@OptIn(UnstableDefault::class)
|
||||||
|
internal val json = Json(
|
||||||
JsonConfiguration(
|
JsonConfiguration(
|
||||||
prettyPrint = true,
|
prettyPrint = true,
|
||||||
useArrayPolymorphism = false,
|
useArrayPolymorphism = false,
|
||||||
encodeDefaults = false
|
encodeDefaults = false,
|
||||||
|
ignoreUnknownKeys = true
|
||||||
),
|
),
|
||||||
context = serialModule
|
context = serialModule
|
||||||
)
|
)
|
||||||
|
@ -1,48 +1,49 @@
|
|||||||
@file:UseSerializers(
|
@file:UseSerializers(
|
||||||
Point3DSerializer::class,
|
Point3DSerializer::class
|
||||||
ConfigSerializer::class,
|
|
||||||
NameTokenSerializer::class,
|
|
||||||
NameSerializer::class,
|
|
||||||
MetaSerializer::class
|
|
||||||
)
|
)
|
||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.io.serialization.MetaSerializer
|
|
||||||
import hep.dataforge.io.serialization.NameSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.isEmpty
|
import hep.dataforge.vis.*
|
||||||
import hep.dataforge.vis.common.AbstractVisualGroup
|
|
||||||
import hep.dataforge.vis.common.StyleSheet
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
|
||||||
import hep.dataforge.vis.common.set
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
interface PrototypeHolder {
|
||||||
|
val parent: VisualGroup?
|
||||||
|
val prototypes: MutableVisualGroup?
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents 3-dimensional Visual Group
|
* Represents 3-dimensional Visual Group
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("group.3d")
|
@SerialName("group.3d")
|
||||||
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D, PrototypeHolder {
|
||||||
|
|
||||||
override var styleSheet: StyleSheet? = null
|
override var styleSheet: StyleSheet? = null
|
||||||
private set
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container for templates visible inside this group
|
* A container for templates visible inside this group
|
||||||
*/
|
*/
|
||||||
var prototypes: VisualGroup3D? = null
|
@Serializable(PrototypesSerializer::class)
|
||||||
set(value) {
|
override var prototypes: MutableVisualGroup? = null
|
||||||
value?.parent = this
|
private set
|
||||||
field = value
|
|
||||||
}
|
/**
|
||||||
|
* Create or edit prototype node as a group
|
||||||
|
*/
|
||||||
|
fun prototypes(builder: MutableVisualGroup.() -> Unit): Unit {
|
||||||
|
(prototypes ?: Prototypes().also {
|
||||||
|
attach(it)
|
||||||
|
prototypes = it
|
||||||
|
}).run(builder)
|
||||||
|
}
|
||||||
|
|
||||||
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
@ -55,38 +56,18 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
|||||||
private val _children = HashMap<NameToken, VisualObject>()
|
private val _children = HashMap<NameToken, VisualObject>()
|
||||||
override val children: Map<NameToken, VisualObject> get() = _children
|
override val children: Map<NameToken, VisualObject> get() = _children
|
||||||
|
|
||||||
// init {
|
|
||||||
// //Do after deserialization
|
|
||||||
// attachChildren()
|
|
||||||
// }
|
|
||||||
|
|
||||||
override fun attachChildren() {
|
override fun attachChildren() {
|
||||||
prototypes?.parent = this
|
prototypes?.parent = this
|
||||||
prototypes?.attachChildren()
|
prototypes?.attachChildren()
|
||||||
super.attachChildren()
|
super.attachChildren()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update or create stylesheet
|
|
||||||
*/
|
|
||||||
fun styleSheet(block: StyleSheet.() -> Unit) {
|
|
||||||
val res = styleSheet ?: StyleSheet(this).also { styleSheet = it }
|
|
||||||
res.block()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeChild(token: NameToken) {
|
override fun removeChild(token: NameToken) {
|
||||||
_children.remove(token)?.run { parent = null }
|
_children.remove(token)?.apply { parent = null }
|
||||||
childrenChanged(token.asName(), null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChild(token: NameToken, child: VisualObject) {
|
override fun setChild(token: NameToken, child: VisualObject) {
|
||||||
if (child.parent == null) {
|
|
||||||
child.parent = this
|
|
||||||
} else if (child.parent !== this) {
|
|
||||||
error("Can't reassign existing parent for $child")
|
|
||||||
}
|
|
||||||
_children[token] = child
|
_children[token] = child
|
||||||
childrenChanged(token.asName(), child)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
@ -94,25 +75,13 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
|||||||
// */
|
// */
|
||||||
// override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child)
|
// override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child)
|
||||||
|
|
||||||
override fun createGroup(name: Name): VisualGroup3D {
|
override fun createGroup(): VisualGroup3D = VisualGroup3D()
|
||||||
return when {
|
|
||||||
name.isEmpty() -> error("Should be unreachable")
|
|
||||||
name.length == 1 -> {
|
|
||||||
val token = name.first()!!
|
|
||||||
when (val current = children[token]) {
|
|
||||||
null -> VisualGroup3D().also { setChild(token, it) }
|
|
||||||
is VisualGroup3D -> current
|
|
||||||
else -> error("Can't create group with name $name because it exists and not a group")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> createGroup(name.first()!!.asName()).createGroup(name.cutFirst())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// val PROTOTYPES_KEY = NameToken("@prototypes")
|
// val PROTOTYPES_KEY = NameToken("@prototypes")
|
||||||
|
|
||||||
fun fromJson(json: String): VisualGroup3D =
|
fun parseJson(json: String): VisualGroup3D =
|
||||||
Visual3D.json.parse(serializer(), json).also { it.attachChildren() }
|
Visual3D.json.parse(serializer(), json).also { it.attachChildren() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,21 +89,50 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
|||||||
/**
|
/**
|
||||||
* Ger a prototype redirecting the request to the parent if prototype is not found
|
* Ger a prototype redirecting the request to the parent if prototype is not found
|
||||||
*/
|
*/
|
||||||
tailrec fun VisualGroup3D.getPrototype(name: Name): VisualObject3D? =
|
tailrec fun PrototypeHolder.getPrototype(name: Name): VisualObject3D? =
|
||||||
prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name)
|
prototypes?.get(name) as? VisualObject3D ?: (parent as? VisualGroup3D)?.getPrototype(name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create or edit prototype node as a group
|
* Define a group with given [name], attach it to this parent and return it.
|
||||||
*/
|
*/
|
||||||
inline fun VisualGroup3D.prototypes(builder: VisualGroup3D.() -> Unit): Unit {
|
fun MutableVisualGroup.group(name: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
||||||
(prototypes ?: VisualGroup3D().also { prototypes = it }).run(builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define a group with given [key], attach it to this parent and return it.
|
|
||||||
*/
|
|
||||||
fun VisualGroup3D.group(key: String = "", action: VisualGroup3D.() -> Unit = {}): VisualGroup3D =
|
|
||||||
VisualGroup3D().apply(action).also {
|
VisualGroup3D().apply(action).also {
|
||||||
set(key, it)
|
set(name, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Prototypes(
|
||||||
|
override var children: MutableMap<NameToken, VisualObject> = LinkedHashMap()
|
||||||
|
) : AbstractVisualGroup(), MutableVisualGroup, PrototypeHolder {
|
||||||
|
|
||||||
|
override var styleSheet: StyleSheet?
|
||||||
|
get() = null
|
||||||
|
set(_) {
|
||||||
|
error("Can't define stylesheet for prototypes block")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeChild(token: NameToken) {
|
||||||
|
children.remove(token)
|
||||||
|
childrenChanged(token.asName(), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setChild(token: NameToken, child: VisualObject) {
|
||||||
|
children[token] = child
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createGroup() = SimpleVisualGroup()
|
||||||
|
|
||||||
|
override var properties: Config?
|
||||||
|
get() = null
|
||||||
|
set(_) {
|
||||||
|
error("Can't define properties for prototypes block")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val prototypes: MutableVisualGroup get() = this
|
||||||
|
|
||||||
|
override fun attachChildren() {
|
||||||
|
children.values.forEach {
|
||||||
|
it.parent = parent
|
||||||
|
(it as? VisualGroup)?.attachChildren()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
@file:UseSerializers(Point3DSerializer::class, NameSerializer::class, NameTokenSerializer::class)
|
@file:UseSerializers(Point3DSerializer::class)
|
||||||
|
|
||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.NameSerializer
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.output.Renderer
|
import hep.dataforge.output.Renderer
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.values.ValueType
|
||||||
|
import hep.dataforge.values.asValue
|
||||||
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.IGNORE_KEY
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
||||||
@ -25,7 +27,8 @@ interface VisualObject3D : VisualObject {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val VISIBLE_KEY = "visible".asName()
|
val VISIBLE_KEY = "visible".asName()
|
||||||
// val SELECTED_KEY = "selected".asName()
|
|
||||||
|
// val SELECTED_KEY = "selected".asName()
|
||||||
val DETAIL_KEY = "detail".asName()
|
val DETAIL_KEY = "detail".asName()
|
||||||
val LAYER_KEY = "layer".asName()
|
val LAYER_KEY = "layer".asName()
|
||||||
val IGNORE_KEY = "ignore".asName()
|
val IGNORE_KEY = "ignore".asName()
|
||||||
@ -55,6 +58,22 @@ interface VisualObject3D : VisualObject {
|
|||||||
val xScale = scale + x
|
val xScale = scale + x
|
||||||
val yScale = scale + y
|
val yScale = scale + y
|
||||||
val zScale = scale + z
|
val zScale = scale + z
|
||||||
|
|
||||||
|
val descriptor by lazy {
|
||||||
|
NodeDescriptor {
|
||||||
|
defineValue(VISIBLE_KEY) {
|
||||||
|
type(ValueType.BOOLEAN)
|
||||||
|
default(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineItem(Material3D.MATERIAL_KEY.toString(), Material3D.descriptor)
|
||||||
|
|
||||||
|
// Material3D.MATERIAL_COLOR_KEY put "#ffffff"
|
||||||
|
// Material3D.MATERIAL_OPACITY_KEY put 1.0
|
||||||
|
// Material3D.MATERIAL_WIREFRAME_KEY put false
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,10 +83,10 @@ interface VisualObject3D : VisualObject {
|
|||||||
var VisualObject3D.layer: Int
|
var VisualObject3D.layer: Int
|
||||||
get() = getProperty(LAYER_KEY).int ?: 0
|
get() = getProperty(LAYER_KEY).int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty(LAYER_KEY, value)
|
setProperty(LAYER_KEY, value.asValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Renderer<VisualObject3D>.render(meta: Meta = EmptyMeta, action: VisualGroup3D.() -> Unit) =
|
fun Renderer<VisualObject3D>.render(meta: Meta = Meta.EMPTY, action: VisualGroup3D.() -> Unit) =
|
||||||
render(VisualGroup3D().apply(action), meta)
|
render(VisualGroup3D().apply(action), meta)
|
||||||
|
|
||||||
// Common properties
|
// Common properties
|
||||||
@ -86,7 +105,7 @@ enum class RotationOrder {
|
|||||||
*/
|
*/
|
||||||
var VisualObject3D.rotationOrder: RotationOrder
|
var VisualObject3D.rotationOrder: RotationOrder
|
||||||
get() = getProperty(VisualObject3D.rotationOrder).enum<RotationOrder>() ?: RotationOrder.XYZ
|
get() = getProperty(VisualObject3D.rotationOrder).enum<RotationOrder>() ?: RotationOrder.XYZ
|
||||||
set(value) = setProperty(VisualObject3D.rotationOrder, value.name)
|
set(value) = setProperty(VisualObject3D.rotationOrder, value.name.asValue())
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,19 +113,19 @@ var VisualObject3D.rotationOrder: RotationOrder
|
|||||||
*/
|
*/
|
||||||
var VisualObject3D.detail: Int?
|
var VisualObject3D.detail: Int?
|
||||||
get() = getProperty(DETAIL_KEY, false).int
|
get() = getProperty(DETAIL_KEY, false).int
|
||||||
set(value) = setProperty(DETAIL_KEY, value)
|
set(value) = setProperty(DETAIL_KEY, value?.asValue())
|
||||||
|
|
||||||
var VisualObject.visible: Boolean?
|
var VisualObject.visible: Boolean?
|
||||||
get() = getProperty(VISIBLE_KEY).boolean
|
get() = getProperty(VISIBLE_KEY).boolean
|
||||||
set(value) = setProperty(VISIBLE_KEY, value)
|
set(value) = setProperty(VISIBLE_KEY, value?.asValue())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this property is true, the object will be ignored on render.
|
* If this property is true, the object will be ignored on render.
|
||||||
* Property is not inherited.
|
* Property is not inherited.
|
||||||
*/
|
*/
|
||||||
var VisualObject.ignore: Boolean?
|
var VisualObject.ignore: Boolean?
|
||||||
get() = getProperty(IGNORE_KEY,false).boolean
|
get() = getProperty(IGNORE_KEY, false).boolean
|
||||||
set(value) = setProperty(IGNORE_KEY, value)
|
set(value) = setProperty(IGNORE_KEY, value?.asValue())
|
||||||
|
|
||||||
//var VisualObject.selected: Boolean?
|
//var VisualObject.selected: Boolean?
|
||||||
// get() = getProperty(SELECTED_KEY).boolean
|
// get() = getProperty(SELECTED_KEY).boolean
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial
|
|
||||||
|
|
||||||
import kotlin.math.PI
|
|
||||||
|
|
||||||
object World {
|
|
||||||
val ZERO = Point3D(0.0, 0.0, 0.0)
|
|
||||||
val ONE = Point3D(1.0, 1.0, 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const val PI2: Float = 2 * PI.toFloat()
|
|
@ -1,9 +1,16 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.buildMeta
|
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.number
|
import hep.dataforge.meta.number
|
||||||
|
import kotlin.math.PI
|
||||||
|
|
||||||
|
object World {
|
||||||
|
val ZERO = Point3D(0.0, 0.0, 0.0)
|
||||||
|
val ONE = Point3D(1.0, 1.0, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const val PI2: Float = 2 * PI.toFloat()
|
||||||
|
|
||||||
expect class Point2D(x: Number, y: Number) {
|
expect class Point2D(x: Number, y: Number) {
|
||||||
var x: Double
|
var x: Double
|
||||||
@ -13,7 +20,7 @@ expect class Point2D(x: Number, y: Number) {
|
|||||||
operator fun Point2D.component1() = x
|
operator fun Point2D.component1() = x
|
||||||
operator fun Point2D.component2() = y
|
operator fun Point2D.component2() = y
|
||||||
|
|
||||||
fun Point2D.toMeta() = buildMeta {
|
fun Point2D.toMeta() = Meta {
|
||||||
VisualObject3D.x put x
|
VisualObject3D.x put x
|
||||||
VisualObject3D.y put y
|
VisualObject3D.y put y
|
||||||
}
|
}
|
||||||
@ -34,7 +41,7 @@ operator fun Point3D.component3() = z
|
|||||||
|
|
||||||
fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0)
|
fun Meta.point3D() = Point3D(this["x"].number ?: 0, this["y"].number ?: 0, this["y"].number ?: 0)
|
||||||
|
|
||||||
fun Point3D.toMeta() = buildMeta {
|
fun Point3D.toMeta() = Meta {
|
||||||
VisualObject3D.x put x
|
VisualObject3D.x put x
|
||||||
VisualObject3D.y put y
|
VisualObject3D.y put y
|
||||||
VisualObject3D.z put z
|
VisualObject3D.z put z
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.descriptor
|
import hep.dataforge.meta.double
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
|
import hep.dataforge.vis.VisualGroup
|
||||||
|
import hep.dataforge.vis.VisualObject
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.internal.DoubleSerializer
|
import kotlinx.serialization.builtins.MapSerializer
|
||||||
import kotlinx.serialization.internal.StringDescriptor
|
import kotlinx.serialization.builtins.nullable
|
||||||
import kotlinx.serialization.internal.nullable
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
inline fun <R> Decoder.decodeStructure(
|
inline fun <R> Decoder.decodeStructure(
|
||||||
desc: SerialDescriptor,
|
desc: SerialDescriptor,
|
||||||
vararg typeParams: KSerializer<*> = emptyArray(),
|
vararg typeParams: KSerializer<*> = emptyArray(),
|
||||||
crossinline block: CompositeDecoder.() -> R
|
crossinline block: CompositeDecoder.() -> R
|
||||||
): R {
|
): R {
|
||||||
val decoder = beginStructure(desc, *typeParams)
|
val decoder = beginStructure(desc, *typeParams)
|
||||||
val res = decoder.block()
|
val res = decoder.block()
|
||||||
@ -31,7 +33,7 @@ inline fun Encoder.encodeStructure(
|
|||||||
|
|
||||||
@Serializer(Point3D::class)
|
@Serializer(Point3D::class)
|
||||||
object Point3DSerializer : KSerializer<Point3D> {
|
object Point3DSerializer : KSerializer<Point3D> {
|
||||||
override val descriptor: SerialDescriptor = descriptor("hep.dataforge.vis.spatial.Point3D") {
|
override val descriptor: SerialDescriptor = SerialDescriptor("hep.dataforge.vis.spatial.Point3D") {
|
||||||
double("x", true)
|
double("x", true)
|
||||||
double("y", true)
|
double("y", true)
|
||||||
double("z", true)
|
double("z", true)
|
||||||
@ -45,28 +47,28 @@ object Point3DSerializer : KSerializer<Point3D> {
|
|||||||
loop@ while (true) {
|
loop@ while (true) {
|
||||||
when (val i = decodeElementIndex(descriptor)) {
|
when (val i = decodeElementIndex(descriptor)) {
|
||||||
CompositeDecoder.READ_DONE -> break@loop
|
CompositeDecoder.READ_DONE -> break@loop
|
||||||
0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
0 -> x = decodeNullableSerializableElement(descriptor, 0, Double.serializer().nullable) ?: 0.0
|
||||||
1 -> y = decodeNullableSerializableElement(descriptor, 1, DoubleSerializer.nullable) ?: 0.0
|
1 -> y = decodeNullableSerializableElement(descriptor, 1, Double.serializer().nullable) ?: 0.0
|
||||||
2 -> z = decodeNullableSerializableElement(descriptor, 2, DoubleSerializer.nullable) ?: 0.0
|
2 -> z = decodeNullableSerializableElement(descriptor, 2, Double.serializer().nullable) ?: 0.0
|
||||||
else -> throw SerializationException("Unknown index $i")
|
else -> throw SerializationException("Unknown index $i")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Point3D(x?:0.0, y?:0.0, z?:0.0)
|
return Point3D(x ?: 0.0, y ?: 0.0, z ?: 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, obj: Point3D) {
|
override fun serialize(encoder: Encoder, value: Point3D) {
|
||||||
encoder.encodeStructure(descriptor) {
|
encoder.encodeStructure(descriptor) {
|
||||||
if (obj.x != 0.0) encodeDoubleElement(descriptor, 0, obj.x)
|
if (value.x != 0.0) encodeDoubleElement(descriptor, 0, value.x)
|
||||||
if (obj.y != 0.0) encodeDoubleElement(descriptor, 1, obj.y)
|
if (value.y != 0.0) encodeDoubleElement(descriptor, 1, value.y)
|
||||||
if (obj.z != 0.0) encodeDoubleElement(descriptor, 2, obj.z)
|
if (value.z != 0.0) encodeDoubleElement(descriptor, 2, value.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializer(Point2D::class)
|
@Serializer(Point2D::class)
|
||||||
object Point2DSerializer : KSerializer<Point2D> {
|
object Point2DSerializer : KSerializer<Point2D> {
|
||||||
override val descriptor: SerialDescriptor = descriptor("hep.dataforge.vis.spatial.Point2D") {
|
override val descriptor: SerialDescriptor = SerialDescriptor("hep.dataforge.vis.spatial.Point2D") {
|
||||||
double("x", true)
|
double("x", true)
|
||||||
double("y", true)
|
double("y", true)
|
||||||
}
|
}
|
||||||
@ -78,32 +80,48 @@ object Point2DSerializer : KSerializer<Point2D> {
|
|||||||
loop@ while (true) {
|
loop@ while (true) {
|
||||||
when (val i = decodeElementIndex(descriptor)) {
|
when (val i = decodeElementIndex(descriptor)) {
|
||||||
CompositeDecoder.READ_DONE -> break@loop
|
CompositeDecoder.READ_DONE -> break@loop
|
||||||
0 -> x = decodeNullableSerializableElement(descriptor, 0, DoubleSerializer.nullable) ?: 0.0
|
0 -> x = decodeNullableSerializableElement(descriptor, 0, Double.serializer().nullable) ?: 0.0
|
||||||
1 -> y = decodeNullableSerializableElement(descriptor, 1, DoubleSerializer.nullable) ?: 0.0
|
1 -> y = decodeNullableSerializableElement(descriptor, 1, Double.serializer().nullable) ?: 0.0
|
||||||
else -> throw SerializationException("Unknown index $i")
|
else -> throw SerializationException("Unknown index $i")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Point2D(x?:0.0, y?:0.0)
|
return Point2D(x ?: 0.0, y ?: 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, obj: Point2D) {
|
override fun serialize(encoder: Encoder, value: Point2D) {
|
||||||
encoder.encodeStructure(descriptor) {
|
encoder.encodeStructure(descriptor) {
|
||||||
if (obj.x != 0.0) encodeDoubleElement(descriptor, 0, obj.x)
|
if (value.x != 0.0) encodeDoubleElement(descriptor, 0, value.x)
|
||||||
if (obj.y != 0.0) encodeDoubleElement(descriptor, 1, obj.y)
|
if (value.y != 0.0) encodeDoubleElement(descriptor, 1, value.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializer(NameToken::class)
|
@Serializer(MutableVisualGroup::class)
|
||||||
object NameTokenSerializer : KSerializer<NameToken> {
|
internal object PrototypesSerializer : KSerializer<MutableVisualGroup> {
|
||||||
override val descriptor: SerialDescriptor = StringDescriptor.withName("NameToken")
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): NameToken {
|
private val mapSerializer: KSerializer<Map<NameToken, VisualObject>> =
|
||||||
return decoder.decodeString().toName().first()!!
|
MapSerializer(
|
||||||
|
NameToken.serializer(),
|
||||||
|
VisualObject.serializer()
|
||||||
|
)
|
||||||
|
|
||||||
|
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): MutableVisualGroup {
|
||||||
|
val map = mapSerializer.deserialize(decoder)
|
||||||
|
return Prototypes(map as? MutableMap<NameToken, VisualObject> ?: LinkedHashMap(map))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, obj: NameToken) {
|
override fun serialize(encoder: Encoder, value: MutableVisualGroup) {
|
||||||
encoder.encodeString(obj.toString())
|
mapSerializer.serialize(encoder, value.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun VisualObject.stringify(): String = Visual3D.json.stringify(VisualObject.serializer(), this)
|
||||||
|
|
||||||
|
fun VisualObject.Companion.parseJson(str: String) = Visual3D.json.parse(VisualObject.serializer(), str).also {
|
||||||
|
if(it is VisualGroup){
|
||||||
|
it.attachChildren()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,16 +2,13 @@ package hep.dataforge.vis.spatial.specifications
|
|||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
|
||||||
class AxesSpec(override val config: Config) : Specific {
|
class Axes : Scheme() {
|
||||||
var visible by boolean(!config.isEmpty())
|
var visible by boolean(!config.isEmpty())
|
||||||
var size by double(AXIS_SIZE)
|
var size by double(AXIS_SIZE)
|
||||||
var width by double(AXIS_WIDTH)
|
var width by double(AXIS_WIDTH)
|
||||||
|
|
||||||
companion object : Specification<AxesSpec> {
|
companion object : SchemeSpec<Axes>(::Axes) {
|
||||||
override fun wrap(config: Config): AxesSpec = AxesSpec(config)
|
|
||||||
|
|
||||||
const val AXIS_SIZE = 1000.0
|
const val AXIS_SIZE = 1000.0
|
||||||
const val AXIS_WIDTH = 3.0
|
const val AXIS_WIDTH = 3.0
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,14 @@
|
|||||||
package hep.dataforge.vis.spatial.specifications
|
package hep.dataforge.vis.spatial.specifications
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.Scheme
|
||||||
|
import hep.dataforge.meta.SchemeSpec
|
||||||
|
import hep.dataforge.meta.double
|
||||||
|
import hep.dataforge.meta.int
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
class CameraSpec(override val config: Config) : Specific {
|
class Camera : Scheme() {
|
||||||
var fov by int(FIELD_OF_VIEW)
|
var fov by int(FIELD_OF_VIEW)
|
||||||
|
|
||||||
//var aspect by double(1.0)
|
//var aspect by double(1.0)
|
||||||
var nearClip by double(NEAR_CLIP)
|
var nearClip by double(NEAR_CLIP)
|
||||||
var farClip by double(FAR_CLIP)
|
var farClip by double(FAR_CLIP)
|
||||||
@ -14,11 +18,10 @@ class CameraSpec(override val config: Config) : Specific {
|
|||||||
var latitude by double(INITIAL_LATITUDE)
|
var latitude by double(INITIAL_LATITUDE)
|
||||||
val zenith: Double get() = PI / 2 - latitude
|
val zenith: Double get() = PI / 2 - latitude
|
||||||
|
|
||||||
companion object : Specification<CameraSpec> {
|
companion object : SchemeSpec<Camera>(::Camera) {
|
||||||
override fun wrap(config: Config): CameraSpec = CameraSpec(config)
|
|
||||||
const val INITIAL_DISTANCE = 300.0
|
const val INITIAL_DISTANCE = 300.0
|
||||||
const val INITIAL_AZIMUTH = 0.0
|
const val INITIAL_AZIMUTH = 0.0
|
||||||
const val INITIAL_LATITUDE = PI/6
|
const val INITIAL_LATITUDE = PI / 6
|
||||||
const val NEAR_CLIP = 0.1
|
const val NEAR_CLIP = 0.1
|
||||||
const val FAR_CLIP = 10000.0
|
const val FAR_CLIP = 10000.0
|
||||||
const val FIELD_OF_VIEW = 75
|
const val FIELD_OF_VIEW = 75
|
@ -0,0 +1,15 @@
|
|||||||
|
package hep.dataforge.vis.spatial.specifications
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Scheme
|
||||||
|
import hep.dataforge.meta.SchemeSpec
|
||||||
|
import hep.dataforge.meta.int
|
||||||
|
import hep.dataforge.meta.spec
|
||||||
|
|
||||||
|
class Canvas : Scheme() {
|
||||||
|
var axes by spec(Axes, Axes.empty())
|
||||||
|
var camera by spec(Camera, Camera.empty())
|
||||||
|
var controls by spec(Controls, Controls.empty())
|
||||||
|
var minSize by int(300)
|
||||||
|
|
||||||
|
companion object : SchemeSpec<Canvas>(::Canvas)
|
||||||
|
}
|
@ -1,15 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial.specifications
|
|
||||||
|
|
||||||
import hep.dataforge.meta.*
|
|
||||||
|
|
||||||
class CanvasSpec(override val config: Config) : Specific {
|
|
||||||
var axes by spec(AxesSpec)
|
|
||||||
var camera by spec(CameraSpec)
|
|
||||||
var controls by spec(ControlsSpec)
|
|
||||||
var minSize by int(300)
|
|
||||||
|
|
||||||
companion object: Specification<CanvasSpec>{
|
|
||||||
override fun wrap(config: Config): CanvasSpec = CanvasSpec(config)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,9 @@
|
|||||||
|
package hep.dataforge.vis.spatial.specifications
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Scheme
|
||||||
|
import hep.dataforge.meta.SchemeSpec
|
||||||
|
|
||||||
|
|
||||||
|
class Controls : Scheme() {
|
||||||
|
companion object : SchemeSpec<Controls>(::Controls)
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
package hep.dataforge.vis.spatial.specifications
|
|
||||||
|
|
||||||
import hep.dataforge.meta.Config
|
|
||||||
import hep.dataforge.meta.Specific
|
|
||||||
import hep.dataforge.meta.Specification
|
|
||||||
|
|
||||||
class ControlsSpec(override val config: Config) : Specific {
|
|
||||||
companion object : Specification<ControlsSpec> {
|
|
||||||
override fun wrap(config: Config): ControlsSpec = ControlsSpec(config)
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,9 +2,9 @@ package hep.dataforge.vis.spatial.transform
|
|||||||
|
|
||||||
import hep.dataforge.meta.update
|
import hep.dataforge.meta.update
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.vis.common.MutableVisualGroup
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.VisualGroup
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
|
|
||||||
internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject {
|
internal fun mergeChild(parent: VisualGroup, child: VisualObject): VisualObject {
|
||||||
|
@ -2,11 +2,10 @@ package hep.dataforge.vis.spatial.transform
|
|||||||
|
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.vis.common.MutableVisualGroup
|
import hep.dataforge.vis.MutableVisualGroup
|
||||||
import hep.dataforge.vis.common.VisualGroup
|
import hep.dataforge.vis.VisualGroup
|
||||||
import hep.dataforge.vis.spatial.Proxy
|
import hep.dataforge.vis.spatial.Proxy
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import hep.dataforge.vis.spatial.prototypes
|
|
||||||
|
|
||||||
object UnRef : VisualTreeTransform<VisualGroup3D>() {
|
object UnRef : VisualTreeTransform<VisualGroup3D>() {
|
||||||
private fun VisualGroup.countRefs(): Map<Name, Int> {
|
private fun VisualGroup.countRefs(): Map<Name, Int> {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package hep.dataforge.vis.spatial.transform
|
package hep.dataforge.vis.spatial.transform
|
||||||
|
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A root class for [VisualObject] tree optimization
|
* A root class for [VisualObject] tree optimization
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.io.toMeta
|
|
||||||
import hep.dataforge.meta.MetaItem
|
import hep.dataforge.meta.MetaItem
|
||||||
import hep.dataforge.meta.getIndexed
|
import hep.dataforge.meta.getIndexed
|
||||||
|
import hep.dataforge.meta.node
|
||||||
|
import hep.dataforge.meta.toMetaItem
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -26,9 +27,9 @@ class ConvexTest {
|
|||||||
val convex = group.first() as Convex
|
val convex = group.first() as Convex
|
||||||
|
|
||||||
val json = Visual3D.json.toJson(Convex.serializer(), convex)
|
val json = Visual3D.json.toJson(Convex.serializer(), convex)
|
||||||
val meta = json.toMeta()
|
val meta = json.toMetaItem().node!!
|
||||||
|
|
||||||
val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D()}
|
val points = meta.getIndexed("points").values.map { (it as MetaItem.NodeItem<*>).node.point3D() }
|
||||||
assertEquals(8, points.count())
|
assertEquals(8, points.count())
|
||||||
|
|
||||||
assertEquals(8, convex.points.size)
|
assertEquals(8, convex.points.size)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.Colors
|
||||||
import hep.dataforge.vis.common.get
|
import hep.dataforge.vis.get
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
@ -3,7 +3,7 @@ package hep.dataforge.vis.spatial
|
|||||||
import hep.dataforge.meta.int
|
import hep.dataforge.meta.int
|
||||||
import hep.dataforge.meta.set
|
import hep.dataforge.meta.set
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.vis.common.useStyle
|
import hep.dataforge.vis.useStyle
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package hep.dataforge.vis.spatial
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.vis.spatial.Visual3D.Companion.json
|
import hep.dataforge.names.toName
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import hep.dataforge.vis.VisualObject
|
||||||
|
import hep.dataforge.vis.get
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class SerializationTest {
|
class SerializationTest {
|
||||||
@ImplicitReflectionSerializer
|
|
||||||
@Test
|
@Test
|
||||||
fun testCubeSerialization() {
|
fun testCubeSerialization() {
|
||||||
val cube = Box(100f, 100f, 100f).apply {
|
val cube = Box(100f, 100f, 100f).apply {
|
||||||
@ -14,9 +14,30 @@ class SerializationTest {
|
|||||||
x = 100
|
x = 100
|
||||||
z = -100
|
z = -100
|
||||||
}
|
}
|
||||||
val string = json.stringify(Box.serializer(), cube)
|
val string = cube.stringify()
|
||||||
println(string)
|
println(string)
|
||||||
val newCube = json.parse(Box.serializer(), string)
|
val newCube = VisualObject.parseJson(string)
|
||||||
assertEquals(cube.config, newCube.config)
|
assertEquals(cube.config, newCube.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testProxySerialization() {
|
||||||
|
val cube = Box(100f, 100f, 100f).apply {
|
||||||
|
color(222)
|
||||||
|
x = 100
|
||||||
|
z = -100
|
||||||
|
}
|
||||||
|
val group = VisualGroup3D().apply {
|
||||||
|
proxy("cube", cube)
|
||||||
|
proxyGroup("pg", "pg.content".toName()){
|
||||||
|
sphere(50){
|
||||||
|
x = -100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val string = group.stringify()
|
||||||
|
println(string)
|
||||||
|
val reconstructed = VisualGroup3D.parseJson(string)
|
||||||
|
assertEquals(group["cube"]?.config, reconstructed["cube"]?.config)
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,18 +2,19 @@ package hep.dataforge.vis.spatial.three
|
|||||||
|
|
||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.getProperty
|
||||||
import hep.dataforge.meta.string
|
import hep.dataforge.meta.string
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.plus
|
import hep.dataforge.names.plus
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.output.Renderer
|
import hep.dataforge.output.Renderer
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.Colors
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import hep.dataforge.vis.spatial.specifications.CameraSpec
|
import hep.dataforge.vis.spatial.specifications.Camera
|
||||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||||
import hep.dataforge.vis.spatial.specifications.ControlsSpec
|
import hep.dataforge.vis.spatial.specifications.Controls
|
||||||
import hep.dataforge.vis.spatial.three.ThreeMaterials.HIGHLIGHT_MATERIAL
|
import hep.dataforge.vis.spatial.three.ThreeMaterials.HIGHLIGHT_MATERIAL
|
||||||
|
import hep.dataforge.vis.spatial.three.ThreeMaterials.SELECTED_MATERIAL
|
||||||
import info.laht.threekt.WebGLRenderer
|
import info.laht.threekt.WebGLRenderer
|
||||||
import info.laht.threekt.cameras.PerspectiveCamera
|
import info.laht.threekt.cameras.PerspectiveCamera
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
@ -23,6 +24,7 @@ import info.laht.threekt.external.controls.OrbitControls
|
|||||||
import info.laht.threekt.external.controls.TrackballControls
|
import info.laht.threekt.external.controls.TrackballControls
|
||||||
import info.laht.threekt.geometries.EdgesGeometry
|
import info.laht.threekt.geometries.EdgesGeometry
|
||||||
import info.laht.threekt.helpers.AxesHelper
|
import info.laht.threekt.helpers.AxesHelper
|
||||||
|
import info.laht.threekt.materials.LineBasicMaterial
|
||||||
import info.laht.threekt.math.Vector2
|
import info.laht.threekt.math.Vector2
|
||||||
import info.laht.threekt.objects.LineSegments
|
import info.laht.threekt.objects.LineSegments
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
@ -39,7 +41,7 @@ import kotlin.math.sin
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: CanvasSpec) : Renderer<VisualObject3D> {
|
class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val canvas: Canvas) : Renderer<VisualObject3D> {
|
||||||
|
|
||||||
override val context: Context get() = three.context
|
override val context: Context get() = three.context
|
||||||
|
|
||||||
@ -51,17 +53,19 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
private val raycaster = Raycaster()
|
private val raycaster = Raycaster()
|
||||||
private val mousePosition: Vector2 = Vector2()
|
private val mousePosition: Vector2 = Vector2()
|
||||||
|
|
||||||
var clickListener: ((Name) -> Unit)? = null
|
var onClick: ((Name?) -> Unit)? = null
|
||||||
|
|
||||||
val axes = AxesHelper(spec.axes.size.toInt()).apply {
|
val axes = AxesHelper(canvas.axes.size.toInt()).apply {
|
||||||
visible = spec.axes.visible
|
visible = canvas.axes.visible
|
||||||
}
|
}
|
||||||
|
|
||||||
val scene: Scene = Scene().apply {
|
val scene: Scene = Scene().apply {
|
||||||
add(axes)
|
add(axes)
|
||||||
}
|
}
|
||||||
|
|
||||||
val camera = buildCamera(spec.camera)
|
val camera = buildCamera(canvas.camera)
|
||||||
|
|
||||||
|
private var picked: Object3D? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
element.clear()
|
element.clear()
|
||||||
@ -75,29 +79,26 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
}
|
}
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
element.addEventListener("mousedown", { event ->
|
element.addEventListener("mousedown", {
|
||||||
val mesh = pick()
|
val picked = pick()
|
||||||
if (mesh != null) {
|
onClick?.invoke(picked?.fullName())
|
||||||
val name = mesh.fullName()
|
|
||||||
clickListener?.invoke(name)
|
|
||||||
}
|
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
camera.aspect = 1.0
|
camera.aspect = 1.0
|
||||||
|
|
||||||
val renderer = WebGLRenderer { antialias = true }.apply {
|
val renderer = WebGLRenderer { antialias = true }.apply {
|
||||||
setClearColor(Colors.skyblue, 1)
|
setClearColor(Colors.skyblue, 1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addControls(renderer.domElement, spec.controls)
|
addControls(renderer.domElement, canvas.controls)
|
||||||
|
|
||||||
fun animate() {
|
fun animate() {
|
||||||
val mesh = pick()
|
val picked = pick()
|
||||||
|
|
||||||
if (mesh != null && highlighted != mesh) {
|
if (picked != null && this.picked != picked) {
|
||||||
highlighted?.toggleHighlight(false)
|
this.picked?.toggleHighlight(false,HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||||
mesh.toggleHighlight(true)
|
picked.toggleHighlight(true, HIGHLIGHT_NAME, HIGHLIGHT_MATERIAL)
|
||||||
|
this.picked = picked
|
||||||
}
|
}
|
||||||
|
|
||||||
window.requestAnimationFrame {
|
window.requestAnimationFrame {
|
||||||
@ -108,7 +109,7 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
|
|
||||||
element.appendChild(renderer.domElement)
|
element.appendChild(renderer.domElement)
|
||||||
|
|
||||||
renderer.setSize(max(spec.minSize, element.offsetWidth), max(spec.minSize, element.offsetWidth))
|
renderer.setSize(max(canvas.minSize, element.offsetWidth), max(canvas.minSize, element.offsetWidth))
|
||||||
|
|
||||||
element.onresize = {
|
element.onresize = {
|
||||||
renderer.setSize(element.offsetWidth, element.offsetWidth)
|
renderer.setSize(element.offsetWidth, element.offsetWidth)
|
||||||
@ -118,18 +119,6 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
animate()
|
animate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pick(): Mesh? {
|
|
||||||
// update the picking ray with the camera and mouse position
|
|
||||||
raycaster.setFromCamera(mousePosition, camera)
|
|
||||||
|
|
||||||
// calculate objects intersecting the picking ray
|
|
||||||
return root?.let { root ->
|
|
||||||
val intersects = raycaster.intersectObject(root, true)
|
|
||||||
val intersect = intersects.firstOrNull()
|
|
||||||
intersect?.`object` as? Mesh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve full name of the object relative to the global root
|
* Resolve full name of the object relative to the global root
|
||||||
*/
|
*/
|
||||||
@ -142,7 +131,26 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildCamera(spec: CameraSpec) = PerspectiveCamera(
|
private fun Object3D.isStatic(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Object3D?.upTrace(): Object3D? = if (this?.name?.startsWith("@") == true) parent else this
|
||||||
|
|
||||||
|
private fun pick(): Object3D? {
|
||||||
|
// update the picking ray with the camera and mouse position
|
||||||
|
raycaster.setFromCamera(mousePosition, camera)
|
||||||
|
|
||||||
|
// calculate objects intersecting the picking ray
|
||||||
|
return root?.let { root ->
|
||||||
|
val intersects = raycaster.intersectObject(root, true)
|
||||||
|
val obj = intersects.map { it.`object` }.firstOrNull { !it.isStatic() }
|
||||||
|
obj.upTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun buildCamera(spec: Camera) = PerspectiveCamera(
|
||||||
spec.fov,
|
spec.fov,
|
||||||
1.0,
|
1.0,
|
||||||
spec.nearClip,
|
spec.nearClip,
|
||||||
@ -153,18 +161,23 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
translateZ(spec.distance * sin(spec.zenith) * cos(spec.azimuth))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addControls(element: Node, controlsSpec: ControlsSpec) {
|
private fun addControls(element: Node, controls: Controls) {
|
||||||
when (controlsSpec["type"].string) {
|
when (controls.getProperty("type").string) {
|
||||||
"trackball" -> TrackballControls(camera, element)
|
"trackball" -> TrackballControls(camera, element)
|
||||||
else -> OrbitControls(camera, element)
|
else -> OrbitControls(camera, element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(obj: VisualObject3D, meta: Meta) {
|
fun clear(){
|
||||||
//clear old root
|
|
||||||
scene.children.find { it.name == "@root" }?.let {
|
scene.children.find { it.name == "@root" }?.let {
|
||||||
scene.remove(it)
|
scene.remove(it)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(obj: VisualObject3D, meta: Meta) {
|
||||||
|
//clear old root
|
||||||
|
clear()
|
||||||
|
|
||||||
|
|
||||||
val object3D = three.buildObject3D(obj)
|
val object3D = three.buildObject3D(obj)
|
||||||
object3D.name = "@root"
|
object3D.name = "@root"
|
||||||
@ -173,43 +186,65 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val spec: Canvas
|
|||||||
root = object3D
|
root = object3D
|
||||||
}
|
}
|
||||||
|
|
||||||
private var highlighted: Mesh? = null
|
private var highlighted: Object3D? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle highlight for the given [Mesh] object
|
* Toggle highlight for the given [Mesh] object
|
||||||
*/
|
*/
|
||||||
private fun Mesh.toggleHighlight(highlight: Boolean) {
|
private fun Object3D.toggleHighlight(
|
||||||
if (highlight) {
|
highlight: Boolean,
|
||||||
val edges = LineSegments(
|
edgesName: String,
|
||||||
EdgesGeometry(geometry as BufferGeometry),
|
material: LineBasicMaterial = SELECTED_MATERIAL
|
||||||
HIGHLIGHT_MATERIAL
|
) {
|
||||||
).apply {
|
if (userData[DO_NOT_HIGHLIGHT_TAG] == true) {
|
||||||
name = "@highlight"
|
return
|
||||||
|
}
|
||||||
|
if (this is Mesh) {
|
||||||
|
if (highlight) {
|
||||||
|
val edges = LineSegments(
|
||||||
|
EdgesGeometry(geometry as BufferGeometry),
|
||||||
|
material
|
||||||
|
).apply {
|
||||||
|
name = edgesName
|
||||||
|
}
|
||||||
|
add(edges)
|
||||||
|
} else {
|
||||||
|
val highlightEdges = children.find { it.name == edgesName }
|
||||||
|
highlightEdges?.let { remove(it) }
|
||||||
}
|
}
|
||||||
add(edges)
|
|
||||||
highlighted = this
|
|
||||||
} else {
|
} else {
|
||||||
val highlightEdges = children.find { it.name == "@highlight" }
|
children.filter { it.name != edgesName }.forEach {
|
||||||
highlightEdges?.let { remove(it) }
|
it.toggleHighlight(highlight, edgesName, material)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle highlight for element with given name
|
* Toggle highlight for element with given name
|
||||||
*/
|
*/
|
||||||
fun highlight(name: Name?) {
|
fun select(name: Name?) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
highlighted?.toggleHighlight(false)
|
highlighted?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL)
|
||||||
highlighted = null
|
highlighted = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val mesh = root?.findChild(name) as? Mesh
|
val obj = root?.findChild(name)
|
||||||
if (mesh != null && highlighted != mesh) {
|
if (obj != null && highlighted != obj) {
|
||||||
highlighted?.toggleHighlight(false)
|
highlighted?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL)
|
||||||
mesh.toggleHighlight(true)
|
obj.toggleHighlight(true, SELECT_NAME, SELECTED_MATERIAL)
|
||||||
|
highlighted = obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DO_NOT_HIGHLIGHT_TAG = "doNotHighlight"
|
||||||
|
private const val HIGHLIGHT_NAME = "@highlight"
|
||||||
|
private const val SELECT_NAME = "@select"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ThreePlugin.output(element: HTMLElement, spec: CanvasSpec = CanvasSpec.empty()): ThreeCanvas =
|
fun ThreePlugin.output(element: HTMLElement, spec: Canvas = Canvas.empty()): ThreeCanvas =
|
||||||
ThreeCanvas(element, this, spec)
|
ThreeCanvas(element, this, spec)
|
||||||
|
|
||||||
|
fun ThreePlugin.render(element: HTMLElement, obj: VisualObject3D, spec: Canvas = Canvas.empty()): Unit =
|
||||||
|
output(element, spec).render(obj)
|
@ -0,0 +1,76 @@
|
|||||||
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
|
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import react.RBuilder
|
||||||
|
import react.RComponent
|
||||||
|
import react.RProps
|
||||||
|
import react.RState
|
||||||
|
import react.dom.div
|
||||||
|
import react.dom.findDOMNode
|
||||||
|
|
||||||
|
interface ThreeCanvasProps : RProps {
|
||||||
|
var context: Context
|
||||||
|
var obj: VisualObject3D
|
||||||
|
var options: Canvas?
|
||||||
|
var selected: Name?
|
||||||
|
var clickCallback: (Name?) -> Unit
|
||||||
|
var canvasCallback: ((ThreeCanvas?) -> Unit)?
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ThreeCanvasState : RState {
|
||||||
|
var element: Element?
|
||||||
|
// var canvas: ThreeCanvas?
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThreeCanvasComponent : RComponent<ThreeCanvasProps, ThreeCanvasState>() {
|
||||||
|
|
||||||
|
var canvas: ThreeCanvas? = null
|
||||||
|
|
||||||
|
override fun componentDidMount() {
|
||||||
|
if(canvas == null) {
|
||||||
|
val element = state.element as? HTMLElement ?: error("Canvas element not found")
|
||||||
|
val three: ThreePlugin = props.context.plugins.fetch(ThreePlugin)
|
||||||
|
canvas = three.output(element, props.options ?: Canvas.empty()).apply {
|
||||||
|
onClick = props.clickCallback
|
||||||
|
}
|
||||||
|
props.canvasCallback?.invoke(canvas)
|
||||||
|
}
|
||||||
|
canvas?.render(props.obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// override fun componentWillUnmount() {
|
||||||
|
// state.element?.clear()
|
||||||
|
// props.canvasCallback?.invoke(null)
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun componentDidUpdate(prevProps: ThreeCanvasProps, prevState: ThreeCanvasState, snapshot: Any) {
|
||||||
|
if (prevProps.obj != props.obj) {
|
||||||
|
componentDidMount()
|
||||||
|
}
|
||||||
|
if (prevProps.selected != props.selected) {
|
||||||
|
canvas?.select(props.selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun RBuilder.render() {
|
||||||
|
div {
|
||||||
|
ref {
|
||||||
|
state.element = findDOMNode(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RBuilder.threeCanvas(object3D: VisualObject3D, options: Canvas.() -> Unit = {}) {
|
||||||
|
child(ThreeCanvasComponent::class) {
|
||||||
|
attrs {
|
||||||
|
this.obj = object3D
|
||||||
|
this.options = Canvas.invoke(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package hep.dataforge.vis.spatial.three
|
|||||||
|
|
||||||
import hep.dataforge.vis.spatial.Label3D
|
import hep.dataforge.vis.spatial.Label3D
|
||||||
import hep.dataforge.vis.spatial.color
|
import hep.dataforge.vis.spatial.color
|
||||||
|
import hep.dataforge.vis.spatial.three.ThreeCanvas.Companion.DO_NOT_HIGHLIGHT_TAG
|
||||||
import info.laht.threekt.DoubleSide
|
import info.laht.threekt.DoubleSide
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.geometries.PlaneBufferGeometry
|
import info.laht.threekt.geometries.PlaneBufferGeometry
|
||||||
@ -18,7 +19,7 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
* Using example from http://stemkoski.github.io/Three.js/Texture-From-Canvas.html
|
||||||
*/
|
*/
|
||||||
object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
object ThreeCanvasLabelFactory : ThreeFactory<Label3D> {
|
||||||
override val type: KClass<in Label3D> get() = Label3D::class
|
override val type: KClass<in Label3D> get() = Label3D::class
|
||||||
|
|
||||||
override fun invoke(obj: Label3D): Object3D {
|
override fun invoke(obj: Label3D): Object3D {
|
||||||
@ -31,7 +32,7 @@ object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
|||||||
//canvas.width = metrics.width.toInt()
|
//canvas.width = metrics.width.toInt()
|
||||||
|
|
||||||
|
|
||||||
context.fillText(obj.text, (canvas.width - metrics.width)/2, 0.5*canvas.height)
|
context.fillText(obj.text, (canvas.width - metrics.width) / 2, 0.5 * canvas.height)
|
||||||
|
|
||||||
|
|
||||||
// canvas contents will be used for a texture
|
// canvas contents will be used for a texture
|
||||||
@ -51,6 +52,7 @@ object ThreeCanvasLabelFactory: ThreeFactory<Label3D> {
|
|||||||
|
|
||||||
mesh.updatePosition(obj)
|
mesh.updatePosition(obj)
|
||||||
|
|
||||||
|
mesh.userData[DO_NOT_HIGHLIGHT_TAG] = true
|
||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ package hep.dataforge.vis.spatial.three
|
|||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
import hep.dataforge.provider.Type
|
import hep.dataforge.provider.Type
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
import hep.dataforge.vis.spatial.Material3D.Companion.MATERIAL_KEY
|
||||||
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
||||||
|
@ -2,8 +2,8 @@ package hep.dataforge.vis.spatial.three
|
|||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.Colors
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.spatial.Material3D
|
import hep.dataforge.vis.spatial.Material3D
|
||||||
import info.laht.threekt.materials.LineBasicMaterial
|
import info.laht.threekt.materials.LineBasicMaterial
|
||||||
import info.laht.threekt.materials.Material
|
import info.laht.threekt.materials.Material
|
||||||
@ -22,11 +22,17 @@ object ThreeMaterials {
|
|||||||
color.set(DEFAULT_LINE_COLOR)
|
color.set(DEFAULT_LINE_COLOR)
|
||||||
}
|
}
|
||||||
|
|
||||||
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
val SELECTED_MATERIAL = LineBasicMaterial().apply {
|
||||||
color.set(Colors.ivory)
|
color.set(Colors.ivory)
|
||||||
linewidth = 8.0
|
linewidth = 8.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val HIGHLIGHT_MATERIAL = LineBasicMaterial().apply {
|
||||||
|
color.set(Colors.blue)
|
||||||
|
linewidth = 8.0
|
||||||
|
}
|
||||||
|
|
||||||
fun getLineMaterial(meta: Meta?): LineBasicMaterial {
|
fun getLineMaterial(meta: Meta?): LineBasicMaterial {
|
||||||
if (meta == null) return DEFAULT_LINE
|
if (meta == null) return DEFAULT_LINE
|
||||||
return LineBasicMaterial().apply {
|
return LineBasicMaterial().apply {
|
||||||
|
@ -3,7 +3,7 @@ package hep.dataforge.vis.spatial.three
|
|||||||
import hep.dataforge.context.*
|
import hep.dataforge.context.*
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
package hep.dataforge.vis.spatial.three
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
import hep.dataforge.io.serialization.ConfigSerializer
|
|
||||||
import hep.dataforge.meta.Config
|
import hep.dataforge.meta.Config
|
||||||
import hep.dataforge.vis.common.AbstractVisualObject
|
import hep.dataforge.vis.AbstractVisualObject
|
||||||
import hep.dataforge.vis.spatial.Point3D
|
import hep.dataforge.vis.spatial.Point3D
|
||||||
import hep.dataforge.vis.spatial.Point3DSerializer
|
import hep.dataforge.vis.spatial.Point3DSerializer
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
@ -26,7 +25,6 @@ class CustomThreeVisualObject(val threeFactory: ThreeFactory<VisualObject3D>) :
|
|||||||
override var rotation: Point3D? = null
|
override var rotation: Point3D? = null
|
||||||
override var scale: Point3D? = null
|
override var scale: Point3D? = null
|
||||||
|
|
||||||
@Serializable(ConfigSerializer::class)
|
|
||||||
override var properties: Config? = null
|
override var properties: Config? = null
|
||||||
|
|
||||||
override fun toObject3D(): Object3D = threeFactory(this)
|
override fun toObject3D(): Object3D = threeFactory(this)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@file:JsModule("@hi-level/three-csg")
|
@file:JsModule("three-csg-ts")
|
||||||
@file:JsNonModule
|
@file:JsNonModule
|
||||||
@file:Suppress(
|
@file:Suppress(
|
||||||
"INTERFACE_WITH_SUPERCLASS",
|
"INTERFACE_WITH_SUPERCLASS",
|
||||||
|
@ -1,19 +1,25 @@
|
|||||||
package hep.dataforge.vis.spatial.three
|
package hep.dataforge.vis.spatial.three
|
||||||
|
|
||||||
|
import hep.dataforge.js.accordion
|
||||||
|
import hep.dataforge.js.entry
|
||||||
import hep.dataforge.js.requireJS
|
import hep.dataforge.js.requireJS
|
||||||
import hep.dataforge.vis.js.editor.accordion
|
|
||||||
import hep.dataforge.vis.spatial.Visual3D
|
import hep.dataforge.vis.spatial.Visual3D
|
||||||
import hep.dataforge.vis.spatial.VisualGroup3D
|
import hep.dataforge.vis.spatial.VisualGroup3D
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.*
|
||||||
import kotlinx.html.TagConsumer
|
|
||||||
import kotlinx.html.button
|
|
||||||
import kotlinx.html.dom.append
|
import kotlinx.html.dom.append
|
||||||
import kotlinx.html.js.*
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import org.w3c.files.Blob
|
import org.w3c.files.Blob
|
||||||
import org.w3c.files.BlobPropertyBag
|
import org.w3c.files.BlobPropertyBag
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.button
|
||||||
|
import react.dom.div
|
||||||
|
import react.dom.input
|
||||||
|
import react.dom.label
|
||||||
import kotlin.dom.clear
|
import kotlin.dom.clear
|
||||||
|
|
||||||
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
||||||
@ -25,6 +31,70 @@ private fun saveData(event: Event, fileName: String, mimeType: String = "text/pl
|
|||||||
fileSaver.saveAs(blob, fileName)
|
fileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun RBuilder.canvasControls(canvas: ThreeCanvas) = accordion("controls") {
|
||||||
|
entry("Settings") {
|
||||||
|
div("row") {
|
||||||
|
div("col-2") {
|
||||||
|
label("checkbox-inline") {
|
||||||
|
input(type = InputType.checkBox){
|
||||||
|
attrs {
|
||||||
|
defaultChecked = canvas.axes.visible
|
||||||
|
onChangeFunction = {
|
||||||
|
canvas.axes.visible = (it.target as HTMLInputElement).checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+"Axes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("col-1") {
|
||||||
|
button {
|
||||||
|
+"Export"
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
||||||
|
Visual3D.json.stringify(
|
||||||
|
VisualGroup3D.serializer(),
|
||||||
|
group
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (json != null) {
|
||||||
|
saveData(it, "object.json", "text/json") {
|
||||||
|
json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry("Layers") {
|
||||||
|
div("row") {
|
||||||
|
(0..11).forEach { layer ->
|
||||||
|
div("col-1") {
|
||||||
|
label { +layer.toString() }
|
||||||
|
input(type = InputType.checkBox){
|
||||||
|
attrs {
|
||||||
|
if (layer == 0) {
|
||||||
|
defaultChecked = true
|
||||||
|
}
|
||||||
|
onChangeFunction = {
|
||||||
|
if ((it.target as HTMLInputElement).checked) {
|
||||||
|
canvas.camera.layers.enable(layer)
|
||||||
|
} else {
|
||||||
|
canvas.camera.layers.disable(layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||||
clear()
|
clear()
|
||||||
append {
|
append {
|
||||||
@ -33,7 +103,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
div("row") {
|
div("row") {
|
||||||
div("col-2") {
|
div("col-2") {
|
||||||
label("checkbox-inline") {
|
label("checkbox-inline") {
|
||||||
input(type = InputType.checkBox).apply {
|
input(type = InputType.checkBox) {
|
||||||
checked = canvas.axes.visible
|
checked = canvas.axes.visible
|
||||||
onChangeFunction = {
|
onChangeFunction = {
|
||||||
canvas.axes.visible = checked
|
canvas.axes.visible = checked
|
||||||
@ -67,7 +137,7 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
(0..11).forEach { layer ->
|
(0..11).forEach { layer ->
|
||||||
div("col-1") {
|
div("col-1") {
|
||||||
label { +layer.toString() }
|
label { +layer.toString() }
|
||||||
input(type = InputType.checkBox).apply {
|
input(type = InputType.checkBox) {
|
||||||
if (layer == 0) {
|
if (layer == 0) {
|
||||||
checked = true
|
checked = true
|
||||||
}
|
}
|
||||||
@ -84,61 +154,6 @@ fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLEl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* card("Settings") {
|
|
||||||
div("row") {
|
|
||||||
div("col-2") {
|
|
||||||
label("checkbox-inline") {
|
|
||||||
input(type = InputType.checkBox).apply {
|
|
||||||
checked = canvas.axes.visible
|
|
||||||
onChangeFunction = {
|
|
||||||
canvas.axes.visible = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+"Axes"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div("col-1") {
|
|
||||||
button {
|
|
||||||
+"Export"
|
|
||||||
onClickFunction = {
|
|
||||||
val json = (canvas.content as? VisualGroup3D)?.let { group ->
|
|
||||||
Visual3D.json.stringify(
|
|
||||||
VisualGroup3D.serializer(),
|
|
||||||
group
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (json != null) {
|
|
||||||
saveData(it, "object.json", "text/json"){
|
|
||||||
json
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
card("Layers") {
|
|
||||||
div("row") {
|
|
||||||
(0..11).forEach { layer ->
|
|
||||||
div("col-1") {
|
|
||||||
label { +layer.toString() }
|
|
||||||
input(type = InputType.checkBox).apply {
|
|
||||||
if (layer == 0) {
|
|
||||||
checked = true
|
|
||||||
}
|
|
||||||
onChangeFunction = {
|
|
||||||
if (checked) {
|
|
||||||
canvas.camera.layers.enable(layer)
|
|
||||||
} else {
|
|
||||||
canvas.camera.layers.disable(layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -153,7 +153,7 @@ open external class Object3D {
|
|||||||
* An object that can be used to store custom data about the Object3D.
|
* An object that can be used to store custom data about the Object3D.
|
||||||
* It should not hold references to functions as these will not be cloned.
|
* It should not hold references to functions as these will not be cloned.
|
||||||
*/
|
*/
|
||||||
var userData: Map<String, Any>
|
var userData: dynamic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional callback that is executed immediately before the Object3D is rendered.
|
* An optional callback that is executed immediately before the Object3D is rendered.
|
||||||
|
@ -5,7 +5,7 @@ import hep.dataforge.context.ContextAware
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.output.Renderer
|
import hep.dataforge.output.Renderer
|
||||||
import hep.dataforge.vis.spatial.VisualObject3D
|
import hep.dataforge.vis.spatial.VisualObject3D
|
||||||
import hep.dataforge.vis.spatial.specifications.CanvasSpec
|
import hep.dataforge.vis.spatial.specifications.Canvas
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import javafx.beans.property.ObjectProperty
|
import javafx.beans.property.ObjectProperty
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
@ -14,7 +14,7 @@ import javafx.scene.paint.Color
|
|||||||
import org.fxyz3d.scene.Axes
|
import org.fxyz3d.scene.Axes
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class FXCanvas3D(val plugin: FX3DPlugin, val spec: CanvasSpec = CanvasSpec.empty()) :
|
class FXCanvas3D(val plugin: FX3DPlugin, val spec: Canvas = Canvas.empty()) :
|
||||||
Fragment(), Renderer<VisualObject3D>, ContextAware {
|
Fragment(), Renderer<VisualObject3D>, ContextAware {
|
||||||
|
|
||||||
override val context: Context get() = plugin.context
|
override val context: Context get() = plugin.context
|
||||||
|
@ -5,7 +5,7 @@ import hep.dataforge.meta.double
|
|||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.int
|
import hep.dataforge.meta.int
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import hep.dataforge.vis.common.Colors
|
import hep.dataforge.vis.Colors
|
||||||
import hep.dataforge.vis.spatial.Material3D
|
import hep.dataforge.vis.spatial.Material3D
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
import javafx.scene.paint.Material
|
import javafx.scene.paint.Material
|
||||||
|
@ -3,7 +3,7 @@ package hep.dataforge.vis.spatial.fx
|
|||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.isEmpty
|
import hep.dataforge.names.isEmpty
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import hep.dataforge.vis.spatial.Proxy
|
import hep.dataforge.vis.spatial.Proxy
|
||||||
import javafx.scene.Group
|
import javafx.scene.Group
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.vis.spatial.fx
|
package hep.dataforge.vis.spatial.fx
|
||||||
|
|
||||||
import hep.dataforge.vis.spatial.specifications.CameraSpec
|
|
||||||
import javafx.beans.InvalidationListener
|
import javafx.beans.InvalidationListener
|
||||||
import javafx.beans.property.SimpleDoubleProperty
|
import javafx.beans.property.SimpleDoubleProperty
|
||||||
import javafx.event.EventHandler
|
import javafx.event.EventHandler
|
||||||
@ -15,6 +14,7 @@ import javafx.scene.transform.Rotate
|
|||||||
import javafx.scene.transform.Translate
|
import javafx.scene.transform.Translate
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
import hep.dataforge.vis.spatial.specifications.Camera as CameraSpec
|
||||||
|
|
||||||
|
|
||||||
class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) {
|
class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) {
|
||||||
|
@ -4,7 +4,7 @@ import hep.dataforge.meta.*
|
|||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.startsWith
|
import hep.dataforge.names.startsWith
|
||||||
import hep.dataforge.names.toName
|
import hep.dataforge.names.toName
|
||||||
import hep.dataforge.vis.common.VisualObject
|
import hep.dataforge.vis.VisualObject
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import javafx.beans.binding.ObjectBinding
|
import javafx.beans.binding.ObjectBinding
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
package hep.dataforge.vis.spatial.gdml
|
package hep.dataforge.vis.spatial
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.JSON_PRETTY
|
||||||
import hep.dataforge.vis.spatial.*
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
import kotlinx.serialization.modules.SerialModule
|
import kotlinx.serialization.modules.SerialModule
|
||||||
import kotlinx.serialization.modules.SerialModuleCollector
|
import kotlinx.serialization.modules.SerialModuleCollector
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
internal val SerialDescriptor.jsonType
|
private fun SerialDescriptor.getJsonType() = when (this.kind) {
|
||||||
get() = when (this.kind) {
|
StructureKind.LIST -> "array"
|
||||||
StructureKind.LIST -> "array"
|
PrimitiveKind.BYTE, PrimitiveKind.SHORT, PrimitiveKind.INT, PrimitiveKind.LONG,
|
||||||
PrimitiveKind.BYTE, PrimitiveKind.SHORT, PrimitiveKind.INT, PrimitiveKind.LONG,
|
PrimitiveKind.FLOAT, PrimitiveKind.DOUBLE -> "number"
|
||||||
PrimitiveKind.FLOAT, PrimitiveKind.DOUBLE -> "number"
|
PrimitiveKind.STRING, PrimitiveKind.CHAR, UnionKind.ENUM_KIND -> "string"
|
||||||
PrimitiveKind.STRING, PrimitiveKind.CHAR, UnionKind.ENUM_KIND -> "string"
|
PrimitiveKind.BOOLEAN -> "boolean"
|
||||||
PrimitiveKind.BOOLEAN -> "boolean"
|
else -> "object"
|
||||||
else -> "object"
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
private fun SerialDescriptor.isVisualObject() = serialName.startsWith("3d")||serialName.startsWith("group")
|
||||||
|
|
||||||
|
private const val definitionNode = "\$defs"
|
||||||
|
|
||||||
private fun SerialModule.enumerate(type: KClass<*>): Sequence<SerialDescriptor> {
|
private fun SerialModule.enumerate(type: KClass<*>): Sequence<SerialDescriptor> {
|
||||||
val list = ArrayList<SerialDescriptor>()
|
val list = ArrayList<SerialDescriptor>()
|
||||||
@ -60,13 +61,16 @@ private fun SerialModule.enumerate(type: KClass<*>): Sequence<SerialDescriptor>
|
|||||||
*/
|
*/
|
||||||
private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): JsonObject {
|
private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): JsonObject {
|
||||||
|
|
||||||
if (descriptor.name in arrayOf(
|
if (descriptor.serialName in arrayOf(
|
||||||
"hep.dataforge.vis.spatial.Point3D",
|
"hep.dataforge.vis.spatial.Point3D",
|
||||||
|
"hep.dataforge.vis.spatial.Point3D?",
|
||||||
"hep.dataforge.vis.spatial.Point2D",
|
"hep.dataforge.vis.spatial.Point2D",
|
||||||
Meta::class.qualifiedName
|
"hep.dataforge.vis.spatial.Point2D?",
|
||||||
|
"hep.dataforge.meta.Meta",
|
||||||
|
"hep.dataforge.meta.Meta?"
|
||||||
)
|
)
|
||||||
) return json {
|
) return json {
|
||||||
"\$ref" to "#/definitions/${descriptor.name}"
|
"\$ref" to "#/$definitionNode/${descriptor.serialName.replace("?", "")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,37 +83,35 @@ private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): Jso
|
|||||||
if (!isEnum && !isPolymorphic) descriptor.elementDescriptors().forEachIndexed { index, child ->
|
if (!isEnum && !isPolymorphic) descriptor.elementDescriptors().forEachIndexed { index, child ->
|
||||||
val elementName = descriptor.getElementName(index)
|
val elementName = descriptor.getElementName(index)
|
||||||
|
|
||||||
properties[elementName] = when (elementName) {
|
val elementSchema = when (elementName) {
|
||||||
"templates" -> json {
|
"properties" -> json {
|
||||||
"\$ref" to "#/definitions/hep.dataforge.vis.spatial.VisualGroup3D"
|
"\$ref" to "#/$definitionNode/hep.dataforge.meta.Meta"
|
||||||
}
|
}
|
||||||
"properties" -> json {
|
"first", "second" -> json {
|
||||||
"\$ref" to "#/definitions/${Meta::class.qualifiedName}"
|
"\$ref" to "#/$definitionNode/children"
|
||||||
}
|
|
||||||
"first", "second" -> json{
|
|
||||||
"\$ref" to "#/definitions/children"
|
|
||||||
}
|
}
|
||||||
"styleSheet" -> json {
|
"styleSheet" -> json {
|
||||||
"type" to "object"
|
"type" to "object"
|
||||||
"additionalProperties" to json {
|
"additionalProperties" to json {
|
||||||
"\$ref" to "#/definitions/${Meta::class.qualifiedName}"
|
"\$ref" to "#/$definitionNode/hep.dataforge.meta.Meta"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in arrayOf("children") -> json {
|
in arrayOf("children", "prototypes") -> json {
|
||||||
"type" to "object"
|
"type" to "object"
|
||||||
"additionalProperties" to json {
|
"additionalProperties" to json {
|
||||||
"\$ref" to "#/definitions/children"
|
"\$ref" to "#/$definitionNode/children"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> jsonSchema(child, context)
|
else -> jsonSchema(child, context)
|
||||||
}
|
}
|
||||||
|
properties[elementName] = elementSchema
|
||||||
|
|
||||||
if (!descriptor.isElementOptional(index)) requiredProperties.add(elementName)
|
if (!descriptor.isElementOptional(index)) requiredProperties.add(elementName)
|
||||||
}
|
}
|
||||||
|
|
||||||
val jsonType = descriptor.jsonType
|
val jsonType = descriptor.getJsonType()
|
||||||
val objectData: MutableMap<String, JsonElement> = mutableMapOf(
|
val objectData: MutableMap<String, JsonElement> = mutableMapOf(
|
||||||
"description" to JsonLiteral(descriptor.name),
|
"description" to JsonLiteral(descriptor.serialName),
|
||||||
"type" to JsonLiteral(jsonType)
|
"type" to JsonLiteral(jsonType)
|
||||||
)
|
)
|
||||||
if (isEnum) {
|
if (isEnum) {
|
||||||
@ -118,6 +120,11 @@ private fun jsonSchema(descriptor: SerialDescriptor, context: SerialModule): Jso
|
|||||||
}
|
}
|
||||||
when (jsonType) {
|
when (jsonType) {
|
||||||
"object" -> {
|
"object" -> {
|
||||||
|
if(descriptor.isVisualObject()) {
|
||||||
|
properties["type"] = json {
|
||||||
|
"const" to descriptor.serialName
|
||||||
|
}
|
||||||
|
}
|
||||||
objectData["properties"] = JsonObject(properties)
|
objectData["properties"] = JsonObject(properties)
|
||||||
val required = requiredProperties.map { JsonLiteral(it) }
|
val required = requiredProperties.map { JsonLiteral(it) }
|
||||||
if (required.isNotEmpty()) {
|
if (required.isNotEmpty()) {
|
||||||
@ -140,9 +147,9 @@ fun main() {
|
|||||||
"children" to json {
|
"children" to json {
|
||||||
"anyOf" to jsonArray {
|
"anyOf" to jsonArray {
|
||||||
context.enumerate(VisualObject3D::class).forEach {
|
context.enumerate(VisualObject3D::class).forEach {
|
||||||
if (it.name == "hep.dataforge.vis.spatial.VisualGroup3D") {
|
if (it.serialName == "hep.dataforge.vis.spatial.VisualGroup3D") {
|
||||||
+json {
|
+json {
|
||||||
"\$ref" to "#/definitions/${it.name}"
|
"\$ref" to "#/$definitionNode/${it.serialName}"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
+jsonSchema(it, context)
|
+jsonSchema(it, context)
|
||||||
@ -150,18 +157,47 @@ fun main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"hep.dataforge.vis.spatial.Point3D" to jsonSchema(Point3DSerializer.descriptor, context)
|
"hep.dataforge.meta.Meta" to json {
|
||||||
"hep.dataforge.vis.spatial.Point2D" to jsonSchema(Point2DSerializer.descriptor, context)
|
"type" to "object"
|
||||||
"hep.dataforge.vis.spatial.VisualGroup3D" to jsonSchema(VisualGroup3D.serializer().descriptor, context)
|
}
|
||||||
|
"hep.dataforge.vis.spatial.Point3D" to json {
|
||||||
|
"type" to "object"
|
||||||
|
"properties" to json {
|
||||||
|
"x" to json {
|
||||||
|
"type" to "number"
|
||||||
|
}
|
||||||
|
"y" to json {
|
||||||
|
"type" to "number"
|
||||||
|
}
|
||||||
|
"z" to json {
|
||||||
|
"type" to "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"hep.dataforge.vis.spatial.Point2D" to json {
|
||||||
|
"type" to "object"
|
||||||
|
"properties" to json {
|
||||||
|
"x" to json {
|
||||||
|
"type" to "number"
|
||||||
|
}
|
||||||
|
"y" to json {
|
||||||
|
"type" to "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"hep.dataforge.vis.spatial.VisualGroup3D" to jsonSchema(
|
||||||
|
VisualGroup3D.serializer().descriptor,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println(
|
println(
|
||||||
Json.indented.stringify(
|
JSON_PRETTY.stringify(
|
||||||
JsonObjectSerializer,
|
JsonObjectSerializer,
|
||||||
json {
|
json {
|
||||||
"definitions" to definitions
|
"\$defs" to definitions
|
||||||
"\$ref" to "#/definitions/hep.dataforge.vis.spatial.VisualGroup3D"
|
"\$ref" to "#/$definitionNode/hep.dataforge.vis.spatial.VisualGroup3D"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
@ -1,11 +1,15 @@
|
|||||||
import org.openjfx.gradle.JavaFXOptions
|
import scientifik.DependencyConfiguration
|
||||||
|
import scientifik.FXModule
|
||||||
|
import scientifik.fx
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("scientifik.mpp")
|
id("scientifik.mpp")
|
||||||
id("org.openjfx.javafxplugin")
|
|
||||||
id("application")
|
id("application")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val fxVersion: String by rootProject.extra
|
||||||
|
fx(FXModule.CONTROLS, version = fxVersion, configuration = DependencyConfiguration.IMPLEMENTATION)
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
|
||||||
jvm {
|
jvm {
|
||||||
@ -27,11 +31,6 @@ kotlin {
|
|||||||
api(project(":dataforge-vis-spatial-gdml"))
|
api(project(":dataforge-vis-spatial-gdml"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmMain{
|
|
||||||
dependencies {
|
|
||||||
api("org.fxyz3d:fxyz3d:0.5.2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +38,8 @@ application {
|
|||||||
mainClassName = "hep.dataforge.vis.spatial.gdml.demo.GDMLDemoAppKt"
|
mainClassName = "hep.dataforge.vis.spatial.gdml.demo.GDMLDemoAppKt"
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<JavaFXOptions> {
|
val convertGdmlToJson by tasks.creating(JavaExec::class) {
|
||||||
modules("javafx.controls")
|
group = "application"
|
||||||
|
classpath = sourceSets["main"].runtimeClasspath
|
||||||
|
main = "hep.dataforge.vis.spatial.gdml.demo.SaveToJsonKt"
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user