Visuliazation package. Multiple fixes to mutable and styled meta.

This commit is contained in:
Alexander Nozik 2019-03-01 22:10:17 +03:00
parent 48c45fa51c
commit 54b30e9260
32 changed files with 1387 additions and 246 deletions

2
.gitignore vendored
View File

@ -7,5 +7,3 @@
!gradle-wrapper.jar !gradle-wrapper.jar
artifactory.gradle

View File

@ -1,19 +1,25 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
buildscript { buildscript {
val kotlinVersion: String by rootProject.extra("1.3.20") val kotlinVersion: String by rootProject.extra("1.3.21")
val ioVersion: String by rootProject.extra("0.1.4") val ioVersion: String by rootProject.extra("0.1.5")
val coroutinesVersion: String by rootProject.extra("1.1.1") val coroutinesVersion: String by rootProject.extra("1.1.1")
val serializationVersion: String by rootProject.extra("0.9.1") val atomicfuVersion: String by rootProject.extra("0.12.1")
val dokkaVersion: String by rootProject.extra("0.9.17")
val serializationVersion: String by rootProject.extra("0.10.0")
repositories { repositories {
jcenter() jcenter()
maven("https://dl.bintray.com/kotlin/kotlin-eap")
} }
dependencies { dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion")
classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4+") classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4+")
classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4")
classpath("org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion")
classpath("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45")
classpath("org.openjfx:javafx-plugin:0.0.7")
} }
} }
@ -23,6 +29,7 @@ plugins {
} }
allprojects { allprojects {
apply(plugin = "maven")
apply(plugin = "maven-publish") apply(plugin = "maven-publish")
apply(plugin = "com.jfrog.artifactory") apply(plugin = "com.jfrog.artifactory")
@ -32,8 +39,17 @@ allprojects {
} }
group = "hep.dataforge" group = "hep.dataforge"
version = "0.1.1-dev-3" version = "0.1.1-dev-4"
// apply bintray configuration
apply(from = "${rootProject.rootDir}/gradle/bintray.gradle")
//apply artifactory configuration
apply(from = "${rootProject.rootDir}/gradle/artifactory.gradle")
}
subprojects {
extensions.findByType<KotlinMultiplatformExtension>()?.apply { extensions.findByType<KotlinMultiplatformExtension>()?.apply {
jvm { jvm {
compilations.all { compilations.all {
@ -48,8 +64,61 @@ allprojects {
} }
} }
} }
// dokka {
// outputFormat = "html"
// outputDirectory = javadoc.destinationDir
// }
//
// task dokkaJar (type: Jar, dependsOn: dokka) {
// from javadoc . destinationDir
// classifier = "javadoc"
// }
if (!name.startsWith("dataforge")) return@subprojects
extensions.findByType<PublishingExtension>()?.apply {
publications.filterIsInstance<MavenPublication>().forEach { publication ->
if (publication.name == "kotlinMultiplatform") {
// for our root metadata publication, set artifactId with a package and project name
publication.artifactId = project.name
} else {
// for targets, set artifactId with a package, project name and target name (e.g. iosX64)
publication.artifactId = "${project.name}-${publication.name}"
}
}
// Create empty jar for sources classifier to satisfy maven requirements
val stubSources by tasks.registering(Jar::class) {
archiveClassifier.set("sources")
//from(sourceSets.main.get().allSource)
}
// Create empty jar for javadoc classifier to satisfy maven requirements
val stubJavadoc by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
}
extensions.findByType<KotlinMultiplatformExtension>()?.apply {
targets.forEach { target ->
val publication = publications.findByName(target.name) as MavenPublication
// Patch publications with fake javadoc
publication.artifact(stubJavadoc)
// Remove gradle metadata publishing from all targets which are not native
// if (target.platformType.name != "native") {
// publication.gradleModuleMetadataFile = null
// tasks.matching { it.name == "generateMetadataFileFor${name.capitalize()}Publication" }.all {
// onlyIf { false }
// }
// }
}
}
}
} }
if (file("artifactory.gradle").exists()) {
apply(from = "artifactory.gradle")
}

View File

