Non-nullable accessor for colors

This commit is contained in:
Alexander Nozik 2023-11-13 21:45:37 +03:00
parent 64c447a37b
commit 399be206be
12 changed files with 302 additions and 23 deletions

View File

@ -7,7 +7,7 @@
- Custom client-side events and thier processing in VisionServer
### 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
- Edges moved to solids module for easier construction
- Visions **must** be rooted in order to subscribe to updates.

View File

@ -12,7 +12,7 @@ val fxVersion by extra("11")
allprojects {
group = "space.kscience"
version = "0.3.0-dev-14"
version = "0.3.0-dev-15"
}
subprojects {

View File

@ -13,7 +13,6 @@ kscience {
useKtor()
fullStack(
"muon-monitor.js",
development = true,
jvmConfig = { withJava() },
jsConfig = { useCommonJs() }
) {
@ -47,9 +46,6 @@ application {
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
}
//TODO ???
tasks.getByName("jsBrowserProductionWebpack").dependsOn("jsDevelopmentExecutableCompileSync")
//distributions {
// main {
// contents {

View File

@ -8,6 +8,6 @@ org.gradle.jvmargs=-Xmx4G
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
#kscience.wasm.disabled=true

View 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)
}
}
}
}

View File

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

View File

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

View File

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

View File

@ -34,33 +34,33 @@ public fun Vision.colorProperty(
ColorAccessor(properties.root(true), propertyName ?: property.name.asName())
}
public var ColorAccessor?.string: String?
get() = this?.value?.let { if (it == Null) null else it.string }
public var ColorAccessor.string: String?
get() = value?.let { if (it == Null) null else it.string }
set(value) {
this?.value = value?.asValue()
this.value = value?.asValue()
}
/**
* Set [webcolor](https://en.wikipedia.org/wiki/Web_colors) as string
*/
public operator fun ColorAccessor?.invoke(webColor: String) {
this?.value = webColor.asValue()
public operator fun ColorAccessor.invoke(webColor: String) {
value = webColor.asValue()
}
/**
* Set color as RGB integer
*/
public operator fun ColorAccessor?.invoke(rgb: Int) {
this?.value = Colors.rgbToString(rgb).asValue()
public operator fun ColorAccessor.invoke(rgb: Int) {
value = Colors.rgbToString(rgb).asValue()
}
/**
* Set color as RGB
*/
public operator fun ColorAccessor?.invoke(r: UByte, g: UByte, b: UByte) {
this?.value = Colors.rgbToString(r, g, b).asValue()
public operator fun ColorAccessor.invoke(r: UByte, g: UByte, b: UByte) {
value = Colors.rgbToString(r, g, b).asValue()
}
public fun ColorAccessor?.clear() {
this?.value = null
public fun ColorAccessor.clear() {
value = null
}

View File

@ -94,7 +94,7 @@ class SolidPropertyTest {
}
}
}
assertEquals("#555555", box?.color.string)
assertEquals("#555555", box?.color?.string)
}
@Test

View File

@ -31,7 +31,7 @@ class SolidReferenceTest {
fun testReferenceSerialization(){
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
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)
}
}

View File

@ -2,7 +2,7 @@ plugins {
id("space.kscience.gradle.mpp")
}
val tablesVersion = "0.2.0-dev-4"
val tablesVersion = "0.2.1"
kscience {
jvm()
@ -22,8 +22,8 @@ kscience {
api("space.kscience:tables-kt:${tablesVersion}")
}
dependencies(jsMain) {
implementation(npm("tabulator-tables", "5.4.4"))
implementation(npm("@types/tabulator-tables", "5.4.8"))
implementation(npm("tabulator-tables", "5.5.2"))
implementation(npm("@types/tabulator-tables", "5.5.3"))
}
useSerialization()
}