forked from kscience/visionforge
New styling design
This commit is contained in:
parent
c5f14fb5e7
commit
2fcfd767c1
@ -21,6 +21,7 @@ abstract class AbstractVisualGroup : AbstractVisualObject(), VisualGroup {
|
||||
*/
|
||||
abstract override val children: Map<NameToken, VisualObject> //get() = _children
|
||||
|
||||
|
||||
// init {
|
||||
// //Do after deserialization
|
||||
// children.values.forEach {
|
||||
|
@ -1,8 +1,10 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.EmptyName
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.vis.common.VisualObject.Companion.STYLE_KEY
|
||||
import kotlinx.serialization.Transient
|
||||
|
||||
internal data class PropertyListener(
|
||||
@ -15,17 +17,21 @@ abstract class AbstractVisualObject : VisualObject {
|
||||
@Transient
|
||||
override var parent: VisualObject? = null
|
||||
|
||||
override var style: Meta? = null
|
||||
protected abstract var properties: Config?
|
||||
|
||||
override var style: List<String>
|
||||
get() = properties?.let { it[STYLE_KEY].stringList } ?: emptyList()
|
||||
set(value) {
|
||||
//notify about style removed
|
||||
style?.items?.forEach {(name, value) ->
|
||||
propertyChanged(name.asName(), value, null)
|
||||
}
|
||||
field = value
|
||||
//notify about style adition
|
||||
value?.items?.forEach { (name, value) ->
|
||||
propertyChanged(name.asName(), null, value)
|
||||
setProperty(VisualObject.STYLE_KEY, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* The config is initialized and assigned on-demand.
|
||||
* To avoid unnecessary allocations, one should access [properties] via [getProperty] instead.
|
||||
*/
|
||||
override val config: Config
|
||||
get() = properties ?: Config().also { config ->
|
||||
properties = config.apply { onChange(this, ::propertyChanged) }
|
||||
}
|
||||
|
||||
@Transient
|
||||
@ -45,22 +51,32 @@ abstract class AbstractVisualObject : VisualObject {
|
||||
listeners.removeAll { it.owner == owner }
|
||||
}
|
||||
|
||||
protected abstract var properties: Config?
|
||||
|
||||
override val config: Config
|
||||
get() = properties ?: Config().also { config ->
|
||||
properties = config.apply { onChange(this, ::propertyChanged) }
|
||||
}
|
||||
|
||||
override fun setProperty(name: Name, value: Any?) {
|
||||
config[name] = value
|
||||
}
|
||||
|
||||
private var styleCache: Laminate? = null
|
||||
|
||||
private fun styles(): Laminate {
|
||||
return styleCache ?: kotlin.run {
|
||||
Laminate(style.map { it.toName() }.mapNotNull(::findStyle))
|
||||
.also { styleCache = it }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to reset style cache
|
||||
*/
|
||||
protected fun styleChanged() {
|
||||
styleCache = null
|
||||
propertyChanged(EmptyName)
|
||||
}
|
||||
|
||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||
return if (inherit) {
|
||||
style?.get(name) ?: properties?.get(name) ?: parent?.getProperty(name, inherit)
|
||||
properties?.get(name) ?: parent?.getProperty(name, inherit) ?: styles()[name]
|
||||
} else {
|
||||
style?.get(name) ?: properties?.get(name)
|
||||
properties?.get(name) ?: styles()[name]
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,3 +88,11 @@ abstract class AbstractVisualObject : VisualObject {
|
||||
updateMeta()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun VisualObject.findStyle(styleName: Name): Meta? {
|
||||
if (this is VisualGroup) {
|
||||
val style = getStyle(styleName)
|
||||
if (style != null) return style
|
||||
}
|
||||
return parent?.findStyle(styleName)
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* Taken from https://github.com/markaren/three.kt/blob/master/threejs-wrapper/src/main/kotlin/info/laht/threekt/math/ColorConstants.kt
|
||||
*/
|
||||
@ -177,6 +179,6 @@ object Colors {
|
||||
|
||||
fun rgbToString(rgb: Int): String {
|
||||
val string = rgb.toString(16)
|
||||
return "#" + string.substring(string.length - 6)
|
||||
return "#" + string.substring(max(0, string.length - 6))
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.provider.Provider
|
||||
|
||||
@ -11,17 +12,18 @@ interface VisualGroup : VisualObject, Provider, Iterable<VisualObject> {
|
||||
|
||||
override val defaultTarget: String get() = VisualObject.TYPE
|
||||
|
||||
override fun provideTop(target: String): Map<Name, VisualObject> = if (target == VisualObject.TYPE) {
|
||||
children.flatMap { (key, value) ->
|
||||
val res: Map<Name, VisualObject> = if (value is VisualGroup) {
|
||||
override fun provideTop(target: String): Map<Name, Any> =
|
||||
when (target) {
|
||||
VisualObject.TYPE -> children.flatMap { (key, value) ->
|
||||
val res: Map<Name, Any> = if (value is VisualGroup) {
|
||||
value.provideTop(target).mapKeys { key + it.key }
|
||||
} else {
|
||||
mapOf(key.asName() to value)
|
||||
}
|
||||
res.entries
|
||||
}.associate { it.toPair() }
|
||||
} else {
|
||||
emptyMap()
|
||||
//TODO add styles
|
||||
else -> emptyMap()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,7 +32,20 @@ interface VisualGroup : VisualObject, Provider, Iterable<VisualObject> {
|
||||
override fun iterator(): Iterator<VisualObject> = children.values.iterator()
|
||||
|
||||
/**
|
||||
* Add listener for children change
|
||||
* Resolve style by its name
|
||||
* TODO change to Config?
|
||||
*/
|
||||
fun getStyle(name: Name): Meta?
|
||||
|
||||
/**
|
||||
* Add or replace style with given name
|
||||
*/
|
||||
fun setStyle(name: Name, meta: Meta)
|
||||
|
||||
/**
|
||||
* Add listener for children structure change.
|
||||
* @param owner the handler to properly remove listeners
|
||||
* @param action First argument of the action is the name of changed child. Second argument is the new value of the object.
|
||||
*/
|
||||
fun onChildrenChange(owner: Any?, action: (Name, VisualObject?) -> Unit)
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.meta.Configurable
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.meta.MetaRepr
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.VisualObject.Companion.TYPE
|
||||
import kotlinx.serialization.Transient
|
||||
|
||||
private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
||||
private fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
||||
//private fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
|
||||
//private fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
|
||||
|
||||
/**
|
||||
* A root type for display hierarchy
|
||||
@ -22,11 +25,6 @@ interface VisualObject : MetaRepr, Configurable {
|
||||
@Transient
|
||||
var parent: VisualObject?
|
||||
|
||||
/**
|
||||
* A style which is set externally and could not be modified from inside
|
||||
*/
|
||||
var style: Meta?
|
||||
|
||||
/**
|
||||
* Set property for this object
|
||||
*/
|
||||
@ -52,8 +50,11 @@ interface VisualObject : MetaRepr, Configurable {
|
||||
*/
|
||||
fun removeChangeListener(owner: Any?)
|
||||
|
||||
var style: List<String>
|
||||
|
||||
companion object {
|
||||
const val TYPE = "visual"
|
||||
val STYLE_KEY = "style".asName()
|
||||
|
||||
//const val META_KEY = "@meta"
|
||||
//const val TAGS_KEY = "@tags"
|
||||
@ -62,4 +63,3 @@ interface VisualObject : MetaRepr, Configurable {
|
||||
|
||||
fun VisualObject.getProperty(key: String, inherit: Boolean = true): MetaItem<*>? = getProperty(key.toName(), inherit)
|
||||
fun VisualObject.setProperty(key: String, value: Any?) = setProperty(key.toName(), value)
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package hep.dataforge.vis.common
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.EmptyName
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.asName
|
||||
@ -11,12 +10,11 @@ import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun String.asName() = if (isBlank()) EmptyName else NameToken(this).asName()
|
||||
|
||||
/**
|
||||
* A delegate for display object properties
|
||||
*/
|
||||
class DisplayObjectDelegate(
|
||||
class VisualObjectDelegate(
|
||||
val key: Name?,
|
||||
val default: MetaItem<*>?,
|
||||
val inherited: Boolean
|
||||
@ -36,7 +34,7 @@ class DisplayObjectDelegate(
|
||||
}
|
||||
}
|
||||
|
||||
class DisplayObjectDelegateWrapper<T>(
|
||||
class VisualObjectDelegateWrapper<T>(
|
||||
val key: Name?,
|
||||
val default: T,
|
||||
val inherited: Boolean,
|
||||
@ -63,55 +61,55 @@ class DisplayObjectDelegateWrapper<T>(
|
||||
|
||||
|
||||
fun VisualObject.value(default: Value? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.value }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.value }
|
||||
|
||||
fun VisualObject.string(default: String? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
|
||||
fun VisualObject.boolean(default: Boolean? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
|
||||
fun VisualObject.number(default: Number? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
|
||||
fun VisualObject.double(default: Double? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
|
||||
fun VisualObject.int(default: Int? = null, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
|
||||
|
||||
fun VisualObject.node(key: String? = null, inherited: Boolean = true) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), null, inherited) { it.node }
|
||||
VisualObjectDelegateWrapper(key?.asName(), null, inherited) { it.node }
|
||||
|
||||
fun VisualObject.item(key: String? = null, inherited: Boolean = true) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), null, inherited) { it }
|
||||
VisualObjectDelegateWrapper(key?.asName(), null, inherited) { it }
|
||||
|
||||
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
|
||||
|
||||
@JvmName("safeString")
|
||||
fun VisualObject.string(default: String, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.string }
|
||||
|
||||
@JvmName("safeBoolean")
|
||||
fun VisualObject.boolean(default: Boolean, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.boolean }
|
||||
|
||||
@JvmName("safeNumber")
|
||||
fun VisualObject.number(default: Number, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.number }
|
||||
|
||||
@JvmName("safeDouble")
|
||||
fun VisualObject.double(default: Double, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.double }
|
||||
|
||||
@JvmName("safeInt")
|
||||
fun VisualObject.int(default: Int, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
VisualObjectDelegateWrapper(key?.asName(), default, inherited) { it.int }
|
||||
|
||||
|
||||
inline fun <reified E : Enum<E>> VisualObject.enum(default: E, key: String? = null, inherited: Boolean = false) =
|
||||
DisplayObjectDelegateWrapper(
|
||||
VisualObjectDelegateWrapper(
|
||||
key?.let { NameToken(it).asName() },
|
||||
default,
|
||||
inherited
|
@ -1,8 +1,8 @@
|
||||
package hep.dataforge.vis.spatial.gdml
|
||||
|
||||
import hep.dataforge.names.EmptyName
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.vis.common.asName
|
||||
import hep.dataforge.vis.common.get
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import scientifik.gdml.*
|
||||
|
@ -5,6 +5,7 @@ package hep.dataforge.vis.spatial
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.io.NameSerializer
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.MetaItem
|
||||
import hep.dataforge.names.Name
|
||||
@ -37,6 +38,11 @@ class Proxy(val templateName: Name) : AbstractVisualObject(), VisualGroup, Visua
|
||||
get() = (parent as? VisualGroup3D)?.getTemplate(templateName)
|
||||
?: error("Template with name $templateName not found in $parent")
|
||||
|
||||
override fun getStyle(name: Name): Meta? = null
|
||||
|
||||
override fun setStyle(name: Name, meta: Meta) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? {
|
||||
return if (inherit) {
|
||||
|
@ -1,21 +1,29 @@
|
||||
@file:UseSerializers(Point3DSerializer::class, ConfigSerializer::class, NameTokenSerializer::class)
|
||||
@file:UseSerializers(
|
||||
Point3DSerializer::class,
|
||||
ConfigSerializer::class,
|
||||
NameTokenSerializer::class,
|
||||
NameSerializer::class
|
||||
)
|
||||
|
||||
package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.io.ConfigSerializer
|
||||
import hep.dataforge.io.NameSerializer
|
||||
import hep.dataforge.meta.Config
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.meta.set
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.isEmpty
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.vis.common.AbstractVisualGroup
|
||||
import hep.dataforge.vis.common.AbstractVisualObject
|
||||
import hep.dataforge.vis.common.VisualGroup
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
import kotlin.collections.set
|
||||
|
||||
@Serializable
|
||||
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
||||
@ -28,8 +36,34 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D {
|
||||
field = value
|
||||
}
|
||||
|
||||
//FIXME to be lifted to AbstractVisualGroup after https://github.com/Kotlin/kotlinx.serialization/issues/378 is fixed
|
||||
public override var properties: Config? = null
|
||||
|
||||
private val styles = HashMap<Name, Meta>()
|
||||
|
||||
override fun getStyle(name: Name): Meta? = styles[name]
|
||||
|
||||
override fun setStyle(name: Name, meta: Meta) {
|
||||
fun VisualObject.applyStyle(name: Name, meta: Meta) {
|
||||
if (style.contains(name.toString())) {
|
||||
//full update
|
||||
//TODO do a fine grained update
|
||||
if(this is AbstractVisualObject){
|
||||
styleChanged()
|
||||
} else {
|
||||
propertyChanged(EmptyName)
|
||||
}
|
||||
}
|
||||
if (this is VisualGroup) {
|
||||
this.children.forEach { (_, child) ->
|
||||
child.applyStyle(name, meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
styles[name] = meta
|
||||
applyStyle(name, meta)
|
||||
}
|
||||
|
||||
override var position: Point3D? = null
|
||||
override var rotation: Point3D? = null
|
||||
override var scale: Point3D? = null
|
||||
@ -96,7 +130,7 @@ fun VisualGroup.attachChildren() {
|
||||
it.parent = this
|
||||
(it as? VisualGroup)?.attachChildren()
|
||||
}
|
||||
if(this is VisualGroup3D){
|
||||
if (this is VisualGroup3D) {
|
||||
templates?.apply {
|
||||
parent = this@attachChildren
|
||||
attachChildren()
|
||||
|
@ -4,11 +4,11 @@ package hep.dataforge.vis.spatial
|
||||
|
||||
import hep.dataforge.io.NameSerializer
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.output.Output
|
||||
import hep.dataforge.vis.common.Colors.rgbToString
|
||||
import hep.dataforge.vis.common.VisualObject
|
||||
import hep.dataforge.vis.common.asName
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.DETAIL_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.LAYER_KEY
|
||||
import hep.dataforge.vis.spatial.VisualObject3D.Companion.MATERIAL_KEY
|
||||
|
@ -2,10 +2,10 @@ package hep.dataforge.vis.spatial.three
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.meta.node
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.names.plus
|
||||
import hep.dataforge.names.startsWith
|
||||
import hep.dataforge.provider.Type
|
||||
import hep.dataforge.vis.common.asName
|
||||
import hep.dataforge.vis.spatial.*
|
||||
import hep.dataforge.vis.spatial.three.ThreeFactory.Companion.TYPE
|
||||
import info.laht.threekt.core.BufferGeometry
|
||||
|
Loading…
Reference in New Issue
Block a user