@ -2,10 +2,6 @@ plugins {
kotlin("multiplatform") kotlin("multiplatform")
} }
repositories {
jcenter()
}
kotlin { kotlin {
jvm() jvm()
js() js()

View File

@ -0,0 +1,7 @@
package hep.dataforge.meta.io
import kotlinx.io.ByteBuffer
import kotlinx.io.core.Input
//TODO replace by abstraction
typealias Binary = Input

View File

@ -0,0 +1,50 @@
package hep.dataforge.meta.io
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.string
interface Envelope {
val meta: Meta
val data: Binary?
companion object {
// /**
// * Property keys
// */
// const val TYPE_PROPERTY = "type"
// const val META_TYPE_PROPERTY = "metaType"
// const val META_LENGTH_PROPERTY = "metaLength"
// const val DATA_LENGTH_PROPERTY = "dataLength"
/**
* meta keys
*/
const val ENVELOPE_NODE = "@envelope"
const val ENVELOPE_TYPE_KEY = "$ENVELOPE_NODE.type"
const val ENVELOPE_DATA_TYPE_KEY = "$ENVELOPE_NODE.dataType"
const val ENVELOPE_DESCRIPTION_KEY = "$ENVELOPE_NODE.description"
//const val ENVELOPE_TIME_KEY = "@envelope.time"
}
}
/**
* The purpose of the envelope
*
* @return
*/
val Envelope.type: String? get() = meta[Envelope.ENVELOPE_TYPE_KEY].string
/**
* The type of data encoding
*
* @return
*/
val Envelope.dataType: String? get() = meta[Envelope.ENVELOPE_DATA_TYPE_KEY].string
/**
* Textual user friendly description
*
* @return
*/
val Envelope.description: String? get() = meta[Envelope.ENVELOPE_DESCRIPTION_KEY].string

View File

@ -1,6 +1,7 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.toName import hep.dataforge.names.toName
//TODO add validator to configuration //TODO add validator to configuration
@ -16,8 +17,14 @@ open class Config : MutableMetaNode<Config>() {
override fun wrap(name: Name, meta: Meta): Config = meta.toConfig() override fun wrap(name: Name, meta: Meta): Config = meta.toConfig()
override fun empty(): Config = Config() override fun empty(): Config = Config()
companion object {
fun empty(): Config = Config()
}
} }
operator fun Config.get(token: NameToken): MetaItem<Config>? = items[token]
fun Meta.toConfig(): Config = this as? Config ?: Config().also { builder -> fun Meta.toConfig(): Config = this as? Config ?: Config().also { builder ->
this.items.mapValues { entry -> this.items.mapValues { entry ->
val item = entry.value val item = entry.value

View File

@ -2,6 +2,7 @@ package hep.dataforge.meta
import hep.dataforge.values.Null import hep.dataforge.values.Null
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.values.asValue
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
@ -11,247 +12,348 @@ import kotlin.reflect.KProperty
//TODO add caching for sealed nodes //TODO add caching for sealed nodes
class ValueDelegate(private val key: String? = null, private val default: Value? = null) : class ValueDelegate(val meta: Meta, private val key: String? = null, private val default: Value? = null) :
ReadOnlyProperty<Metoid, Value?> { ReadOnlyProperty<Any?, Value?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Value? { override fun getValue(thisRef: Any?, property: KProperty<*>): Value? {
return thisRef.meta[key ?: property.name]?.value ?: default return meta[key ?: property.name]?.value ?: default
} }
} }
class StringDelegate(private val key: String? = null, private val default: String? = null) : class StringDelegate(val meta: Meta, private val key: String? = null, private val default: String? = null) :
ReadOnlyProperty<Metoid, String?> { ReadOnlyProperty<Any?, String?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): String? { override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
return thisRef.meta[key ?: property.name]?.string ?: default return meta[key ?: property.name]?.string ?: default
} }
} }
class BooleanDelegate(private val key: String? = null, private val default: Boolean? = null) : class BooleanDelegate(val meta: Meta, private val key: String? = null, private val default: Boolean? = null) :
ReadOnlyProperty<Metoid, Boolean?> { ReadOnlyProperty<Metoid, Boolean?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean? { override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean? {
return thisRef.meta[key ?: property.name]?.boolean ?: default return meta[key ?: property.name]?.boolean ?: default
} }
} }
class NumberDelegate(private val key: String? = null, private val default: Number? = null) : class NumberDelegate(val meta: Meta, private val key: String? = null, private val default: Number? = null) :
ReadOnlyProperty<Metoid, Number?> { ReadOnlyProperty<Any?, Number?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Number? { override fun getValue(thisRef: Any?, property: KProperty<*>): Number? {
return thisRef.meta[key ?: property.name]?.number ?: default return meta[key ?: property.name]?.number ?: default
}
//delegates for number transformation
val double get() = DelegateWrapper(this) { it?.toDouble() }
val int get() = DelegateWrapper(this) { it?.toInt() }
val short get() = DelegateWrapper(this) { it?.toShort() }
val long get() = DelegateWrapper(this) { it?.toLong() }
}
class DelegateWrapper<T, R>(val delegate: ReadOnlyProperty<Any?, T>, val reader: (T) -> R) :
ReadOnlyProperty<Any?, R> {
override fun getValue(thisRef: Any?, property: KProperty<*>): R {
return reader(delegate.getValue(thisRef, property))
} }
} }
//Delegates with non-null values //Delegates with non-null values
class SafeStringDelegate(private val key: String? = null, private val default: String) : class SafeStringDelegate(val meta: Meta, private val key: String? = null, private val default: String) :
ReadOnlyProperty<Metoid, String> { ReadOnlyProperty<Any?, String> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): String { override fun getValue(thisRef: Any?, property: KProperty<*>): String {
return thisRef.meta[key ?: property.name]?.string ?: default return meta[key ?: property.name]?.string ?: default
} }
} }
class SafeBooleanDelegate(private val key: String? = null, private val default: Boolean) : class SafeBooleanDelegate(val meta: Meta, private val key: String? = null, private val default: Boolean) :
ReadOnlyProperty<Metoid, Boolean> { ReadOnlyProperty<Any?, Boolean> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean { override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return thisRef.meta[key ?: property.name]?.boolean ?: default return meta[key ?: property.name]?.boolean ?: default
} }
} }
class SafeNumberDelegate(private val key: String? = null, private val default: Number) : class SafeNumberDelegate(val meta: Meta, private val key: String? = null, private val default: Number) :
ReadOnlyProperty<Metoid, Number> { ReadOnlyProperty<Any?, Number> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Number { override fun getValue(thisRef: Any?, property: KProperty<*>): Number {
return thisRef.meta[key ?: property.name]?.number ?: default return meta[key ?: property.name]?.number ?: default
} }
val double get() = DelegateWrapper(this) { it.toDouble() }
val int get() = DelegateWrapper(this) { it.toInt() }
val short get() = DelegateWrapper(this) { it.toShort() }
val long get() = DelegateWrapper(this) { it.toLong() }
} }
class SafeEnumDelegate<E : Enum<E>>( class SafeEnumDelegate<E : Enum<E>>(
val meta: Meta,
private val key: String? = null, private val key: String? = null,
private val default: E, private val default: E,
private val resolver: (String) -> E private val resolver: (String) -> E
) : ReadOnlyProperty<Metoid, E> { ) : ReadOnlyProperty<Any?, E> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): E { override fun getValue(thisRef: Any?, property: KProperty<*>): E {
return (thisRef.meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default return (meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default
} }
} }
//Child node delegate //Child node delegate
class ChildDelegate<T>(private val key: String? = null, private val converter: (Meta) -> T) : class ChildDelegate<T>(val meta: Meta, private val key: String? = null, private val converter: (Meta) -> T) :
ReadOnlyProperty<Metoid, T?> { ReadOnlyProperty<Any?, T?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): T? { override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
return thisRef.meta[key ?: property.name]?.node?.let { converter(it) } return meta[key ?: property.name]?.node?.let { converter(it) }
} }
} }
//Read-only delegates //Read-only delegates for Metas
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
fun Metoid.value(default: Value = Null, key: String? = null) = ValueDelegate(key, default) fun Meta.value(default: Value = Null, key: String? = null) = ValueDelegate(this, key, default)
fun Metoid.string(default: String? = null, key: String? = null) = StringDelegate(key, default) fun Meta.string(default: String? = null, key: String? = null) = StringDelegate(this, key, default)
fun Metoid.boolean(default: Boolean? = null, key: String? = null) = BooleanDelegate(key, default) fun Meta.boolean(default: Boolean? = null, key: String? = null) = BooleanDelegate(this, key, default)
fun Metoid.number(default: Number? = null, key: String? = null) = NumberDelegate(key, default) fun Meta.number(default: Number? = null, key: String? = null) = NumberDelegate(this, key, default)
fun Metoid.child(key: String? = null) = ChildDelegate(key) { it } fun Meta.child(key: String? = null) = ChildDelegate(this, key) { it }
fun <T : Metoid> Metoid.child(key: String? = null, converter: (Meta) -> T) = ChildDelegate(key, converter)
@JvmName("safeString") @JvmName("safeString")
fun Metoid.string(default: String, key: String? = null) = SafeStringDelegate(key, default) fun Meta.string(default: String, key: String? = null) = SafeStringDelegate(this, key, default)
@JvmName("safeBoolean") @JvmName("safeBoolean")
fun Metoid.boolean(default: Boolean, key: String? = null) = SafeBooleanDelegate(key, default) fun Meta.boolean(default: Boolean, key: String? = null) = SafeBooleanDelegate(this, key, default)
@JvmName("safeNumber") @JvmName("safeNumber")
fun Metoid.number(default: Number, key: String? = null) = SafeNumberDelegate(key, default) fun Meta.number(default: Number, key: String? = null) = SafeNumberDelegate(this, key, default)
inline fun <reified E : Enum<E>> Meta.enum(default: E, key: String? = null) =
SafeEnumDelegate(this, key, default) { enumValueOf(it) }
inline fun <reified E : Enum<E>> Metoid.enum(default: E, key: String? = null) =
SafeEnumDelegate(key, default) { enumValueOf(it) }
/* Config delegates */ /* Config delegates */
class ValueConfigDelegate(private val key: String? = null, private val default: Value? = null) : class ValueConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, Value?> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): Value? { private val key: String? = null,
return thisRef.config[key ?: property.name]?.value ?: default private val default: Value? = null
) : ReadWriteProperty<Any?, Value?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? {
return config[key ?: property.name]?.value ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Value?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
val name = key ?: property.name val name = key ?: property.name
if (value == null) { if (value == null) {
thisRef.config.remove(name) config.remove(name)
} else { } else {
thisRef.config[name] = value config.setValue(name, value)
} }
} }
} }
class StringConfigDelegate(private val key: String? = null, private val default: String? = null) : class StringConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, String?> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): String? { private val key: String? = null,
return thisRef.config[key ?: property.name]?.string ?: default private val default: String? = null
) : ReadWriteProperty<Any?, String?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
return config[key ?: property.name]?.string ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: String?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
thisRef.config[key ?: property.name] = value val name = key ?: property.name
if (value == null) {
config.remove(name)
} else {
config.setValue(name, value.asValue())
}
} }
} }
class BooleanConfigDelegate(private val key: String? = null, private val default: Boolean? = null) : class BooleanConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, Boolean?> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): Boolean? { private val key: String? = null,
return thisRef.config[key ?: property.name]?.boolean ?: default private val default: Boolean? = null
) : ReadWriteProperty<Any?, Boolean?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean? {
return config[key ?: property.name]?.boolean ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Boolean?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean?) {
thisRef.config[key ?: property.name] = value val name = key ?: property.name
if (value == null) {
config.remove(name)
} else {
config.setValue(name, value.asValue())
}
} }
} }
class NumberConfigDelegate(private val key: String? = null, private val default: Number? = null) : class NumberConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, Number?> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): Number? { private val key: String? = null,
return thisRef.config[key ?: property.name]?.number ?: default private val default: Number? = null
) : ReadWriteProperty<Any?, Number?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Number? {
return config[key ?: property.name]?.number ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Number?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Number?) {
thisRef.config[key ?: property.name] = value val name = key ?: property.name
if (value == null) {
config.remove(name)
} else {
config.setValue(name, value.asValue())
}
} }
val double get() = ReadWriteDelegateWrapper(this, reader = { it?.toDouble() }, writer = { it })
val int get() = ReadWriteDelegateWrapper(this, reader = { it?.toInt() }, writer = { it })
val short get() = ReadWriteDelegateWrapper(this, reader = { it?.toShort() }, writer = { it })
val long get() = ReadWriteDelegateWrapper(this, reader = { it?.toLong() }, writer = { it })
} }
//Delegates with non-null values //Delegates with non-null values
class SafeStringConfigDelegate(private val key: String? = null, private val default: String) : class SafeStringConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, String> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): String { private val key: String? = null,
return thisRef.config[key ?: property.name]?.string ?: default private val default: String
) : ReadWriteProperty<Any?, String> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String {
return config[key ?: property.name]?.string ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: String) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
thisRef.config[key ?: property.name] = value config.setValue(key ?: property.name, value.asValue())
} }
} }
class SafeBooleanConfigDelegate(private val key: String? = null, private val default: Boolean) : class SafeBooleanConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, Boolean> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): Boolean { private val key: String? = null,
return thisRef.config[key ?: property.name]?.boolean ?: default private val default: Boolean
) : ReadWriteProperty<Any?, Boolean> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return config[key ?: property.name]?.boolean ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Boolean) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
thisRef.config[key ?: property.name] = value config.setValue(key ?: property.name, value.asValue())
} }
} }
class SafeNumberConfigDelegate(private val key: String? = null, private val default: Number) : class SafeNumberConfigDelegate<M : MutableMeta<M>>(
ReadWriteProperty<Configurable, Number> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): Number { private val key: String? = null,
return thisRef.config[key ?: property.name]?.number ?: default private val default: Number
) : ReadWriteProperty<Any?, Number> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Number {
return config[key ?: property.name]?.number ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Number) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Number) {
thisRef.config[key ?: property.name] = value config.setValue(key ?: property.name, value.asValue())
} }
val double get() = ReadWriteDelegateWrapper(this, reader = { it.toDouble() }, writer = { it })
val int get() = ReadWriteDelegateWrapper(this, reader = { it.toInt() }, writer = { it })
val short get() = ReadWriteDelegateWrapper(this, reader = { it.toShort() }, writer = { it })
val long get() = ReadWriteDelegateWrapper(this, reader = { it.toLong() }, writer = { it })
} }
class SafeEnumvConfigDelegate<E : Enum<E>>( class SafeEnumvConfigDelegate<M : MutableMeta<M>, E : Enum<E>>(
val config: M,
private val key: String? = null, private val key: String? = null,
private val default: E, private val default: E,
private val resolver: (String) -> E private val resolver: (String) -> E
) : ReadWriteProperty<Configurable, E> { ) : ReadWriteProperty<Any?, E> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): E { override fun getValue(thisRef: Any?, property: KProperty<*>): E {
return (thisRef.config[key ?: property.name]?.string)?.let { resolver(it) } ?: default return (config[key ?: property.name]?.string)?.let { resolver(it) } ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: E) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: E) {
thisRef.config[key ?: property.name] = value.name config.setValue(key ?: property.name, value.name.asValue())
} }
} }
//Child node delegate //Child node delegate
class ChildConfigDelegate<T : Configurable>(private val key: String? = null, private val converter: (Config) -> T) : class MetaNodeDelegate<M : MutableMetaNode<M>>(
ReadWriteProperty<Configurable, T> { val config: M,
override fun getValue(thisRef: Configurable, property: KProperty<*>): T { private val key: String? = null
return converter(thisRef.config[key ?: property.name]?.node ?: Config()) ) : ReadWriteProperty<Any?, Meta> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta {
return config[key ?: property.name]?.node ?: EmptyMeta
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: T) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta) {
thisRef.config[key ?: property.name] = value.config config[key ?: property.name] = value
} }
} }
class ChildConfigDelegate<M : MutableMetaNode<M>, T : Configurable>(
val config: M,
private val key: String? = null,
private val converter: (Meta) -> T
) :
ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return converter(config[key ?: property.name]?.node ?: EmptyMeta)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
config[key ?: property.name] = value.config
}
}
class ReadWriteDelegateWrapper<T, R>(
val delegate: ReadWriteProperty<Any?, T>,
val reader: (T) -> R,
val writer: (R) -> T
) : ReadWriteProperty<Any?, R> {
override fun getValue(thisRef: Any?, property: KProperty<*>): R {
return reader(delegate.getValue(thisRef, property))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) {
delegate.setValue(thisRef, property, writer(value))
}
}
//Read-write delegates //Read-write delegates
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
fun Configurable.value(default: Value = Null, key: String? = null) = ValueConfigDelegate(key, default) fun <M : MutableMeta<M>> M.value(default: Value = Null, key: String? = null) =
ValueConfigDelegate(this, key, default)
fun Configurable.string(default: String? = null, key: String? = null) = StringConfigDelegate(key, default) fun <M : MutableMeta<M>> M.string(default: String? = null, key: String? = null) =
StringConfigDelegate(this, key, default)
fun Configurable.boolean(default: Boolean? = null, key: String? = null) = BooleanConfigDelegate(key, default) fun <M : MutableMeta<M>> M.boolean(default: Boolean? = null, key: String? = null) =
BooleanConfigDelegate(this, key, default)
fun Configurable.number(default: Number? = null, key: String? = null) = NumberConfigDelegate(key, default) fun <M : MutableMeta<M>> M.number(default: Number? = null, key: String? = null) =
NumberConfigDelegate(this, key, default)
fun Configurable.child(key: String? = null) = ChildConfigDelegate(key) { SimpleConfigurable(it) } fun <M : MutableMetaNode<M>> M.child(key: String? = null) = MetaNodeDelegate(this, key)
fun <T : Configurable> Configurable.child(key: String? = null, converter: (Config) -> T) =
ChildConfigDelegate(key, converter)
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) } //fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
@JvmName("safeString") @JvmName("safeString")
fun Configurable.string(default: String, key: String? = null) = SafeStringConfigDelegate(key, default) fun <M : MutableMeta<M>> M.string(default: String, key: String? = null) =
SafeStringConfigDelegate(this, key, default)
@JvmName("safeBoolean") @JvmName("safeBoolean")
fun Configurable.boolean(default: Boolean, key: String? = null) = SafeBooleanConfigDelegate(key, default) fun <M : MutableMeta<M>> M.boolean(default: Boolean, key: String? = null) =
SafeBooleanConfigDelegate(this, key, default)
@JvmName("safeNumber") @JvmName("safeNumber")
fun Configurable.number(default: Number, key: String? = null) = SafeNumberConfigDelegate(key, default) fun <M : MutableMeta<M>> M.number(default: Number, key: String? = null) =
SafeNumberConfigDelegate(this, key, default)
inline fun <reified E : Enum<E>> Configurable.enum(default: E, key: String? = null) = inline fun <M : MutableMeta<M>, reified E : Enum<E>> M.enum(default: E, key: String? = null) =
SafeEnumvConfigDelegate(key, default) { enumValueOf(it) } SafeEnumvConfigDelegate(this, key, default) { enumValueOf(it) }

