forked from kscience/visionforge
Non-nullable accessor for colors
This commit is contained in:
parent
64c447a37b
commit
399be206be
@ -7,7 +7,7 @@
|
|||||||
- Custom client-side events and thier processing in VisionServer
|
- Custom client-side events and thier processing in VisionServer
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Color accessor property is now `colorProperty`. Color uses `invoke` instead of `set`
|
- Color accessor property is now `colorProperty`. Color uses non-nullable `invoke` instead of `set`.
|
||||||
- API update for server and pages
|
- API update for server and pages
|
||||||
- Edges moved to solids module for easier construction
|
- Edges moved to solids module for easier construction
|
||||||
- Visions **must** be rooted in order to subscribe to updates.
|
- Visions **must** be rooted in order to subscribe to updates.
|
||||||
|
@ -12,7 +12,7 @@ val fxVersion by extra("11")
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "space.kscience"
|
group = "space.kscience"
|
||||||
version = "0.3.0-dev-14"
|
version = "0.3.0-dev-15"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
@ -13,7 +13,6 @@ kscience {
|
|||||||
useKtor()
|
useKtor()
|
||||||
fullStack(
|
fullStack(
|
||||||
"muon-monitor.js",
|
"muon-monitor.js",
|
||||||
development = true,
|
|
||||||
jvmConfig = { withJava() },
|
jvmConfig = { withJava() },
|
||||||
jsConfig = { useCommonJs() }
|
jsConfig = { useCommonJs() }
|
||||||
) {
|
) {
|
||||||
@ -47,9 +46,6 @@ application {
|
|||||||
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO ???
|
|
||||||
tasks.getByName("jsBrowserProductionWebpack").dependsOn("jsDevelopmentExecutableCompileSync")
|
|
||||||
|
|
||||||
//distributions {
|
//distributions {
|
||||||
// main {
|
// main {
|
||||||
// contents {
|
// contents {
|
||||||
|
@ -8,6 +8,6 @@ org.gradle.jvmargs=-Xmx4G
|
|||||||
|
|
||||||
org.jetbrains.compose.experimental.jscanvas.enabled=true
|
org.jetbrains.compose.experimental.jscanvas.enabled=true
|
||||||
|
|
||||||
toolsVersion=0.15.0-kotlin-1.9.20-RC2
|
toolsVersion=0.15.0-kotlin-1.9.20
|
||||||
#kotlin.experimental.tryK2=true
|
#kotlin.experimental.tryK2=true
|
||||||
#kscience.wasm.disabled=true
|
#kscience.wasm.disabled=true
|
||||||
|
41
ui/compose/build.gradle.kts
Normal file
41
ui/compose/build.gradle.kts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
plugins {
|
||||||
|
id("space.kscience.gradle.mpp")
|
||||||
|
id("org.jetbrains.compose") version "1.5.10"
|
||||||
|
// id("com.android.library")
|
||||||
|
}
|
||||||
|
|
||||||
|
kscience{
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
// wasm()
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
// android()
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api(compose.runtime)
|
||||||
|
api(compose.foundation)
|
||||||
|
api(compose.material)
|
||||||
|
api(compose.preview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jsMain by getting{
|
||||||
|
dependencies {
|
||||||
|
api(compose.html.core)
|
||||||
|
api("app.softwork:bootstrap-compose:0.1.15")
|
||||||
|
api("app.softwork:bootstrap-compose-icons:0.1.15")
|
||||||
|
api(projects.visionforge.visionforgeThreejs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.jetbrains.compose.web.css.AlignItems
|
||||||
|
import org.jetbrains.compose.web.css.alignItems
|
||||||
|
import org.jetbrains.compose.web.dom.Span
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.isLeaf
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.lastOrNull
|
||||||
|
import space.kscience.dataforge.names.plus
|
||||||
|
|
||||||
|
|
||||||
|
private val MetaViewerItem: FC<MetaViewerProps> = fc("MetaViewerItem") { props ->
|
||||||
|
metaViewerItem(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun MetaViewerItem(root: Meta, name: Name, rootDescriptor: MetaDescriptor? = null) {
|
||||||
|
var expanded: Boolean by remember { mutableStateOf(true) }
|
||||||
|
val item: Meta? = root[name]
|
||||||
|
val descriptorItem: MetaDescriptor? = rootDescriptor?.get(name)
|
||||||
|
val actualValue = item?.value ?: descriptorItem?.defaultValue
|
||||||
|
val actualMeta = item ?: descriptorItem?.defaultNode
|
||||||
|
|
||||||
|
val token = name.lastOrNull()?.toString() ?: props.rootName ?: ""
|
||||||
|
|
||||||
|
val expanderClick: (Event) -> Unit = {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexRow(attrs = {
|
||||||
|
classes("metaItem")
|
||||||
|
style {
|
||||||
|
alignItems(AlignItems.Center)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
if (actualMeta?.isLeaf == false) {
|
||||||
|
Span(attrs = {
|
||||||
|
|
||||||
|
})
|
||||||
|
styledSpan {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeCaret
|
||||||
|
if (expanded) {
|
||||||
|
+TreeStyles.treeCaredDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
onClickFunction = expanderClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styledSpan {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeLabel
|
||||||
|
if (item == null) {
|
||||||
|
+TreeStyles.treeLabelInactive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+token
|
||||||
|
}
|
||||||
|
styledDiv {
|
||||||
|
a {
|
||||||
|
+actualValue.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expanded) {
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
+TreeStyles.tree
|
||||||
|
}
|
||||||
|
val keys = buildSet {
|
||||||
|
descriptorItem?.children?.keys?.forEach {
|
||||||
|
add(NameToken(it))
|
||||||
|
}
|
||||||
|
actualMeta!!.items.keys.let { addAll(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.filter { !it.body.startsWith("@") }.forEach { token ->
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeItem
|
||||||
|
}
|
||||||
|
child(MetaViewerItem) {
|
||||||
|
attrs {
|
||||||
|
this.key = props.name.toString()
|
||||||
|
this.root = props.root
|
||||||
|
this.name = props.name + token
|
||||||
|
this.descriptor = props.descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val MetaViewer: FC<MetaViewerProps> = fc("MetaViewer") { props ->
|
||||||
|
child(MetaViewerItem) {
|
||||||
|
attrs {
|
||||||
|
this.key = ""
|
||||||
|
this.root = props.root
|
||||||
|
this.name = Name.EMPTY
|
||||||
|
this.descriptor = props.descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.metaViewer(meta: Meta, descriptor: MetaDescriptor? = null, key: Any? = null) {
|
||||||
|
child(MetaViewer) {
|
||||||
|
attrs {
|
||||||
|
this.key = key?.toString() ?: ""
|
||||||
|
this.root = meta
|
||||||
|
this.descriptor = descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import kotlinx.css.*
|
||||||
|
import org.jetbrains.compose.web.css.*
|
||||||
|
|
||||||
|
public object TreeStyles : StyleSheet() {
|
||||||
|
/**
|
||||||
|
* Remove default bullets
|
||||||
|
*/
|
||||||
|
public val tree: String by style {
|
||||||
|
paddingLeft(5.px)
|
||||||
|
marginLeft(0.px)
|
||||||
|
listStyleType("none")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style the caret/arrow
|
||||||
|
*/
|
||||||
|
public val treeCaret by style {
|
||||||
|
cursor("pointer")
|
||||||
|
userSelect = UserSelect.none
|
||||||
|
/* Create the caret/arrow with a unicode, and style it */
|
||||||
|
before {
|
||||||
|
content = "\u25B6".quoted
|
||||||
|
color(Color.black)
|
||||||
|
display(DisplayStyle.InlineBlock)
|
||||||
|
marginRight(6.px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate the caret/arrow icon when clicked on (using JavaScript)
|
||||||
|
*/
|
||||||
|
public val treeCaredDown by style {
|
||||||
|
before {
|
||||||
|
content = "\u25B6".quoted
|
||||||
|
color(Color.black)
|
||||||
|
display(DisplayStyle.InlineBlock)
|
||||||
|
marginRight(6.px)
|
||||||
|
transform { rotate(90.deg) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeItem: String by style {
|
||||||
|
alignItems(AlignItems.Center)
|
||||||
|
paddingLeft(10.px)
|
||||||
|
border {
|
||||||
|
left{
|
||||||
|
width(1.px)
|
||||||
|
color(Color.lightgray)
|
||||||
|
style = LineStyle.Dashed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeLabel by style {
|
||||||
|
border(style = LineStyle.None)
|
||||||
|
padding(left = 4.pt, right = 4.pt, top = 0.pt, bottom = 0.pt)
|
||||||
|
textAlign("left")
|
||||||
|
flex(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeLabelInactive: RuleSet by css {
|
||||||
|
color = Color.lightGray
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeLabelSelected: RuleSet by css {
|
||||||
|
backgroundColor = Color.lightBlue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import org.jetbrains.compose.web.css.DisplayStyle
|
||||||
|
import org.jetbrains.compose.web.css.FlexDirection
|
||||||
|
import org.jetbrains.compose.web.css.display
|
||||||
|
import org.jetbrains.compose.web.css.flexDirection
|
||||||
|
import org.jetbrains.compose.web.dom.AttrBuilderContext
|
||||||
|
import org.jetbrains.compose.web.dom.Div
|
||||||
|
import org.jetbrains.compose.web.dom.ElementScope
|
||||||
|
import org.w3c.dom.HTMLDivElement
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
public fun FlexColumn(
|
||||||
|
attrs: AttrBuilderContext<HTMLDivElement>? = null,
|
||||||
|
content: @Composable ElementScope<HTMLDivElement>.() -> Unit,
|
||||||
|
): Unit = Div(
|
||||||
|
attrs = {
|
||||||
|
style {
|
||||||
|
display(DisplayStyle.Flex)
|
||||||
|
flexDirection(FlexDirection.Column)
|
||||||
|
}
|
||||||
|
attrs?.invoke(this)
|
||||||
|
},
|
||||||
|
content
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
public fun FlexRow(
|
||||||
|
attrs: AttrBuilderContext<HTMLDivElement>? = null,
|
||||||
|
content: @Composable ElementScope<HTMLDivElement>.() -> Unit,
|
||||||
|
): Unit = Div(
|
||||||
|
attrs = {
|
||||||
|
style {
|
||||||
|
display(DisplayStyle.Flex)
|
||||||
|
flexDirection(FlexDirection.Row)
|
||||||
|
}
|
||||||
|
attrs?.invoke(this)
|
||||||
|
},
|
||||||
|
content
|
||||||
|
)
|
@ -34,33 +34,33 @@ public fun Vision.colorProperty(
|
|||||||
ColorAccessor(properties.root(true), propertyName ?: property.name.asName())
|
ColorAccessor(properties.root(true), propertyName ?: property.name.asName())
|
||||||
}
|
}
|
||||||
|
|
||||||
public var ColorAccessor?.string: String?
|
public var ColorAccessor.string: String?
|
||||||
get() = this?.value?.let { if (it == Null) null else it.string }
|
get() = value?.let { if (it == Null) null else it.string }
|
||||||
set(value) {
|
set(value) {
|
||||||
this?.value = value?.asValue()
|
this.value = value?.asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
|
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(webColor: String) {
|
public operator fun ColorAccessor.invoke(webColor: String) {
|
||||||
this?.value = webColor.asValue()
|
value = webColor.asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set color as RGB integer
|
* Set color as RGB integer
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(rgb: Int) {
|
public operator fun ColorAccessor.invoke(rgb: Int) {
|
||||||
this?.value = Colors.rgbToString(rgb).asValue()
|
value = Colors.rgbToString(rgb).asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set color as RGB
|
* Set color as RGB
|
||||||
*/
|
*/
|
||||||
public operator fun ColorAccessor?.invoke(r: UByte, g: UByte, b: UByte) {
|
public operator fun ColorAccessor.invoke(r: UByte, g: UByte, b: UByte) {
|
||||||
this?.value = Colors.rgbToString(r, g, b).asValue()
|
value = Colors.rgbToString(r, g, b).asValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun ColorAccessor?.clear() {
|
public fun ColorAccessor.clear() {
|
||||||
this?.value = null
|
value = null
|
||||||
}
|
}
|
@ -94,7 +94,7 @@ class SolidPropertyTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertEquals("#555555", box?.color.string)
|
assertEquals("#555555", box?.color?.string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -31,7 +31,7 @@ class SolidReferenceTest {
|
|||||||
fun testReferenceSerialization(){
|
fun testReferenceSerialization(){
|
||||||
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
|
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
|
||||||
val deserialized = Solids.jsonForSolids.decodeFromJsonElement(SolidGroup.serializer(), serialized)
|
val deserialized = Solids.jsonForSolids.decodeFromJsonElement(SolidGroup.serializer(), serialized)
|
||||||
assertEquals(groupWithReference.items["test"]?.color.string, deserialized.items["test"]?.color.string)
|
assertEquals(groupWithReference.items["test"]?.color?.string, deserialized.items["test"]?.color?.string)
|
||||||
assertEquals("blue", (deserialized.children.getChild("test") as Solid).color.string)
|
assertEquals("blue", (deserialized.children.getChild("test") as Solid).color.string)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ plugins {
|
|||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val tablesVersion = "0.2.0-dev-4"
|
val tablesVersion = "0.2.1"
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
@ -22,8 +22,8 @@ kscience {
|
|||||||
api("space.kscience:tables-kt:${tablesVersion}")
|
api("space.kscience:tables-kt:${tablesVersion}")
|
||||||
}
|
}
|
||||||
dependencies(jsMain) {
|
dependencies(jsMain) {
|
||||||
implementation(npm("tabulator-tables", "5.4.4"))
|
implementation(npm("tabulator-tables", "5.5.2"))
|
||||||
implementation(npm("@types/tabulator-tables", "5.4.8"))
|
implementation(npm("@types/tabulator-tables", "5.5.3"))
|
||||||
}
|
}
|
||||||
useSerialization()
|
useSerialization()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user