Cleanup groups

This commit is contained in:
Alexander Nozik 2020-04-12 10:44:35 +03:00
parent e19ec02ff3
commit ca985a6a66
8 changed files with 105 additions and 51 deletions

View File

@ -11,8 +11,7 @@ import kotlinx.serialization.Transient
/** /**
* Abstract implementation of mutable group of [VisualObject] * Abstract implementation of mutable group of [VisualObject]
*/ */
abstract class AbstractVisualGroup : AbstractVisualObject(), abstract class AbstractVisualGroup : AbstractVisualObject(), MutableVisualGroup {
MutableVisualGroup {
//protected abstract val _children: MutableMap<NameToken, T> //protected abstract val _children: MutableMap<NameToken, T>
@ -21,6 +20,17 @@ abstract class AbstractVisualGroup : AbstractVisualObject(),
*/ */
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 {

View File

@ -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()
}

View File

@ -9,6 +9,7 @@ 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.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)
@ -64,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"

View File

@ -154,11 +154,10 @@ 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
@ -166,8 +165,7 @@ inline fun VisualGroup3D.ref(
fun VisualGroup3D.proxy( fun VisualGroup3D.proxy(
name: String, name: String,
obj: VisualObject3D, obj: VisualObject3D,
templateName: Name = name.toName(), templateName: Name = name.toName()
block: Proxy.() -> Unit = {}
): Proxy { ): Proxy {
val existing = getPrototype(templateName) val existing = getPrototype(templateName)
if (existing == null) { if (existing == null) {
@ -177,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)
} }

View File

@ -7,6 +7,7 @@ import hep.dataforge.context.PluginTag
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.SimpleVisualGroup
import hep.dataforge.vis.Visual import hep.dataforge.vis.Visual
import hep.dataforge.vis.VisualObject import hep.dataforge.vis.VisualObject
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -38,23 +39,26 @@ class Visual3D(meta: Meta) : AbstractPlugin(meta) {
contextual(Point2DSerializer) contextual(Point2DSerializer)
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())
subclass(Extruded.serializer())
subclass(PolyLine.serializer()) subclass(PolyLine.serializer())
subclass(Label3D.serializer()) subclass(Label3D.serializer())
subclass(Sphere.serializer())
} }
} }
val json = Json( internal val json = Json(
JsonConfiguration( JsonConfiguration(
prettyPrint = true, prettyPrint = true,
useArrayPolymorphism = false, useArrayPolymorphism = false,
encodeDefaults = false encodeDefaults = false,
ignoreUnknownKeys = true
), ),
context = serialModule context = serialModule
) )

View File

@ -27,7 +27,6 @@ interface PrototypeHolder {
class VisualGroup3D : AbstractVisualGroup(), VisualObject3D, PrototypeHolder { 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
@ -63,14 +62,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D, PrototypeHolder {
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)?.apply { parent = null } _children.remove(token)?.apply { parent = null }
} }
@ -86,20 +77,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D, PrototypeHolder {
override fun createGroup(): VisualGroup3D = 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")
@ -109,8 +86,6 @@ class VisualGroup3D : AbstractVisualGroup(), VisualObject3D, PrototypeHolder {
} }
} }
fun VisualGroup3D.stringify(): String = Visual3D.json.stringify(VisualGroup3D.serializer(),this)
/** /**
* 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
*/ */
@ -129,7 +104,11 @@ internal class Prototypes(
override var children: MutableMap<NameToken, VisualObject> = LinkedHashMap() override var children: MutableMap<NameToken, VisualObject> = LinkedHashMap()
) : AbstractVisualGroup(), MutableVisualGroup, PrototypeHolder { ) : AbstractVisualGroup(), MutableVisualGroup, PrototypeHolder {
override val styleSheet: StyleSheet? get() = null override var styleSheet: StyleSheet?
get() = null
set(value) {
error("Can't define stylesheet for prototypes block")
}
override fun removeChild(token: NameToken) { override fun removeChild(token: NameToken) {
children.remove(token) children.remove(token)
@ -140,9 +119,13 @@ internal class Prototypes(
children[token] = child children[token] = child
} }
override fun createGroup(): Prototypes = Prototypes() override fun createGroup() = SimpleVisualGroup()
override var properties: Config? = null override var properties: Config?
get() = null
set(value) {
error("Can't define properties for prototypes block")
}
override val prototypes: MutableVisualGroup get() = this override val prototypes: MutableVisualGroup get() = this

View File

@ -3,6 +3,7 @@ package hep.dataforge.vis.spatial
import hep.dataforge.meta.double import hep.dataforge.meta.double
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.vis.MutableVisualGroup import hep.dataforge.vis.MutableVisualGroup
import hep.dataforge.vis.VisualGroup
import hep.dataforge.vis.VisualObject import hep.dataforge.vis.VisualObject
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.MapSerializer
@ -98,11 +99,13 @@ object Point2DSerializer : KSerializer<Point2D> {
@Serializer(MutableVisualGroup::class) @Serializer(MutableVisualGroup::class)
internal object PrototypesSerializer : KSerializer<MutableVisualGroup> { internal object PrototypesSerializer : KSerializer<MutableVisualGroup> {
private val mapSerializer: KSerializer<Map<NameToken, VisualObject>> = private val mapSerializer: KSerializer<Map<NameToken, VisualObject>> =
MapSerializer( MapSerializer(
NameToken.serializer(), NameToken.serializer(),
PolymorphicSerializer(VisualObject::class) VisualObject.serializer()
) )
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
override fun deserialize(decoder: Decoder): MutableVisualGroup { override fun deserialize(decoder: Decoder): MutableVisualGroup {
@ -113,6 +116,12 @@ internal object PrototypesSerializer : KSerializer<MutableVisualGroup> {
override fun serialize(encoder: Encoder, value: MutableVisualGroup) { override fun serialize(encoder: Encoder, value: MutableVisualGroup) {
mapSerializer.serialize(encoder, value.children) 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()
}
} }

View File

@ -1,7 +1,8 @@
package hep.dataforge.vis.spatial package hep.dataforge.vis.spatial
import hep.dataforge.names.toName
import hep.dataforge.vis.VisualObject
import hep.dataforge.vis.get import hep.dataforge.vis.get
import hep.dataforge.vis.spatial.Visual3D.Companion.json
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -13,9 +14,9 @@ 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)
} }
@ -26,9 +27,13 @@ class SerializationTest {
x = 100 x = 100
z = -100 z = -100
} }
val group = VisualGroup3D().apply { val group = VisualGroup3D().apply {
proxy("cube", cube) proxy("cube", cube)
proxyGroup("pg", "pg.content".toName()){
sphere(50){
x = -100
}
}
} }
val string = group.stringify() val string = group.stringify()
println(string) println(string)