View File

@ -0,0 +1,36 @@
package hep.dataforge.meta
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/*
* Extra delegates for special cases
*/
/**
* A delegate for a string list
*/
class StringListConfigDelegate(
val config: Config,
private val key: String? = null,
private val default: List<String> = emptyList()
) :
ReadWriteProperty<Any?, List<String>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): List<String> {
return config[key ?: property.name]?.value?.list?.map { it.string } ?: default
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<String>) {
val name = key ?: property.name
config[name] = value
}
}
fun Configurable.stringList(vararg default: String = emptyArray(), key: String? = null) =
StringListConfigDelegate(config, key, default.toList())
fun <T : Metoid> Metoid.child(key: String? = null, converter: (Meta) -> T) = ChildDelegate(meta, key, converter)
fun <T : Configurable> Configurable.child(key: String? = null, converter: (Meta) -> T) =
ChildConfigDelegate(config, key, converter)

View File

@ -3,7 +3,7 @@ package hep.dataforge.meta
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
/** /**
* A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [StyledConfig]. * A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Styled].
* *
* *
*/ */

View File

@ -102,21 +102,26 @@ operator fun Meta.iterator(): Iterator<Pair<Name, Value>> = asValueSequence().it
/** /**
* A meta node that ensures that all of its descendants has at least the same type * A meta node that ensures that all of its descendants has at least the same type
*/ */
abstract class MetaNode<M : MetaNode<M>> : Meta { interface MetaNode<M : MetaNode<M>> : Meta {
abstract override val items: Map<NameToken, MetaItem<M>> override val items: Map<NameToken, MetaItem<M>>
}
operator fun get(name: Name): MetaItem<M>? { operator fun <M : MetaNode<M>> MetaNode<M>.get(name: Name): MetaItem<M>? {
return name.first()?.let { token -> return name.first()?.let { token ->
val tail = name.cutFirst() val tail = name.cutFirst()
when (tail.length) { when (tail.length) {
0 -> items[token] 0 -> items[token]
else -> items[token]?.node?.get(tail) else -> items[token]?.node?.get(tail)
}
} }
} }
}
operator fun get(key: String): MetaItem<M>? = get(key.toName()) operator fun <M : MetaNode<M>> MetaNode<M>.get(key: String): MetaItem<M>? = get(key.toName())
/**
* Equals and hash code implementation for meta node
*/
abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M> {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is Meta) return false if (other !is Meta) return false
@ -134,7 +139,8 @@ abstract class MetaNode<M : MetaNode<M>> : Meta {
* *
* If the argument is possibly mutable node, it is copied on creation * If the argument is possibly mutable node, it is copied on creation
*/ */
class SealedMeta internal constructor(override val items: Map<NameToken, MetaItem<SealedMeta>>) : MetaNode<SealedMeta>() class SealedMeta internal constructor(override val items: Map<NameToken, MetaItem<SealedMeta>>) :
AbstractMetaNode<SealedMeta>()
/** /**
* Generate sealed node from [this]. If it is already sealed return it as is * Generate sealed node from [this]. If it is already sealed return it as is
@ -154,17 +160,19 @@ object EmptyMeta : Meta {
* Unsafe methods to access values and nodes directly from [MetaItem] * Unsafe methods to access values and nodes directly from [MetaItem]
*/ */
val MetaItem<*>.value val MetaItem<*>?.value
get() = (this as? MetaItem.ValueItem)?.value get() = (this as? MetaItem.ValueItem)?.value
?: (this.node[VALUE_KEY] as? MetaItem.ValueItem)?.value ?: (this?.node?.get(VALUE_KEY) as? MetaItem.ValueItem)?.value
?: error("Trying to interpret node meta item as value item")
val MetaItem<*>.string get() = value.string val MetaItem<*>?.string get() = value?.string
val MetaItem<*>.boolean get() = value.boolean val MetaItem<*>?.boolean get() = value?.boolean
val MetaItem<*>.number get() = value.number val MetaItem<*>?.number get() = value?.number
val MetaItem<*>.double get() = number.toDouble() val MetaItem<*>?.double get() = number?.toDouble()
val MetaItem<*>.int get() = number.toInt() val MetaItem<*>?.int get() = number?.toInt()
val MetaItem<*>.long get() = number.toLong() val MetaItem<*>?.long get() = number?.toLong()
val MetaItem<*>.short get() = number.toShort() val MetaItem<*>?.short get() = number?.toShort()
val MetaItem<*>?.stringList get() = value?.list?.map { it.string } ?: emptyList()
val <M : Meta> MetaItem<M>.node: M val <M : Meta> MetaItem<M>.node: M
get() = when (this) { get() = when (this) {

View File

@ -6,19 +6,17 @@ import hep.dataforge.names.plus
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.values.Value import hep.dataforge.values.Value
class MetaListener( internal data class MetaListener(
val owner: Any? = null, val owner: Any? = null,
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
) { )
operator fun invoke(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) = action(name, oldItem, newItem)
}
interface MutableMeta<M : MutableMeta<M>> : Meta { interface MutableMeta<M : MutableMeta<M>> : MetaNode<M> {
override val items: Map<NameToken, MetaItem<M>> override val items: Map<NameToken, MetaItem<M>>
operator fun set(name: Name, item: MetaItem<M>?) operator fun set(name: Name, item: MetaItem<M>?)
fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
fun removeListener(owner: Any) fun removeListener(owner: Any? = null)
} }
/** /**
@ -26,7 +24,7 @@ interface MutableMeta<M : MutableMeta<M>> : Meta {
* *
* Changes in Meta are not thread safe. * Changes in Meta are not thread safe.
*/ */
abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableMeta<M> { abstract class MutableMetaNode<M : MutableMetaNode<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
private val listeners = HashSet<MetaListener>() private val listeners = HashSet<MetaListener>()
/** /**
@ -39,7 +37,7 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
/** /**
* Remove all listeners belonging to given owner * Remove all listeners belonging to given owner
*/ */
override fun removeListener(owner: Any) { override fun removeListener(owner: Any?) {
listeners.removeAll { it.owner === owner } listeners.removeAll { it.owner === owner }
} }
@ -49,7 +47,7 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
get() = _items get() = _items
protected fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) { protected fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) {
listeners.forEach { it(name, oldItem, newItem) } listeners.forEach { it.action(name, oldItem, newItem) }
} }
protected open fun replaceItem(key: NameToken, oldItem: MetaItem<M>?, newItem: MetaItem<M>?) { protected open fun replaceItem(key: NameToken, oldItem: MetaItem<M>?, newItem: MetaItem<M>?) {
@ -72,12 +70,12 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
* @param name the name of the node where meta should be attached. Needed for correct assignment validators and styles * @param name the name of the node where meta should be attached. Needed for correct assignment validators and styles
* @param meta the node itself * @param meta the node itself
*/ */
abstract fun wrap(name: Name, meta: Meta): M internal abstract fun wrap(name: Name, meta: Meta): M
/** /**
* Create empty node * Create empty node
*/ */
abstract fun empty(): M internal abstract fun empty(): M
override operator fun set(name: Name, item: MetaItem<M>?) { override operator fun set(name: Name, item: MetaItem<M>?) {
when (name.length) { when (name.length) {
@ -95,20 +93,22 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
} }
} }
} }
} }
fun <M : MutableMeta<M>> M.remove(name: Name) = set(name, null) fun <M : MutableMeta<M>> MutableMeta<M>.remove(name: Name) = set(name, null)
fun <M : MutableMeta<M>> M.remove(name: String) = remove(name.toName()) fun <M : MutableMeta<M>> MutableMeta<M>.remove(name: String) = remove(name.toName())
fun <M : MutableMeta<M>> M.setValue(name: Name, value: Value) = set(name, MetaItem.ValueItem(value)) fun <M : MutableMeta<M>> MutableMeta<M>.setValue(name: Name, value: Value) = set(name, MetaItem.ValueItem(value))
fun <M : MutableMeta<M>> M.setItem(name: String, item: MetaItem<M>) = set(name.toName(), item) fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: String, item: MetaItem<M>) = set(name.toName(), item)
fun <M : MutableMeta<M>> M.setValue(name: String, value: Value) = set(name.toName(), MetaItem.ValueItem(value)) fun <M : MutableMeta<M>> MutableMeta<M>.setValue(name: String, value: Value) =
fun <M : MutableMeta<M>> M.setItem(token: NameToken, item: MetaItem<M>?) = set(token.toName(), item) set(name.toName(), MetaItem.ValueItem(value))
fun <M : MutableMetaNode<M>> M.setNode(name: Name, node: Meta) = set(name, MetaItem.NodeItem(wrap(name, node))) fun <M : MutableMeta<M>> MutableMeta<M>.setItem(token: NameToken, item: MetaItem<M>?) = set(token.toName(), item)
fun <M : MutableMetaNode<M>> M.setNode(name: String, node: Meta) = setNode(name.toName(), node)
fun <M : MutableMetaNode<M>> MutableMetaNode<M>.setNode(name: Name, node: Meta) =
set(name, MetaItem.NodeItem(wrap(name, node)))
fun <M : MutableMetaNode<M>> MutableMetaNode<M>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
/** /**
* Universal set method * Universal set method
@ -116,6 +116,10 @@ fun <M : MutableMetaNode<M>> M.setNode(name: String, node: Meta) = setNode(name.
operator fun <M : MutableMetaNode<M>> M.set(name: Name, value: Any?) { operator fun <M : MutableMetaNode<M>> M.set(name: Name, value: Any?) {
when (value) { when (value) {
null -> remove(name) null -> remove(name)
is MetaItem<*> -> when (value) {
is MetaItem.ValueItem<*> -> setValue(name, value.value)
is MetaItem.NodeItem<*> -> setNode(name, value.node)
}
is Meta -> setNode(name, value) is Meta -> setNode(name, value)
else -> setValue(name, Value.of(value)) else -> setValue(name, Value.of(value))
} }

View File

@ -55,5 +55,8 @@ fun <C : Specification, S : SpecificationCompanion<C>> S.createStyle(action: C.(
Config().also { update(it, action) } Config().also { update(it, action) }
fun <C : Specification> Specification.spec(spec: SpecificationCompanion<C>, key: String? = null) = fun <M : MutableMetaNode<M>, C : Specification> Specification.spec(
ChildConfigDelegate<C>(key) { spec.wrap(config) } spec: SpecificationCompanion<C>,
key: String? = null
) =
ChildConfigDelegate(config, key) { spec.wrap(config) }

View File

@ -1,68 +0,0 @@
package hep.dataforge.meta
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import hep.dataforge.names.toName
/**
* A configuration decorator with applied style
*/
class StyledConfig(val config: Config, style: Meta = EmptyMeta) : Config() {
var style: Meta = style
set(value) {
field.items.forEach {
itemChanged(it.key.toName(), it.value, null)
}
field = value
value.items.forEach {
itemChanged(it.key.toName(), null, it.value)
}
}
init {
config.onChange { name, oldItem, newItem -> this.itemChanged(name, oldItem, newItem) }
}
override fun set(name: Name, item: MetaItem<Config>?) {
when (item) {
null -> config.remove(name)
is MetaItem.ValueItem -> config.setValue(name, item.value)
is MetaItem.NodeItem -> config.setNode(name, item.node)
}
}
override val items: Map<NameToken, MetaItem<Config>>
get() = (config.items.keys + style.items.keys).associate { key ->
val value = config.items[key]
val styleValue = style[key]
val item: MetaItem<Config> = when (value) {
null -> when (styleValue) {
null -> error("Should be unreachable")
is MetaItem.ValueItem -> MetaItem.ValueItem(styleValue.value)
is MetaItem.NodeItem -> MetaItem.NodeItem<Config>(StyledConfig(config.empty(), styleValue.node))
}
is MetaItem.ValueItem -> MetaItem.ValueItem(value.value)
is MetaItem.NodeItem -> MetaItem.NodeItem(
StyledConfig(value.node, styleValue?.node ?: EmptyMeta)
)
}
key to item
}
}
fun Config.withStyle(style: Meta = EmptyMeta) = if (this is StyledConfig) {
StyledConfig(this.config, style)
} else {
StyledConfig(this, style)
}
interface Styleable : Configurable {
override val config: StyledConfig
var style
get() = config.style
set(value) {
config.style = value
}
}

View File

@ -0,0 +1,68 @@
package hep.dataforge.meta
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* A meta object with read-only meta base and changeable configuration on top of it
* @param base - unchangeable base
* @param style - the style
*/
class Styled(val base: Meta, val style: Config = Config().empty()) : MutableMeta<Styled> {
override val items: Map<NameToken, MetaItem<Styled>>
get() = (base.items.keys + style.items.keys).associate { key ->
val value = base.items[key]
val styleValue = style[key]
val item: MetaItem<Styled> = when (value) {
null -> when (styleValue) {
null -> error("Should be unreachable")
is MetaItem.ValueItem -> MetaItem.ValueItem(styleValue.value)
is MetaItem.NodeItem -> MetaItem.NodeItem(Styled(style.empty(), styleValue.node))
}
is MetaItem.ValueItem -> MetaItem.ValueItem(value.value)
is MetaItem.NodeItem -> MetaItem.NodeItem(
Styled(value.node, styleValue?.node ?: Config.empty())
)
}
key to item
}
override fun set(name: Name, item: MetaItem<Styled>?) {
if (item == null) {
style.remove(name)
} else {
style.set(name, item)
}
}
override fun onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) {
//TODO test correct behavior
style.onChange(owner) { name, before, after -> action(name, before ?: base[name], after ?: base[name]) }
}
override fun removeListener(owner: Any?) {
style.removeListener(owner)
}
}
fun Styled.configure(meta: Meta) = apply { style.update(style) }
fun Meta.withStyle(style: Meta = EmptyMeta) = if (this is Styled) {
this.apply { this.configure(style) }
} else {
Styled(this, style.toConfig())
}
class StyledNodeDelegate(val owner: Styled, val key: String?) : ReadWriteProperty<Any?, Meta> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta {
return owner[key ?: property.name]?.node ?: EmptyMeta
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta) {
owner.style[key ?: property.name] = value
}
}

View File

@ -0,0 +1,24 @@
plugins {
kotlin("multiplatform")
}
kotlin {
jvm()
js()
sourceSets {
val commonMain by getting {
dependencies {
api(project(":dataforge-io"))
}
}
val jvmMain by getting {
dependencies {
}
}
val jsMain by getting {
dependencies {
}
}
}
}

View File

@ -0,0 +1,23 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.openjfx.gradle.JavaFXOptions
plugins {
kotlin("jvm")
id("org.openjfx.javafxplugin")
}
dependencies{
api(project(":dataforge-vis:dataforge-vis-spatial"))
api("no.tornado:tornadofx:1.7.18")
implementation("org.fxyz3d:fxyz3d:0.4.0")
}
extensions.findByType<JavaFXOptions>()?.apply {
modules("javafx.controls")
}
tasks.withType<KotlinCompile> {
kotlinOptions{
jvmTarget = "1.8"
}
}

View File

@ -0,0 +1,45 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Context
import hep.dataforge.io.Output
import hep.dataforge.meta.Meta
import javafx.scene.*
import javafx.scene.paint.Color
import org.fxyz3d.geometry.Point3D
import org.fxyz3d.shapes.primitives.CuboidMesh
import org.fxyz3d.utils.CameraTransformer
class FXSpatialRenderer(override val context: Context) : Output<DisplayObject3D> {
private val world: Group = Group()
val camera = PerspectiveCamera()
val cameraTransform = CameraTransformer().apply {
children.add(camera)
}
val canvas: SubScene = SubScene(
Group(world, cameraTransform).apply { DepthTest.ENABLE },
1024.0,
768.0,
true,
SceneAntialiasing.BALANCED
).apply {
fill = Color.GREY
this.camera = this@FXSpatialRenderer.camera
id = "canvas"
}
private fun buildObject(obj: DisplayObject3D): Node {
val center = Point3D(obj.x.toFloat(), obj.y.toFloat(), obj.z.toFloat())
return when (obj) {
is Box3D -> CuboidMesh(obj.xSize, obj.ySize, obj.zSize).apply { this.center = center }
else -> TODO()
}
}
override fun render(obj: DisplayObject3D, meta: Meta) {
world.children.add(buildObject(obj))
}
}

View File

@ -0,0 +1,44 @@
package hep.dataforge.vis.spatial
import hep.dataforge.context.Global
import hep.dataforge.meta.EmptyMeta
import javafx.scene.Parent
import tornadofx.*
class RendererDemoApp: App(RendererDemoView::class)
class RendererDemoView: View(){
val renderer = FXSpatialRenderer(Global)
override val root: Parent = borderpane{
center = renderer.canvas
}
init {
val cube = Box3D(null, EmptyMeta).apply {
xSize = 100.0
ySize = 100.0
zSize = 100.0
}
renderer.render(cube)
renderer.camera.apply {
nearClip = 0.1
farClip = 10000.0
translateX = -200.0
translateY = -200.0
fieldOfView = 20.0
}
renderer.cameraTransform.apply{
ry.angle = -30.0
rx.angle = -15.0
}
}
}
fun main() {
launch<RendererDemoApp>()
}

View File

@ -0,0 +1,42 @@
plugins{
kotlin("js")
id("kotlin")
}
// configure(listOf(compilations.main, compilations.test)) {
// tasks.getByName(compileKotlinTaskName).kotlinOptions {
// sourceMap = true
// moduleKind = "umd"
// metaInfo = true
// }
// }
//
// configure(compilations.main) {
// tasks.getByName(compileKotlinTaskName).kotlinOptions {
// main = "call"
// }
// }
dependencies {
implementation("info.laht.threekt:threejs-wrapper:0.88-npm-1")
}
extensions.findByType<KotlinFrontendExtension>()?.apply {
extensions.findByType<NpmExtension>()?.apply {
dependency("three")
dependency("three-orbitcontrols")
devDependency("karma")
}
sourceMaps = true
bundle("webpack") {
this as WebPackExtension
bundleName = "main"
proxyUrl = "http://localhost:8080"
contentPath = file("src/main/web")
sourceMapEnabled = true
mode = "development"
}
}

View File

@ -0,0 +1,26 @@
plugins {
kotlin("multiplatform")
}
kotlin {
jvm()
js()
sourceSets {
val commonMain by getting {
dependencies {
api(project(":dataforge-vis"))
}
}
val jvmMain by getting {
dependencies {
}
}
val jsMain by getting {
dependencies {
}
}
}
}

View File

@ -0,0 +1,28 @@
package hep.dataforge.vis.spatial
import hep.dataforge.meta.Meta
import hep.dataforge.vis.DisplayLeaf
import hep.dataforge.vis.DisplayObject
import hep.dataforge.vis.double
open class DisplayObject3D(parent: DisplayObject?, type: String, meta: Meta) : DisplayLeaf(parent, type, meta) {
var x by double(0.0)
var y by double(0.0)
var z by double(0.0)
companion object {
const val TYPE = "geometry.spatial"
}
}
class Box3D(parent: DisplayObject?, meta: Meta) : DisplayObject3D(parent,
TYPE, meta) {
var xSize by double(1.0)
var ySize by double(1.0)
var zSize by double(1.0)
companion object {
const val TYPE = "geometry.spatial.box"
}
}

View File

@ -0,0 +1,143 @@
package hep.dataforge.vis
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.vis.DisplayObject.Companion.DEFAULT_TYPE
import hep.dataforge.vis.DisplayObject.Companion.META_KEY
import hep.dataforge.vis.DisplayObject.Companion.TAGS_KEY
/**
* A root type for display hierarchy
*/
interface DisplayObject {
/**
* The parent object of this one. If null, this one is a root.
*/
val parent: DisplayObject?
/**
* The type of this object. Uses `.` notation. Empty type means untyped group
*/
val type: String
val properties: Styled
companion object {
const val DEFAULT_TYPE = ""
const val TYPE_KEY = "@type"
const val CHILDREN_KEY = "@children"
const val META_KEY = "@meta"
const val TAGS_KEY = "@tags"
}
}
interface DisplayGroup : DisplayObject {
val children: List<DisplayObject>
/**
* Add a child object and notify listeners
*/
fun addChild(obj: DisplayObject)
/**
* Remove a specific child and notify listeners
*/
fun removeChild(obj: DisplayObject)
/**
* Add listener for children change
* TODO add detailed information into change listener
*/
fun onChildrenChange(owner: Any? = null, action: () -> Unit)
/**
* Remove children change listener
*/
fun removeChildrenChangeListener(owner: Any? = null)
}
/**
* Get the property of this display object of parent's if not found
*/
tailrec fun DisplayObject.getProperty(name: Name): MetaItem<*>? = properties[name] ?: parent?.getProperty(name)
/**
* A change listener for [DisplayObject] configuration.
*/
fun DisplayObject.onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) =
properties.style.onChange(owner, action)
/**
* Remove all meta listeners with matching owners
*/
fun DisplayObject.removeChangeListener(owner: Any?) =
properties.style.removeListener(owner)
/**
* Additional meta not relevant to display
*/
val DisplayObject.meta: Meta get() = properties[META_KEY]?.node ?: EmptyMeta
val DisplayObject.tags: List<String> get() = properties[TAGS_KEY].stringList
internal data class ObjectListener(
val owner: Any?,
val action: () -> Unit
)
/**
* Basic group of display objects
*/
open class DisplayNode(
override val parent: DisplayObject?,
override val type: String = DEFAULT_TYPE,
meta: Meta = EmptyMeta
) : DisplayGroup {
private val _children = ArrayList<DisplayObject>()
override val children: List<DisplayObject> get() = _children
override val properties = Styled(meta)
private val listeners = HashSet<ObjectListener>()
override fun addChild(obj: DisplayObject) {
// val before = _children[name]
// if (obj == null) {
// _children.remove(name)
// } else {
// _children[name] = obj
// }
// listeners.forEach { it.action(name, before, obj) }
_children.add(obj)
listeners.forEach { it.action() }
}
override fun removeChild(obj: DisplayObject) {
if(_children.remove(obj)){
listeners.forEach { it.action }
}
}
override fun onChildrenChange(owner: Any?, action: () -> Unit) {
listeners.add(ObjectListener(owner, action))
}
override fun removeChildrenChangeListener(owner: Any?) {
listeners.removeAll { it.owner === owner }
}
}
/**
* Basic [DisplayObject] leaf element
*/
open class DisplayLeaf(
override val parent: DisplayObject?,
override val type: String,
meta: Meta = EmptyMeta
) : DisplayObject {
final override val properties = Styled(meta)
}

View File

@ -0,0 +1,48 @@
package hep.dataforge.vis
import hep.dataforge.meta.*
import hep.dataforge.values.Null
import hep.dataforge.values.Value
import kotlin.jvm.JvmName
fun DisplayObject.value(default: Value = Null, key: String? = null) =
ValueConfigDelegate(properties, key, default)
fun DisplayObject.string(default: String? = null, key: String? = null) =
StringConfigDelegate(properties, key, default)
fun DisplayObject.boolean(default: Boolean? = null, key: String? = null) =
BooleanConfigDelegate(properties, key, default)
fun DisplayObject.number(default: Number? = null, key: String? = null) =
NumberConfigDelegate(properties, key, default)
fun DisplayObject.double(default: Double? = null, key: String? = null) =
NumberConfigDelegate(properties, key, default).double
fun DisplayObject.int(default: Int? = null, key: String? = null) =
NumberConfigDelegate(properties, key, default).int
fun DisplayObject.node(key: String? = null) = StyledNodeDelegate(properties, key)
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
@JvmName("safeString")
fun DisplayObject.string(default: String, key: String? = null) =
SafeStringConfigDelegate(properties, key, default)
@JvmName("safeBoolean")
fun DisplayObject.boolean(default: Boolean, key: String? = null) =
SafeBooleanConfigDelegate(properties, key, default)
@JvmName("safeNumber")
fun DisplayObject.number(default: Number, key: String? = null) =
SafeNumberConfigDelegate(properties, key, default)
@JvmName("safeDouble")
fun DisplayObject.double(default: Double, key: String? = null) =
SafeNumberConfigDelegate(properties, key, default).double
inline fun <reified E : Enum<E>> DisplayObject.enum(default: E, key: String? = null) =
SafeEnumvConfigDelegate(properties, key, default) { enumValueOf(it) }

View File

@ -0,0 +1,40 @@
package hep.dataforge.vis
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
interface NamedObject : DisplayObject {
val name: String
operator fun get(nameToken: NameToken): DisplayGroup?
operator fun set(nameToken: NameToken, group: DisplayGroup)
}
/**
* Recursively get a child
*/
tailrec operator fun NamedObject.get(name: Name): DisplayObject? = when (name.length) {
0 -> this
1 -> this[name[0]]
else -> name.first()?.let { this[it] as? NamedObject }?.get(name.cutFirst())
}
/**
* Set given object creating intermediate empty groups if needed
* @param name - the full name of a child
* @param objFactory - a function that creates child object from parent (to avoid mutable parent parameter)
*/
fun NamedObject.set(name: Name, objFactory: (parent: DisplayObject) -> DisplayGroup): Unit = when (name.length) {
0 -> error("Can't set object with empty name")
1 -> set(name[0], objFactory(this))
else -> (this[name.first()!!] ?: DisplayNode(this))
.run {
if (this is NamedObject) {
this.set(name.cutFirst(), objFactory)
} else {
error("Can't assign child to a leaf element $this")
}
}
}

7
gradle.properties Normal file
View File

@ -0,0 +1,7 @@
# Enable official Kotlin Code Style in the IDE.
kotlin.code.style=official
artifactoryUser=darksnake
artifactoryPassword=nortlander
bintrayUser=altavir
bintrayApiKey=9dcb7a779986e1b08898980269b6d428cadda0c3

31
gradle/artifactory.gradle Normal file
View File

@ -0,0 +1,31 @@
apply plugin: "com.jfrog.artifactory"
artifactory {
def artifactory_user = project.hasProperty('artifactoryUser') ? project.property('artifactoryUser') : ""
def artifactory_password = project.hasProperty('artifactoryPassword') ? project.property('artifactoryPassword') : ""
def artifactory_contextUrl = 'http://npm.mipt.ru:8081/artifactory'
contextUrl = artifactory_contextUrl //The base Artifactory URL if not overridden by the publisher/resolver
publish {
repository {
repoKey = 'gradle-dev-local'
username = artifactory_user
password = artifactory_password
}
defaults {
publications('jvm', 'js', 'kotlinMultiplatform', 'metadata')
publishBuildInfo = false
publishArtifacts = true
publishPom = true
publishIvy = false
}
}
resolve {
repository {
repoKey = 'gradle-dev'
username = artifactory_user
password = artifactory_password
}
}
}

85
gradle/bintray.gradle Normal file
View File

@ -0,0 +1,85 @@
apply plugin: 'com.jfrog.bintray'
def vcs = "https://github.com/mipt-npm/kmath"
def pomConfig = {
licenses {
license {
name "The Apache Software License, Version 2.0"
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution "repo"
}
}
developers {
developer {
id "MIPT-NPM"
name "MIPT nuclear physics methods laboratory"
organization "MIPT"
organizationUrl "http://npm.mipt.ru"
}
}
scm {
url vcs
}
}
project.ext.configureMavenCentralMetadata = { pom ->
def root = asNode()
root.appendNode('name', project.name)
root.appendNode('description', project.description)
root.appendNode('url', vcs)
root.children().last() + pomConfig
}
project.ext.configurePom = pomConfig
// Configure publishing
publishing {
repositories {
maven {
url = "https://bintray.com/mipt-npm/scientifik"
}
}
// Process each publication we have in this project
publications.all { publication ->
// apply changes to pom.xml files, see pom.gradle
pom.withXml(configureMavenCentralMetadata)
}
}
bintray {
user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
publish = true
override = true // for multi-platform Kotlin/Native publishing
pkg {
userOrg = "mipt-npm"
repo = "scientifik"
name = "scientifik.kmath"
issueTrackerUrl = "https://github.com/mipt-npm/kmath/issues"
licenses = ['Apache-2.0']
vcsUrl = vcs
version {
name = project.version
vcsTag = project.version
released = new Date()
}
}
}
bintrayUpload.dependsOn publishToMavenLocal
// This is for easier debugging of bintray uploading problems
bintrayUpload.doFirst {
publications = project.publishing.publications.findAll {
!it.name.contains('-test') && it.name != 'kotlinMultiplatform'
}.collect {
println("Uploading artifact '$it.groupId:$it.artifactId:$it.version' from publication '$it.name'")
it.name//https://github.com/bintray/gradle-bintray-plugin/issues/256
}
}

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -1,11 +1,22 @@
pluginManagement { pluginManagement {
repositories { repositories {
mavenCentral()
jcenter() jcenter()
maven("https://plugins.gradle.org/m2/") gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-eap/")
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"kotlinx-atomicfu" -> useModule("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${requested.version}")
"kotlin-multiplatform" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
"org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45")
}
}
} }
} }
//enableFeaturePreview("GRADLE_METADATA") enableFeaturePreview("GRADLE_METADATA")
rootProject.name = "dataforge-core" rootProject.name = "dataforge-core"
include( include(
@ -15,5 +26,8 @@ include(
":dataforge-data", ":dataforge-data",
":dataforge-io", ":dataforge-io",
":dataforge-workspace", ":dataforge-workspace",
":dataforge-scripting" ":dataforge-scripting",
":dataforge-vis",
":dataforge-vis:dataforge-vis-spatial",
":dataforge-vis:dataforge-vis-fx"
) )