Compare commits
No commits in common. "f0db286ce645fbea36794b4927fc5992d9bc3e11" and "cbf3f4941abe44f8e91d48aca3d450dc7d912030" have entirely different histories.
f0db286ce6
...
cbf3f4941a
15
CHANGELOG.md
15
CHANGELOG.md
@ -5,6 +5,8 @@
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- **Breaking API** Move vision cache to upper level for renderers to avoid re-creating visions for page reload.
|
||||||
|
- **Breaking API** Forms refactor
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
@ -14,19 +16,6 @@
|
|||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
## 0.4.0 - 2024-02-16
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Added compose-mpp rendering.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- **Breaking API** Move vision cache to upper level for renderers to avoid re-creating visions for page reload.
|
|
||||||
- **Breaking API** Forms refactor.
|
|
||||||
- **Breaking API** Migrated from React to Compose-html.
|
|
||||||
- **Breaking API** changed js package for `visionforge-core` to `space.kscience.visionforge.html` to avoid mixing html and generic parts.
|
|
||||||
|
|
||||||
## 0.3.0 - 2023-12-23
|
## 0.3.0 - 2023-12-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
26
README.md
26
README.md
@ -70,11 +70,7 @@ To learn more about DataForge, please consult the following URLs:
|
|||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
### [visionforge-compose-html](visionforge-compose-html)
|
### [ui](ui)
|
||||||
>
|
|
||||||
> **Maturity**: EXPERIMENTAL
|
|
||||||
|
|
||||||
### [visionforge-compose-multiplatform](visionforge-compose-multiplatform)
|
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
@ -115,10 +111,6 @@ To learn more about DataForge, please consult the following URLs:
|
|||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
### [demo/compose-desktop-demo](demo/compose-desktop-demo)
|
|
||||||
>
|
|
||||||
> **Maturity**: EXPERIMENTAL
|
|
||||||
|
|
||||||
### [demo/gdml](demo/gdml)
|
### [demo/gdml](demo/gdml)
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
@ -143,6 +135,22 @@ To learn more about DataForge, please consult the following URLs:
|
|||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
|
### [ui/bootstrap](ui/bootstrap)
|
||||||
|
>
|
||||||
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
|
### [ui/compose](ui/compose)
|
||||||
|
>
|
||||||
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
|
### [ui/react](ui/react)
|
||||||
|
>
|
||||||
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
|
### [ui/ring](ui/ring)
|
||||||
|
>
|
||||||
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
### [visionforge-jupyter/visionforge-jupyter-common](visionforge-jupyter/visionforge-jupyter-common)
|
### [visionforge-jupyter/visionforge-jupyter-common](visionforge-jupyter/visionforge-jupyter-common)
|
||||||
> Jupyter api artifact including all common modules
|
> Jupyter api artifact including all common modules
|
||||||
>
|
>
|
||||||
|
@ -10,7 +10,7 @@ val dataforgeVersion by extra("0.8.0")
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "space.kscience"
|
group = "space.kscience"
|
||||||
version = "0.4.0"
|
version = "0.4.0-dev-3"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
# Module compose-desktop-demo
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
public final class ComposableSingletons$MainKt {
|
|
||||||
public static final field INSTANCE LComposableSingletons$MainKt;
|
|
||||||
public static field lambda-1 Lkotlin/jvm/functions/Function2;
|
|
||||||
public static field lambda-2 Lkotlin/jvm/functions/Function3;
|
|
||||||
public static field lambda-3 Lkotlin/jvm/functions/Function3;
|
|
||||||
public fun <init> ()V
|
|
||||||
public final fun getLambda-1$compose_desktop_demo ()Lkotlin/jvm/functions/Function2;
|
|
||||||
public final fun getLambda-2$compose_desktop_demo ()Lkotlin/jvm/functions/Function3;
|
|
||||||
public final fun getLambda-3$compose_desktop_demo ()Lkotlin/jvm/functions/Function3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class MainKt {
|
|
||||||
public static final fun App (Landroidx/compose/runtime/Composer;I)V
|
|
||||||
public static final fun main ()V
|
|
||||||
public static synthetic fun main ([Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("space.kscience.gradle.mpp")
|
|
||||||
alias(spclibs.plugins.compose)
|
|
||||||
}
|
|
||||||
|
|
||||||
kscience {
|
|
||||||
jvm()
|
|
||||||
useCoroutines()
|
|
||||||
|
|
||||||
commonMain{
|
|
||||||
implementation(projects.visionforgeSolid)
|
|
||||||
}
|
|
||||||
|
|
||||||
jvmMain {
|
|
||||||
implementation(projects.visionforgeComposeMultiplatform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin{
|
|
||||||
explicitApi = null
|
|
||||||
sourceSets{
|
|
||||||
commonMain{
|
|
||||||
dependencies {
|
|
||||||
implementation(compose.desktop.currentOs)
|
|
||||||
api(compose.preview)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
compose{
|
|
||||||
desktop{
|
|
||||||
desktop {
|
|
||||||
application {
|
|
||||||
mainClass = "MainKt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.material.MaterialTheme
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.window.Window
|
|
||||||
import androidx.compose.ui.window.application
|
|
||||||
import space.kscience.dataforge.meta.set
|
|
||||||
import space.kscience.visionforge.compose.PropertyEditor
|
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
|
||||||
fun App(){
|
|
||||||
val options = remember {
|
|
||||||
Canvas3DOptions{
|
|
||||||
meta["custom.field"] = 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PropertyEditor(
|
|
||||||
properties = options.meta,
|
|
||||||
descriptor = Canvas3DOptions.descriptor,
|
|
||||||
expanded = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun main() = application {
|
|
||||||
Window(onCloseRequest = ::exitApplication) {
|
|
||||||
MaterialTheme {
|
|
||||||
App()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,14 +6,14 @@ import org.jetbrains.compose.web.renderComposable
|
|||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.gdml.GdmlShowCase
|
import space.kscience.gdml.GdmlShowCase
|
||||||
|
import space.kscience.visionforge.Application
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
|
import space.kscience.visionforge.compose.TreeStyles
|
||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
import space.kscience.visionforge.html.Application
|
|
||||||
import space.kscience.visionforge.html.VisionForgeStyles
|
|
||||||
import space.kscience.visionforge.html.startApplication
|
|
||||||
import space.kscience.visionforge.solid.ambientLight
|
import space.kscience.visionforge.solid.ambientLight
|
||||||
import space.kscience.visionforge.solid.invoke
|
import space.kscience.visionforge.solid.invoke
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
import space.kscience.visionforge.startApplication
|
||||||
|
|
||||||
|
|
||||||
private class GDMLDemoApp : Application {
|
private class GDMLDemoApp : Application {
|
||||||
@ -33,7 +33,7 @@ private class GDMLDemoApp : Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderComposable(element) {
|
renderComposable(element) {
|
||||||
Style(VisionForgeStyles)
|
Style(TreeStyles)
|
||||||
Style {
|
Style {
|
||||||
"html" {
|
"html" {
|
||||||
height(100.percent)
|
height(100.percent)
|
||||||
|
@ -5,16 +5,16 @@ import org.w3c.dom.Document
|
|||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.plotly.models.Trace
|
import space.kscience.plotly.models.Trace
|
||||||
import space.kscience.plotly.scatter
|
import space.kscience.plotly.scatter
|
||||||
|
import space.kscience.visionforge.Application
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.html.Application
|
import space.kscience.visionforge.compose.Tabs
|
||||||
import space.kscience.visionforge.html.Tabs
|
import space.kscience.visionforge.compose.TreeStyles
|
||||||
import space.kscience.visionforge.html.VisionForgeStyles
|
|
||||||
import space.kscience.visionforge.html.startApplication
|
|
||||||
import space.kscience.visionforge.markup.MarkupPlugin
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
import space.kscience.visionforge.solid.three.compose.ThreeView
|
import space.kscience.visionforge.solid.three.compose.ThreeView
|
||||||
|
import space.kscience.visionforge.startApplication
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun Trace.appendXYLatest(x: Number, y: Number, history: Int = 400, xErr: Number? = null, yErr: Number? = null) {
|
fun Trace.appendXYLatest(x: Number, y: Number, history: Int = 400, xErr: Number? = null, yErr: Number? = null) {
|
||||||
@ -40,7 +40,7 @@ private class JsPlaygroundApp : Application {
|
|||||||
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
|
val element = document.getElementById("playground") ?: error("Element with id 'playground' not found on page")
|
||||||
|
|
||||||
renderComposable(element) {
|
renderComposable(element) {
|
||||||
Style(VisionForgeStyles)
|
Style(TreeStyles)
|
||||||
Div({
|
Div({
|
||||||
style {
|
style {
|
||||||
padding(0.pt)
|
padding(0.pt)
|
||||||
|
@ -15,8 +15,8 @@ import space.kscience.plotly.Plot
|
|||||||
import space.kscience.plotly.layout
|
import space.kscience.plotly.layout
|
||||||
import space.kscience.plotly.models.Trace
|
import space.kscience.plotly.models.Trace
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.html.Vision
|
import space.kscience.visionforge.compose.Vision
|
||||||
import space.kscience.visionforge.html.zIndex
|
import space.kscience.visionforge.compose.zIndex
|
||||||
import space.kscience.visionforge.markup.VisionOfMarkup
|
import space.kscience.visionforge.markup.VisionOfMarkup
|
||||||
import space.kscience.visionforge.plotly.asVision
|
import space.kscience.visionforge.plotly.asVision
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
public final class ru/mipt/npm/muon/monitor/Event {
|
public final class ru/mipt/npm/muon/monitor/Event {
|
||||||
public static final field $stable I
|
|
||||||
public static final field Companion Lru/mipt/npm/muon/monitor/Event$Companion;
|
public static final field Companion Lru/mipt/npm/muon/monitor/Event$Companion;
|
||||||
public fun <init> (ILjava/util/List;Ljava/util/Collection;)V
|
public fun <init> (ILjava/util/List;Ljava/util/Collection;)V
|
||||||
public final fun component1 ()I
|
public final fun component1 ()I
|
||||||
@ -16,7 +15,6 @@ public final class ru/mipt/npm/muon/monitor/Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/Event$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
public final class ru/mipt/npm/muon/monitor/Event$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||||
public static final field $stable I
|
|
||||||
public static final field INSTANCE Lru/mipt/npm/muon/monitor/Event$$serializer;
|
public static final field INSTANCE Lru/mipt/npm/muon/monitor/Event$$serializer;
|
||||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||||
@ -32,7 +30,6 @@ public final class ru/mipt/npm/muon/monitor/Event$Companion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/Model {
|
public final class ru/mipt/npm/muon/monitor/Model {
|
||||||
public static final field $stable I
|
|
||||||
public fun <init> (Lspace/kscience/visionforge/VisionManager;)V
|
public fun <init> (Lspace/kscience/visionforge/VisionManager;)V
|
||||||
public final fun displayEvent (Lru/mipt/npm/muon/monitor/Event;)V
|
public final fun displayEvent (Lru/mipt/npm/muon/monitor/Event;)V
|
||||||
public final fun encodeToString ()Ljava/lang/String;
|
public final fun encodeToString ()Ljava/lang/String;
|
||||||
@ -43,7 +40,6 @@ public final class ru/mipt/npm/muon/monitor/Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/Monitor {
|
public final class ru/mipt/npm/muon/monitor/Monitor {
|
||||||
public static final field $stable I
|
|
||||||
public static final field CENTRAL_LAYER_Z F
|
public static final field CENTRAL_LAYER_Z F
|
||||||
public static final field GEOMETRY_TOLERANCE D
|
public static final field GEOMETRY_TOLERANCE D
|
||||||
public static final field INSTANCE Lru/mipt/npm/muon/monitor/Monitor;
|
public static final field INSTANCE Lru/mipt/npm/muon/monitor/Monitor;
|
||||||
@ -61,7 +57,6 @@ public final class ru/mipt/npm/muon/monitor/ReadResourceKt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/SC1 {
|
public final class ru/mipt/npm/muon/monitor/SC1 {
|
||||||
public static final field $stable I
|
|
||||||
public fun <init> (Ljava/lang/String;Lspace/kscience/visionforge/solid/Float32Vector3D;FFF)V
|
public fun <init> (Ljava/lang/String;Lspace/kscience/visionforge/solid/Float32Vector3D;FFF)V
|
||||||
public synthetic fun <init> (Ljava/lang/String;Lspace/kscience/visionforge/solid/Float32Vector3D;FFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Ljava/lang/String;Lspace/kscience/visionforge/solid/Float32Vector3D;FFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public final fun getCenter ()Lspace/kscience/visionforge/solid/Float32Vector3D;
|
public final fun getCenter ()Lspace/kscience/visionforge/solid/Float32Vector3D;
|
||||||
@ -72,7 +67,6 @@ public final class ru/mipt/npm/muon/monitor/SC1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/SC16 {
|
public final class ru/mipt/npm/muon/monitor/SC16 {
|
||||||
public static final field $stable I
|
|
||||||
public fun <init> (Ljava/lang/String;Lspace/kscience/visionforge/solid/Float32Vector3D;)V
|
public fun <init> (Ljava/lang/String;Lspace/kscience/visionforge/solid/Float32Vector3D;)V
|
||||||
public final fun getCenter ()Lspace/kscience/visionforge/solid/Float32Vector3D;
|
public final fun getCenter ()Lspace/kscience/visionforge/solid/Float32Vector3D;
|
||||||
public final fun getName ()Ljava/lang/String;
|
public final fun getName ()Ljava/lang/String;
|
||||||
@ -87,7 +81,6 @@ public final class ru/mipt/npm/muon/monitor/server/MMServerKt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/sim/Cos2TrackGenerator : ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
public final class ru/mipt/npm/muon/monitor/sim/Cos2TrackGenerator : ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
||||||
public static final field $stable I
|
|
||||||
public fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DFF)V
|
public fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DFF)V
|
||||||
public synthetic fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
public fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
||||||
@ -98,7 +91,6 @@ public final class ru/mipt/npm/muon/monitor/sim/Cos2TrackGenerator : ru/mipt/npm
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/sim/FixedAngleGenerator : ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
public final class ru/mipt/npm/muon/monitor/sim/FixedAngleGenerator : ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
||||||
public static final field $stable I
|
|
||||||
public fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DDFF)V
|
public fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DDFF)V
|
||||||
public synthetic fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DDFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;DDFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
public fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
||||||
@ -142,7 +134,6 @@ public abstract interface class ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ru/mipt/npm/muon/monitor/sim/UniformTrackGenerator : ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
public final class ru/mipt/npm/muon/monitor/sim/UniformTrackGenerator : ru/mipt/npm/muon/monitor/sim/TrackGenerator {
|
||||||
public static final field $stable I
|
|
||||||
public fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;FF)V
|
public fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;FF)V
|
||||||
public synthetic fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;FFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Lorg/apache/commons/math3/random/RandomGenerator;FFILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
public fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
||||||
|
@ -44,10 +44,8 @@ kscience {
|
|||||||
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kotlin{
|
|
||||||
explicitApi = null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
kotlin.explicitApi = null
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
||||||
|
@ -5,11 +5,11 @@ import org.jetbrains.compose.web.renderComposable
|
|||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.request
|
import space.kscience.dataforge.context.request
|
||||||
|
import space.kscience.visionforge.Application
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
import space.kscience.visionforge.html.Application
|
import space.kscience.visionforge.compose.VisionForgeStyles
|
||||||
import space.kscience.visionforge.html.VisionForgeStyles
|
|
||||||
import space.kscience.visionforge.html.startApplication
|
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
import space.kscience.visionforge.startApplication
|
||||||
|
|
||||||
private class MMDemoApp : Application {
|
private class MMDemoApp : Application {
|
||||||
|
|
||||||
|
@ -53,11 +53,6 @@ public final class space/kscience/visionforge/examples/GenerateSchemaKt {
|
|||||||
public static synthetic fun main ([Ljava/lang/String;)V
|
public static synthetic fun main ([Ljava/lang/String;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/examples/MarkdownVisionKt {
|
|
||||||
public static final fun main ()V
|
|
||||||
public static synthetic fun main ([Ljava/lang/String;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/examples/PlotlyVisionKt {
|
public final class space/kscience/visionforge/examples/PlotlyVisionKt {
|
||||||
public static final fun main ()V
|
public static final fun main ()V
|
||||||
public static synthetic fun main ([Ljava/lang/String;)V
|
public static synthetic fun main ([Ljava/lang/String;)V
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.visionforge.html.runVisionClient
|
|
||||||
import space.kscience.visionforge.jupyter.VFNotebookClient
|
import space.kscience.visionforge.jupyter.VFNotebookClient
|
||||||
import space.kscience.visionforge.markup.MarkupPlugin
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
|
import space.kscience.visionforge.runVisionClient
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
import space.kscience.visionforge.tables.TableVisionJsPlugin
|
import space.kscience.visionforge.tables.TableVisionJsPlugin
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
import space.kscience.visionforge.html.Application
|
import space.kscience.visionforge.Application
|
||||||
import space.kscience.visionforge.html.startApplication
|
|
||||||
import space.kscience.visionforge.solid.x
|
import space.kscience.visionforge.solid.x
|
||||||
import space.kscience.visionforge.solid.y
|
import space.kscience.visionforge.solid.y
|
||||||
|
import space.kscience.visionforge.startApplication
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
private class ThreeDemoApp : Application {
|
private class ThreeDemoApp : Application {
|
||||||
|
@ -40,9 +40,13 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
include(
|
include(
|
||||||
":visionforge-core",
|
// ":ui",
|
||||||
|
// ":ui:react",
|
||||||
|
// ":ui:ring",
|
||||||
|
// ":ui:material",
|
||||||
|
// ":ui:bootstrap",
|
||||||
":visionforge-compose-html",
|
":visionforge-compose-html",
|
||||||
":visionforge-compose-multiplatform",
|
":visionforge-core",
|
||||||
":visionforge-solid",
|
":visionforge-solid",
|
||||||
// ":visionforge-fx",
|
// ":visionforge-fx",
|
||||||
":visionforge-threejs",
|
":visionforge-threejs",
|
||||||
@ -60,7 +64,6 @@ include(
|
|||||||
":demo:playground",
|
":demo:playground",
|
||||||
// ":demo:plotly-fx",
|
// ":demo:plotly-fx",
|
||||||
":demo:js-playground",
|
":demo:js-playground",
|
||||||
":demo:compose-desktop-demo",
|
|
||||||
":visionforge-jupyter",
|
":visionforge-jupyter",
|
||||||
":visionforge-jupyter:visionforge-jupyter-common"
|
":visionforge-jupyter:visionforge-jupyter-common"
|
||||||
)
|
)
|
||||||
|
4
ui/README.md
Normal file
4
ui/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Module ui
|
||||||
|
|
||||||
|
|
||||||
|
|
4
ui/bootstrap/README.md
Normal file
4
ui/bootstrap/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Module bootstrap
|
||||||
|
|
||||||
|
|
||||||
|
|
19
ui/bootstrap/build.gradle.kts
Normal file
19
ui/bootstrap/build.gradle.kts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
plugins {
|
||||||
|
id("space.kscience.gradle.mpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataforgeVersion: String by rootProject.extra
|
||||||
|
|
||||||
|
kscience{
|
||||||
|
js()
|
||||||
|
jsMain{
|
||||||
|
dependencies {
|
||||||
|
api(project(":visionforge-solid"))
|
||||||
|
api(project(":ui:react"))
|
||||||
|
implementation(npm("file-saver", "2.0.2"))
|
||||||
|
implementation(npm("bootstrap","4.6.0"))
|
||||||
|
implementation(npm("jquery","3.5.1"))
|
||||||
|
implementation(npm("popper.js","1.16.1"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
public fun useBootstrap(){
|
||||||
|
kotlinext.js.require<dynamic>("bootstrap/dist/css/bootstrap.min.css")
|
||||||
|
kotlinext.js.require<dynamic>("bootstrap")
|
||||||
|
}
|
||||||
|
|
||||||
|
//public inline fun TagConsumer<HTMLElement>.card(title: String, crossinline block: TagConsumer<HTMLElement>.() -> Unit) {
|
||||||
|
// div("card w-100") {
|
||||||
|
// div("card-body") {
|
||||||
|
// h3(classes = "card-title") { +title }
|
||||||
|
// block()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public typealias SectionsBuilder = MutableList<Pair<String, DIV.() -> Unit>>
|
||||||
|
//
|
||||||
|
//public fun SectionsBuilder.entry(title: String, builder: DIV.() -> Unit) {
|
||||||
|
// add(title to builder)
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
//public fun TagConsumer<HTMLElement>.accordion(id: String, elements: List<Pair<String, DIV.() -> Unit>>) {
|
||||||
|
// div("container-fluid") {
|
||||||
|
// div("accordion") {
|
||||||
|
// this.id = id
|
||||||
|
// elements.forEachIndexed { index, (title, builder) ->
|
||||||
|
// val headerID = "${id}-${index}-heading"
|
||||||
|
// val collapseID = "${id}-${index}-collapse"
|
||||||
|
// div("card") {
|
||||||
|
// div("card-header") {
|
||||||
|
// this.id = headerID
|
||||||
|
// h5("mb-0") {
|
||||||
|
// button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
// attributes["data-toggle"] = "collapse"
|
||||||
|
// attributes["data-target"] = "#$collapseID"
|
||||||
|
// attributes["aria-expanded"] = "false"
|
||||||
|
// attributes["aria-controls"] = collapseID
|
||||||
|
// +title
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// div("collapse") {
|
||||||
|
// this.id = collapseID
|
||||||
|
// attributes["aria-labelledby"] = headerID
|
||||||
|
// attributes["data-parent"] = "#$id"
|
||||||
|
// div("card-body", block = builder)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
//public fun TagConsumer<HTMLElement>.accordion(id: String, builder: AccordionBuilder.() -> Unit) {
|
||||||
|
// val list = ArrayList<Pair<String, DIV.() -> Unit>>().apply(builder)
|
||||||
|
// accordion(id, list)
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public fun Element.displayCanvasControls(canvas: ThreeCanvas, block: TagConsumer<HTMLElement>.() -> Unit = {}) {
|
||||||
|
// clear()
|
||||||
|
// append {
|
||||||
|
// accordion("controls") {
|
||||||
|
// entry("Settings") {
|
||||||
|
// div("row") {
|
||||||
|
// div("col-2") {
|
||||||
|
// label("checkbox-inline") {
|
||||||
|
// input(type = InputType.checkBox) {
|
||||||
|
// checked = canvas.axes.visible
|
||||||
|
// onChangeFunction = {
|
||||||
|
// canvas.axes.visible = checked
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// +"Axes"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// div("col-1") {
|
||||||
|
// button {
|
||||||
|
// +"Export"
|
||||||
|
// onClickFunction = {
|
||||||
|
// val json = (canvas.content as? SolidGroup)?.let { group ->
|
||||||
|
// val visionManager = canvas.context.plugins.fetch(SolidManager).visionManager
|
||||||
|
// visionManager.encodeToString(group)
|
||||||
|
// }
|
||||||
|
// if (json != null) {
|
||||||
|
// saveData(it, "object.json", "text/json") {
|
||||||
|
// json
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// entry("Layers") {
|
||||||
|
// div("row") {
|
||||||
|
// (0..11).forEach { layer ->
|
||||||
|
// div("col-1") {
|
||||||
|
// label { +layer.toString() }
|
||||||
|
// input(type = InputType.checkBox) {
|
||||||
|
// if (layer == 0) {
|
||||||
|
// checked = true
|
||||||
|
// }
|
||||||
|
// onChangeFunction = {
|
||||||
|
// if (checked) {
|
||||||
|
// canvas.camera.layers.enable(layer)
|
||||||
|
// } else {
|
||||||
|
// canvas.camera.layers.disable(layer)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// block()
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,77 @@
|
|||||||
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.css.*
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import org.w3c.files.Blob
|
||||||
|
import org.w3c.files.BlobPropertyBag
|
||||||
|
import react.FC
|
||||||
|
import react.Props
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.attrs
|
||||||
|
import react.dom.button
|
||||||
|
import react.fc
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.encodeToString
|
||||||
|
import space.kscience.visionforge.react.flexColumn
|
||||||
|
import space.kscience.visionforge.react.flexRow
|
||||||
|
import space.kscience.visionforge.react.propertyEditor
|
||||||
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import styled.css
|
||||||
|
|
||||||
|
private fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
val fileSaver = kotlinext.js.require<dynamic>("file-saver")
|
||||||
|
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
|
||||||
|
fileSaver.saveAs(blob, fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.canvasControls(canvasOptions: Canvas3DOptions, vision: Vision?) {
|
||||||
|
child(CanvasControls) {
|
||||||
|
attrs {
|
||||||
|
this.canvasOptions = canvasOptions
|
||||||
|
this.vision = vision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public external interface CanvasControlsProps : Props {
|
||||||
|
public var canvasOptions: Canvas3DOptions
|
||||||
|
public var vision: Vision?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
|
||||||
|
flexColumn {
|
||||||
|
flexRow {
|
||||||
|
css {
|
||||||
|
border = Border(1.px, BorderStyle.solid, Color.blue)
|
||||||
|
padding = Padding(4.px)
|
||||||
|
}
|
||||||
|
props.vision?.let { vision ->
|
||||||
|
button {
|
||||||
|
+"Export"
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
val json = vision.encodeToString()
|
||||||
|
saveData(it, "object.json", "text/json") {
|
||||||
|
json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
propertyEditor(
|
||||||
|
scope = props.vision?.manager?.context ?: GlobalScope,
|
||||||
|
properties = props.canvasOptions.meta,
|
||||||
|
descriptor = Canvas3DOptions.descriptor,
|
||||||
|
expanded = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
import kotlinx.html.ButtonType
|
||||||
|
import kotlinx.html.DIV
|
||||||
|
import kotlinx.html.id
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.*
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.length
|
||||||
|
import styled.StyledDOMBuilder
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
import styled.styledNav
|
||||||
|
|
||||||
|
|
||||||
|
public inline fun RBuilder.card(title: String, crossinline block: StyledDOMBuilder<DIV>.() -> Unit): Unit =
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+"card"
|
||||||
|
+"w-100"
|
||||||
|
}
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+"card-body"
|
||||||
|
}
|
||||||
|
h3(classes = "card-title") {
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.accordion(
|
||||||
|
id: String,
|
||||||
|
elements: List<Pair<String, StyledDOMBuilder<DIV>.() -> Unit>>,
|
||||||
|
): Unit = styledDiv {
|
||||||
|
css {
|
||||||
|
+"accordion"
|
||||||
|
//+"p-1"
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
this.id = id
|
||||||
|
}
|
||||||
|
elements.forEachIndexed { index, (title, builder) ->
|
||||||
|
val headerID = "${id}-${index}-heading"
|
||||||
|
val collapseID = "${id}-${index}-collapse"
|
||||||
|
div("card p-0 m-0") {
|
||||||
|
div("card-header") {
|
||||||
|
attrs {
|
||||||
|
this.id = headerID
|
||||||
|
}
|
||||||
|
h5("mb-0") {
|
||||||
|
button(classes = "btn btn-link collapsed", type = ButtonType.button) {
|
||||||
|
attrs {
|
||||||
|
attributes["data-toggle"] = "collapse"
|
||||||
|
attributes["data-target"] = "#$collapseID"
|
||||||
|
attributes["aria-expanded"] = "false"
|
||||||
|
attributes["aria-controls"] = collapseID
|
||||||
|
}
|
||||||
|
+title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div("collapse") {
|
||||||
|
attrs {
|
||||||
|
this.id = collapseID
|
||||||
|
attributes["aria-labelledby"] = headerID
|
||||||
|
attributes["data-parent"] = "#$id"
|
||||||
|
}
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+"card-body"
|
||||||
|
}
|
||||||
|
builder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public fun RBuilder.nameCrumbs(name: Name?, rootTitle: String, link: (Name) -> Unit): Unit = styledNav {
|
||||||
|
css {
|
||||||
|
+"p-0"
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
attributes["aria-label"] = "breadcrumb"
|
||||||
|
}
|
||||||
|
ol("breadcrumb") {
|
||||||
|
li("breadcrumb-item") {
|
||||||
|
button(classes = "btn btn-link p-0") {
|
||||||
|
+rootTitle
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
link(Name.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name != null) {
|
||||||
|
val tokens = ArrayList<NameToken>(name.length)
|
||||||
|
name.tokens.forEach { token ->
|
||||||
|
tokens.add(token)
|
||||||
|
val fullName = Name(tokens.toList())
|
||||||
|
li("breadcrumb-item") {
|
||||||
|
button(classes = "btn btn-link p-0") {
|
||||||
|
+token.toString()
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
console.log("Selected = $fullName")
|
||||||
|
link(fullName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public typealias RSectionsBuilder = MutableList<Pair<String, StyledDOMBuilder<DIV>.() -> Unit>>
|
||||||
|
|
||||||
|
public fun RSectionsBuilder.entry(title: String, builder: StyledDOMBuilder<DIV>.() -> Unit) {
|
||||||
|
add(title to builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.accordion(id: String, builder: RSectionsBuilder.() -> Unit): Unit {
|
||||||
|
val list = ArrayList<Pair<String, StyledDOMBuilder<DIV>.() -> Unit>>().apply(builder)
|
||||||
|
accordion(id, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum class ContainerSize(public val suffix: String) {
|
||||||
|
DEFAULT(""),
|
||||||
|
SM("-sm"),
|
||||||
|
MD("-md"),
|
||||||
|
LG("-lg"),
|
||||||
|
XL("-xl"),
|
||||||
|
FLUID("-fluid")
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun RBuilder.container(
|
||||||
|
size: ContainerSize = ContainerSize.FLUID,
|
||||||
|
block: StyledDOMBuilder<DIV>.() -> Unit,
|
||||||
|
): Unit = styledDiv {
|
||||||
|
css {
|
||||||
|
classes.add("container${size.suffix}")
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum class GridMaxSize(public val suffix: String) {
|
||||||
|
NONE(""),
|
||||||
|
SM("-sm"),
|
||||||
|
MD("-md"),
|
||||||
|
LG("-lg"),
|
||||||
|
XL("-xl")
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun RBuilder.gridColumn(
|
||||||
|
weight: Int? = null,
|
||||||
|
maxSize: GridMaxSize = GridMaxSize.NONE,
|
||||||
|
block: StyledDOMBuilder<DIV>.() -> Unit,
|
||||||
|
): Unit = styledDiv {
|
||||||
|
val weightSuffix = weight?.let { "-$it" } ?: ""
|
||||||
|
css {
|
||||||
|
classes.add("col${maxSize.suffix}$weightSuffix")
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun RBuilder.gridRow(
|
||||||
|
block: StyledDOMBuilder<DIV>.() -> Unit,
|
||||||
|
): Unit = styledDiv {
|
||||||
|
css {
|
||||||
|
classes.add("row")
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
import kotlinx.html.DIV
|
||||||
|
import kotlinx.html.classes
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import react.*
|
||||||
|
import react.dom.attrs
|
||||||
|
import react.dom.button
|
||||||
|
import react.dom.li
|
||||||
|
import react.dom.ul
|
||||||
|
import space.kscience.visionforge.react.flexColumn
|
||||||
|
import styled.StyledDOMBuilder
|
||||||
|
import styled.styledDiv
|
||||||
|
|
||||||
|
public external interface TabProps : PropsWithChildren {
|
||||||
|
public var id: String
|
||||||
|
public var title: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val Tab: FC<TabProps> = fc { props ->
|
||||||
|
props.children()
|
||||||
|
}
|
||||||
|
|
||||||
|
public external interface TabPaneProps : PropsWithChildren {
|
||||||
|
public var activeTab: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val TabPane: FC<TabPaneProps> = fc("TabPane") { props ->
|
||||||
|
var activeTab: String? by useState(props.activeTab)
|
||||||
|
|
||||||
|
val children: Array<out ReactElement<*>?> = Children.map(props.children) {
|
||||||
|
it.asElementOrNull()
|
||||||
|
} ?: emptyArray()
|
||||||
|
|
||||||
|
val childrenProps = children.mapNotNull {
|
||||||
|
it?.props?.unsafeCast<TabProps>()
|
||||||
|
}
|
||||||
|
|
||||||
|
flexColumn {
|
||||||
|
ul("nav nav-tabs") {
|
||||||
|
childrenProps.forEach { cp ->
|
||||||
|
li("nav-item") {
|
||||||
|
button(classes = "nav-link") {
|
||||||
|
+(cp.title ?: cp.id)
|
||||||
|
attrs {
|
||||||
|
if (cp.id == activeTab) {
|
||||||
|
classes = classes + "active"
|
||||||
|
}
|
||||||
|
onClickFunction = {
|
||||||
|
activeTab = cp.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children.find { (it?.props?.unsafeCast<TabProps>())?.id == activeTab }?.let {
|
||||||
|
child(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TabBuilder(internal val parentBuilder: RBuilder) {
|
||||||
|
public fun tab(id: String, title: String? = null, builder: StyledDOMBuilder<DIV>.() -> Unit) {
|
||||||
|
parentBuilder.child(Tab) {
|
||||||
|
attrs {
|
||||||
|
this.id = id
|
||||||
|
this.title = title
|
||||||
|
}
|
||||||
|
styledDiv {
|
||||||
|
builder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun RBuilder.tabPane(activeTab: String? = null, crossinline builder: TabBuilder.() -> Unit) {
|
||||||
|
child(TabPane) {
|
||||||
|
attrs {
|
||||||
|
this.activeTab = activeTab
|
||||||
|
}
|
||||||
|
TabBuilder(this).builder()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
import kotlinx.css.*
|
||||||
|
import react.FC
|
||||||
|
import react.PropsWithChildren
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.h2
|
||||||
|
import react.fc
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.isEmpty
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.react.visionTree
|
||||||
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
|
||||||
|
public external interface ThreeControlsProps : PropsWithChildren {
|
||||||
|
public var canvasOptions: Canvas3DOptions
|
||||||
|
public var vision: Vision?
|
||||||
|
public var selected: Name?
|
||||||
|
public var onSelect: (Name) -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
|
||||||
|
tabPane(if (props.selected != null) "Properties" else null) {
|
||||||
|
tab("Canvas") {
|
||||||
|
card("Canvas configuration") {
|
||||||
|
canvasControls(props.canvasOptions, props.vision)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tab("Tree") {
|
||||||
|
css {
|
||||||
|
border = Border(1.px, BorderStyle.solid, Color.lightGray)
|
||||||
|
padding = Padding(10.px)
|
||||||
|
}
|
||||||
|
h2 { +"Object tree" }
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
flex = Flex(1.0, 1.0, FlexBasis.inherit)
|
||||||
|
}
|
||||||
|
props.vision?.let {
|
||||||
|
visionTree(it, props.selected, props.onSelect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tab("Properties") {
|
||||||
|
props.selected.let { selected ->
|
||||||
|
val selectedObject: Vision? = when {
|
||||||
|
selected == null -> null
|
||||||
|
selected.isEmpty() -> props.vision
|
||||||
|
else -> (props.vision as? SolidGroup)?.get(selected)
|
||||||
|
}
|
||||||
|
if (selectedObject != null) {
|
||||||
|
visionPropertyEditor(selectedObject, key = selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.parentBuilder.run {
|
||||||
|
props.children()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.threeControls(
|
||||||
|
canvasOptions: Canvas3DOptions,
|
||||||
|
vision: Vision?,
|
||||||
|
selected: Name?,
|
||||||
|
onSelect: (Name) -> Unit = {},
|
||||||
|
builder: TabBuilder.() -> Unit = {},
|
||||||
|
): Unit = child(ThreeControls) {
|
||||||
|
attrs {
|
||||||
|
this.canvasOptions = canvasOptions
|
||||||
|
this.vision = vision
|
||||||
|
this.selected = selected
|
||||||
|
this.onSelect = onSelect
|
||||||
|
}
|
||||||
|
TabBuilder(this).builder()
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import react.RBuilder
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.isEmpty
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.getStyle
|
||||||
|
import space.kscience.visionforge.react.EditorPropertyState
|
||||||
|
import space.kscience.visionforge.react.PropertyEditor
|
||||||
|
import space.kscience.visionforge.react.metaViewer
|
||||||
|
import space.kscience.visionforge.react.render
|
||||||
|
import space.kscience.visionforge.root
|
||||||
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
|
import space.kscience.visionforge.styles
|
||||||
|
|
||||||
|
public fun RBuilder.visionPropertyEditor(
|
||||||
|
vision: Vision,
|
||||||
|
descriptor: MetaDescriptor? = vision.descriptor,
|
||||||
|
key: Any? = null,
|
||||||
|
) {
|
||||||
|
|
||||||
|
card("Properties") {
|
||||||
|
child(PropertyEditor) {
|
||||||
|
attrs {
|
||||||
|
this.key = key?.toString()
|
||||||
|
this.meta = vision.properties.root()
|
||||||
|
this.updates = vision.properties.changes
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
|
||||||
|
this.getPropertyState = { name ->
|
||||||
|
val ownMeta = vision.properties.own?.get(name)
|
||||||
|
if (ownMeta != null && !ownMeta.isEmpty()) {
|
||||||
|
EditorPropertyState.Defined
|
||||||
|
} else if (vision.properties.root().getValue(name) != null) {
|
||||||
|
// TODO differentiate
|
||||||
|
EditorPropertyState.Default()
|
||||||
|
} else {
|
||||||
|
EditorPropertyState.Undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val styles = if (vision is SolidReference) {
|
||||||
|
(vision.styles + vision.prototype.styles).distinct()
|
||||||
|
} else {
|
||||||
|
vision.styles
|
||||||
|
}
|
||||||
|
if (styles.isNotEmpty()) {
|
||||||
|
card("Styles") {
|
||||||
|
accordion("styles") {
|
||||||
|
styles.forEach { styleName ->
|
||||||
|
val style = vision.getStyle(styleName)
|
||||||
|
if (style != null) {
|
||||||
|
entry(styleName) {
|
||||||
|
metaViewer(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Element.visionPropertyEditor(
|
||||||
|
item: Vision,
|
||||||
|
descriptor: MetaDescriptor? = item.descriptor,
|
||||||
|
): Unit = space.kscience.visionforge.react.createRoot(this).render {
|
||||||
|
visionPropertyEditor(item, descriptor = descriptor)
|
||||||
|
}
|
56
ui/bootstrap/src/jsMain/resources/css/custom-bootstrap.css
Normal file
56
ui/bootstrap/src/jsMain/resources/css/custom-bootstrap.css
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*full height*/
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-fluid { height: inherit; }
|
||||||
|
|
||||||
|
/* Remove default bullets */
|
||||||
|
ul, .tree {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the caret/arrow */
|
||||||
|
.tree-caret {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none; /* Prevent text selection */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the caret/arrow with a unicode, and style it */
|
||||||
|
.tree-caret::before {
|
||||||
|
content: "\25B6";
|
||||||
|
color: black;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-leaf{
|
||||||
|
user-select: none;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-leaf::before {
|
||||||
|
content: "\25C6";
|
||||||
|
color: black;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
|
||||||
|
.tree-caret-down::before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-label-inactive {
|
||||||
|
color: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-label-selected{
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding{
|
||||||
|
padding: 0;
|
||||||
|
}
|
4
ui/react/README.md
Normal file
4
ui/react/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Module react
|
||||||
|
|
||||||
|
|
||||||
|
|
16
ui/react/build.gradle.kts
Normal file
16
ui/react/build.gradle.kts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
plugins {
|
||||||
|
id("space.kscience.gradle.mpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
kscience {
|
||||||
|
js()
|
||||||
|
jsMain {
|
||||||
|
dependencies {
|
||||||
|
api(projects.visionforgeSolid)
|
||||||
|
api("org.jetbrains.kotlin-wrappers:kotlin-styled")
|
||||||
|
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
|
||||||
|
// implementation(npm("react-select","4.3.0"))
|
||||||
|
api(projects.visionforgeThreejs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.Align
|
||||||
|
import kotlinx.css.alignItems
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.*
|
||||||
|
import react.dom.a
|
||||||
|
import react.dom.attrs
|
||||||
|
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
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
import styled.styledSpan
|
||||||
|
|
||||||
|
public external interface MetaViewerProps : Props {
|
||||||
|
/**
|
||||||
|
* Root meta
|
||||||
|
*/
|
||||||
|
public var root: Meta
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The title of root node
|
||||||
|
*/
|
||||||
|
public var rootName: String?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full path to the displayed node in [root]. Could be empty
|
||||||
|
*/
|
||||||
|
public var name: Name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root descriptor
|
||||||
|
*/
|
||||||
|
public var descriptor: MetaDescriptor?
|
||||||
|
}
|
||||||
|
|
||||||
|
private val MetaViewerItem: FC<MetaViewerProps> = fc("MetaViewerItem") { props ->
|
||||||
|
metaViewerItem(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
|
||||||
|
var expanded: Boolean by useState { true }
|
||||||
|
val item = props.root[props.name]
|
||||||
|
val descriptorItem: MetaDescriptor? = props.descriptor?.get(props.name)
|
||||||
|
val actualValue = item?.value ?: descriptorItem?.defaultValue
|
||||||
|
val actualMeta = item ?: descriptorItem?.defaultNode
|
||||||
|
|
||||||
|
val token = props.name.lastOrNull()?.toString() ?: props.rootName ?: ""
|
||||||
|
|
||||||
|
val expanderClick: (Event) -> Unit = {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
flexRow {
|
||||||
|
css {
|
||||||
|
alignItems = Align.center
|
||||||
|
}
|
||||||
|
if (actualMeta?.isLeaf == false) {
|
||||||
|
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,38 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import org.w3c.dom.HTMLOptionElement
|
||||||
|
import org.w3c.dom.HTMLSelectElement
|
||||||
|
import org.w3c.dom.asList
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.FC
|
||||||
|
import react.dom.attrs
|
||||||
|
import react.dom.option
|
||||||
|
import react.dom.select
|
||||||
|
import react.fc
|
||||||
|
import space.kscience.dataforge.meta.asValue
|
||||||
|
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||||
|
import space.kscience.dataforge.meta.string
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val MultiSelectChooser: FC<ValueChooserProps> = fc("MultiSelectChooser") { props ->
|
||||||
|
val onChange: (Event) -> Unit = { event: Event ->
|
||||||
|
val newSelected = (event.target as HTMLSelectElement).selectedOptions.asList()
|
||||||
|
.map { (it as HTMLOptionElement).value.asValue() }
|
||||||
|
props.onValueChange(newSelected.asValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
attrs {
|
||||||
|
multiple = true
|
||||||
|
values = (props.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
|
||||||
|
onChangeFunction = onChange
|
||||||
|
}
|
||||||
|
props.descriptor?.allowedValues?.forEach { optionValue ->
|
||||||
|
option {
|
||||||
|
+optionValue.string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,277 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.css.*
|
||||||
|
import kotlinx.css.properties.TextDecoration
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.*
|
||||||
|
import react.dom.attrs
|
||||||
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
|
import space.kscience.dataforge.meta.ObservableMutableMeta
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.ValueRestriction
|
||||||
|
import space.kscience.dataforge.meta.descriptors.get
|
||||||
|
import space.kscience.dataforge.meta.remove
|
||||||
|
import space.kscience.dataforge.names.*
|
||||||
|
import space.kscience.visionforge.hidden
|
||||||
|
import styled.css
|
||||||
|
import styled.styledButton
|
||||||
|
import styled.styledDiv
|
||||||
|
import styled.styledSpan
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display state of a property
|
||||||
|
*/
|
||||||
|
public sealed class EditorPropertyState {
|
||||||
|
public object Defined : EditorPropertyState()
|
||||||
|
public class Default(public val source: String = "unknown") : EditorPropertyState()
|
||||||
|
|
||||||
|
public object Undefined : EditorPropertyState()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public external interface PropertyEditorProps : Props {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root config object - always non-null
|
||||||
|
*/
|
||||||
|
public var meta: MutableMeta
|
||||||
|
|
||||||
|
public var getPropertyState: (Name) -> EditorPropertyState
|
||||||
|
|
||||||
|
public var scope: CoroutineScope
|
||||||
|
|
||||||
|
public var updates: Flow<Name>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full path to the displayed node in [meta]. Could be empty
|
||||||
|
*/
|
||||||
|
public var name: Name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root descriptor
|
||||||
|
*/
|
||||||
|
public var descriptor: MetaDescriptor?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial expanded state
|
||||||
|
*/
|
||||||
|
public var expanded: Boolean?
|
||||||
|
}
|
||||||
|
|
||||||
|
private val PropertyEditorItem: FC<PropertyEditorProps> = fc("PropertyEditorItem") { props ->
|
||||||
|
propertyEditorItem(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||||
|
var expanded: Boolean by useState { props.expanded ?: true }
|
||||||
|
val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) }
|
||||||
|
var property: MutableMeta by useState { props.meta.getOrCreate(props.name) }
|
||||||
|
var editorPropertyState: EditorPropertyState by useState { props.getPropertyState(props.name) }
|
||||||
|
|
||||||
|
|
||||||
|
val keys = useMemo(descriptor) {
|
||||||
|
buildSet {
|
||||||
|
descriptor?.children?.filterNot {
|
||||||
|
it.key.startsWith("@") || it.value.hidden
|
||||||
|
}?.forEach {
|
||||||
|
add(NameToken(it.key))
|
||||||
|
}
|
||||||
|
//ownProperty?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val token = props.name.lastOrNull()?.toString() ?: "Properties"
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
property = props.meta.getOrCreate(props.name)
|
||||||
|
editorPropertyState = props.getPropertyState(props.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(props.meta) {
|
||||||
|
val job = props.updates.onEach { updatedName ->
|
||||||
|
if (updatedName == props.name) {
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
}.launchIn(props.scope)
|
||||||
|
|
||||||
|
cleanup {
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val expanderClick: (Event) -> Unit = {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
val removeClick: (Event) -> Unit = {
|
||||||
|
props.meta.remove(props.name)
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
flexRow {
|
||||||
|
css {
|
||||||
|
alignItems = Align.center
|
||||||
|
}
|
||||||
|
if (keys.isNotEmpty()) {
|
||||||
|
styledSpan {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeCaret
|
||||||
|
if (expanded) {
|
||||||
|
+TreeStyles.treeCaredDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
onClickFunction = expanderClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
styledSpan {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeLabel
|
||||||
|
if (editorPropertyState != EditorPropertyState.Defined) {
|
||||||
|
+TreeStyles.treeLabelInactive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+token
|
||||||
|
}
|
||||||
|
if (!props.name.isEmpty() && descriptor?.valueRestriction != ValueRestriction.ABSENT) {
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
//+TreeStyles.resizeableInput
|
||||||
|
width = 160.px
|
||||||
|
margin = Margin(1.px, 5.px)
|
||||||
|
}
|
||||||
|
ValueChooser {
|
||||||
|
attrs {
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.state = editorPropertyState
|
||||||
|
this.value = property.value
|
||||||
|
this.onValueChange = {
|
||||||
|
property.value = it
|
||||||
|
editorPropertyState = props.getPropertyState(props.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styledButton {
|
||||||
|
css {
|
||||||
|
width = 24.px
|
||||||
|
alignSelf = Align.stretch
|
||||||
|
margin = Margin(1.px, 5.px)
|
||||||
|
backgroundColor = Color.white
|
||||||
|
borderStyle = BorderStyle.solid
|
||||||
|
borderRadius = 2.px
|
||||||
|
textAlign = TextAlign.center
|
||||||
|
textDecoration = TextDecoration.none
|
||||||
|
cursor = Cursor.pointer
|
||||||
|
disabled {
|
||||||
|
cursor = Cursor.auto
|
||||||
|
borderStyle = BorderStyle.dashed
|
||||||
|
color = Color.lightGray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+"\u00D7"
|
||||||
|
attrs {
|
||||||
|
if (editorPropertyState != EditorPropertyState.Defined) {
|
||||||
|
disabled = true
|
||||||
|
} else {
|
||||||
|
onClickFunction = removeClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expanded) {
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
+TreeStyles.tree
|
||||||
|
}
|
||||||
|
keys.forEach { token ->
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeItem
|
||||||
|
}
|
||||||
|
child(PropertyEditorItem) {
|
||||||
|
attrs {
|
||||||
|
this.key = props.name.toString()
|
||||||
|
this.meta = props.meta
|
||||||
|
this.name = props.name + token
|
||||||
|
this.descriptor = props.descriptor
|
||||||
|
this.scope = props.scope
|
||||||
|
this.getPropertyState = { props.getPropertyState(props.name + token) }
|
||||||
|
this.updates = props.updates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//configEditor(props.root, props.name + token, props.descriptor, props.default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val PropertyEditor: FC<PropertyEditorProps> = fc("PropertyEditor") { props ->
|
||||||
|
child(PropertyEditorItem) {
|
||||||
|
attrs {
|
||||||
|
this.key = ""
|
||||||
|
this.meta = props.meta
|
||||||
|
this.name = Name.EMPTY
|
||||||
|
this.descriptor = props.descriptor
|
||||||
|
this.expanded = props.expanded
|
||||||
|
this.scope = props.scope
|
||||||
|
this.getPropertyState = props.getPropertyState
|
||||||
|
this.updates = props.updates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
public fun RBuilder.propertyEditor(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
properties: ObservableMutableMeta,
|
||||||
|
descriptor: MetaDescriptor? = null,
|
||||||
|
key: Any? = null,
|
||||||
|
expanded: Boolean? = null,
|
||||||
|
) {
|
||||||
|
child(PropertyEditor) {
|
||||||
|
attrs {
|
||||||
|
this.meta = properties
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.key = key?.toString() ?: ""
|
||||||
|
this.expanded = expanded
|
||||||
|
this.scope = scope
|
||||||
|
this.getPropertyState = { name ->
|
||||||
|
if (properties[name] != null) {
|
||||||
|
EditorPropertyState.Defined
|
||||||
|
} else if (descriptor?.get(name)?.defaultValue != null) {
|
||||||
|
EditorPropertyState.Default("descriptor")
|
||||||
|
} else {
|
||||||
|
EditorPropertyState.Undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.updates = callbackFlow {
|
||||||
|
properties.onChange(scope) { name ->
|
||||||
|
scope.launch {
|
||||||
|
send(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeOnClose {
|
||||||
|
properties.removeListener(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.pct
|
||||||
|
import kotlinx.css.width
|
||||||
|
import kotlinx.html.InputType
|
||||||
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import kotlinx.html.js.onInputFunction
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.FC
|
||||||
|
import react.dom.attrs
|
||||||
|
import react.fc
|
||||||
|
import react.useState
|
||||||
|
import space.kscience.dataforge.meta.asValue
|
||||||
|
import space.kscience.dataforge.meta.descriptors.ValueRestriction
|
||||||
|
import space.kscience.dataforge.meta.double
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.string
|
||||||
|
import styled.css
|
||||||
|
import styled.styledInput
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") { props ->
|
||||||
|
var innerValue by useState(props.value?.double)
|
||||||
|
var rangeDisabled: Boolean by useState(props.state != EditorPropertyState.Defined)
|
||||||
|
|
||||||
|
val handleDisable: (Event) -> Unit = {
|
||||||
|
val checkBoxValue = (it.target as HTMLInputElement).checked
|
||||||
|
rangeDisabled = !checkBoxValue
|
||||||
|
props.onValueChange(
|
||||||
|
if (!checkBoxValue) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
innerValue?.asValue()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val handleChange: (Event) -> Unit = {
|
||||||
|
val newValue = (it.target as HTMLInputElement).value
|
||||||
|
props.onValueChange(newValue.toDoubleOrNull()?.asValue())
|
||||||
|
innerValue = newValue.toDoubleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
flexRow {
|
||||||
|
if (props.descriptor?.valueRestriction != ValueRestriction.REQUIRED) {
|
||||||
|
styledInput(type = InputType.checkBox) {
|
||||||
|
attrs {
|
||||||
|
defaultChecked = rangeDisabled.not()
|
||||||
|
onChangeFunction = handleDisable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styledInput(type = InputType.range) {
|
||||||
|
css {
|
||||||
|
width = 100.pct
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
disabled = rangeDisabled
|
||||||
|
value = innerValue?.toString() ?: ""
|
||||||
|
// onChangeFunction = handleChange
|
||||||
|
onInputFunction = handleChange
|
||||||
|
val minValue = props.descriptor?.attributes?.get("min").string
|
||||||
|
minValue?.let {
|
||||||
|
min = it
|
||||||
|
}
|
||||||
|
val maxValue = props.descriptor?.attributes?.get("max").string
|
||||||
|
maxValue?.let {
|
||||||
|
max = it
|
||||||
|
}
|
||||||
|
props.descriptor?.attributes?.get("step").string?.let {
|
||||||
|
step = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.*
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import react.*
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
|
import space.kscience.dataforge.context.request
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.solid.Solid
|
||||||
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import space.kscience.visionforge.solid.three.ThreeCanvas
|
||||||
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
|
||||||
|
public external interface ThreeCanvasProps : Props {
|
||||||
|
public var context: Context
|
||||||
|
public var options: Canvas3DOptions?
|
||||||
|
public var solid: Solid?
|
||||||
|
public var selected: Name?
|
||||||
|
}
|
||||||
|
|
||||||
|
public val ThreeCanvasComponent: FC<ThreeCanvasProps> = fc("ThreeCanvasComponent") { props ->
|
||||||
|
val elementRef = useRef<Element>(null)
|
||||||
|
var canvas by useState<ThreeCanvas?>(null)
|
||||||
|
|
||||||
|
val three: ThreePlugin = useMemo(props.context) { props.context.request(ThreePlugin) }
|
||||||
|
|
||||||
|
useEffect(props.solid, props.options, elementRef) {
|
||||||
|
if (canvas == null) {
|
||||||
|
val element = elementRef.current ?: error("Canvas element not found")
|
||||||
|
canvas = ThreeCanvas(three, element, props.options ?: Canvas3DOptions())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(canvas, props.solid) {
|
||||||
|
props.solid?.let { obj ->
|
||||||
|
canvas?.render(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(canvas, props.selected) {
|
||||||
|
canvas?.select(props.selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
maxWidth = 100.vw
|
||||||
|
maxHeight = 100.vh
|
||||||
|
width = 100.pct
|
||||||
|
height = 100.pct
|
||||||
|
}
|
||||||
|
ref = elementRef
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.*
|
||||||
|
import kotlinx.css.properties.deg
|
||||||
|
import kotlinx.css.properties.rotate
|
||||||
|
import styled.StyleSheet
|
||||||
|
|
||||||
|
public object TreeStyles : StyleSheet("treeStyles", true) {
|
||||||
|
/**
|
||||||
|
* Remove default bullets
|
||||||
|
*/
|
||||||
|
public val tree: RuleSet by css {
|
||||||
|
paddingLeft = 5.px
|
||||||
|
marginLeft = 0.px
|
||||||
|
listStyleType = ListStyleType.none
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style the caret/arrow
|
||||||
|
*/
|
||||||
|
public val treeCaret: RuleSet by css {
|
||||||
|
cursor = Cursor.pointer
|
||||||
|
userSelect = UserSelect.none
|
||||||
|
/* Create the caret/arrow with a unicode, and style it */
|
||||||
|
before {
|
||||||
|
content = "\u25B6".quoted
|
||||||
|
color = Color.black
|
||||||
|
display = Display.inlineBlock
|
||||||
|
marginRight = 6.px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate the caret/arrow icon when clicked on (using JavaScript)
|
||||||
|
*/
|
||||||
|
public val treeCaredDown:RuleSet by css {
|
||||||
|
before {
|
||||||
|
content = "\u25B6".quoted
|
||||||
|
color = Color.black
|
||||||
|
display = Display.inlineBlock
|
||||||
|
marginRight = 6.px
|
||||||
|
transform.rotate(90.deg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeItem:RuleSet by css {
|
||||||
|
alignItems = Align.center
|
||||||
|
paddingLeft = 10.px
|
||||||
|
borderLeftStyle = BorderStyle.dashed
|
||||||
|
borderLeftWidth = 1.px
|
||||||
|
borderLeftColor = Color.lightGray
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeLabel:RuleSet by css {
|
||||||
|
border = Border.none
|
||||||
|
padding = Padding(left = 4.pt, right = 4.pt, top = 0.pt, bottom = 0.pt)
|
||||||
|
textAlign = TextAlign.left
|
||||||
|
flex = Flex(1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeLabelInactive: RuleSet by css {
|
||||||
|
color = Color.lightGray
|
||||||
|
}
|
||||||
|
|
||||||
|
public val treeLabelSelected:RuleSet by css {
|
||||||
|
backgroundColor = Color.lightBlue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.*
|
||||||
|
import kotlinx.css.properties.TextDecoration
|
||||||
|
import kotlinx.css.properties.TextDecorationLine
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.*
|
||||||
|
import react.dom.attrs
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.lastOrNull
|
||||||
|
import space.kscience.dataforge.names.plus
|
||||||
|
import space.kscience.dataforge.names.startsWith
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.VisionGroup
|
||||||
|
import space.kscience.visionforge.asSequence
|
||||||
|
import space.kscience.visionforge.isEmpty
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
import styled.styledSpan
|
||||||
|
|
||||||
|
public external interface ObjectTreeProps : Props {
|
||||||
|
public var name: Name
|
||||||
|
public var selected: Name?
|
||||||
|
public var obj: Vision
|
||||||
|
public var clickCallback: (Name) -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
private val TreeLabel = fc<ObjectTreeProps> { props ->
|
||||||
|
val token = useMemo(props.name) { props.name.lastOrNull()?.toString() ?: "World" }
|
||||||
|
styledSpan {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeLabel
|
||||||
|
color = Color("#069")
|
||||||
|
cursor = Cursor.pointer
|
||||||
|
hover {
|
||||||
|
textDecoration = TextDecoration(setOf(TextDecorationLine.underline))
|
||||||
|
}
|
||||||
|
if (props.name == props.selected) {
|
||||||
|
+TreeStyles.treeLabelSelected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+token
|
||||||
|
attrs {
|
||||||
|
onClickFunction = { props.clickCallback(props.name) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun RBuilder.visionTree(props: ObjectTreeProps): Unit {
|
||||||
|
var expanded: Boolean by useState { props.selected?.startsWith(props.name) ?: false }
|
||||||
|
|
||||||
|
val onClick: (Event) -> Unit = {
|
||||||
|
expanded = !expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
val obj = props.obj
|
||||||
|
|
||||||
|
//display as node if any child is visible
|
||||||
|
if (obj is VisionGroup) {
|
||||||
|
flexRow {
|
||||||
|
if (obj.children.keys.any { !it.body.startsWith("@") }) {
|
||||||
|
styledSpan {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeCaret
|
||||||
|
if (expanded) {
|
||||||
|
+TreeStyles.treeCaredDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
onClickFunction = onClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
child(TreeLabel, props = props)
|
||||||
|
}
|
||||||
|
if (expanded) {
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
+TreeStyles.tree
|
||||||
|
}
|
||||||
|
obj.children.asSequence()
|
||||||
|
.filter { !it.first.toString().startsWith("@") } // ignore statics and other hidden children
|
||||||
|
.sortedBy { (it.second as? VisionGroup)?.children?.isEmpty() ?: true } // ignore empty groups
|
||||||
|
.forEach { (childToken, child) ->
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
+TreeStyles.treeItem
|
||||||
|
}
|
||||||
|
child(ObjectTree) {
|
||||||
|
attrs {
|
||||||
|
this.name = props.name + childToken
|
||||||
|
this.obj = child
|
||||||
|
this.selected = props.selected
|
||||||
|
this.clickCallback = props.clickCallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
child(TreeLabel, props = props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ObjectTree: FC<ObjectTreeProps> = fc("ObjectTree") { props ->
|
||||||
|
visionTree(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.visionTree(
|
||||||
|
vision: Vision,
|
||||||
|
selected: Name? = null,
|
||||||
|
clickCallback: (Name) -> Unit = {},
|
||||||
|
) {
|
||||||
|
child(ObjectTree) {
|
||||||
|
attrs {
|
||||||
|
this.name = Name.EMPTY
|
||||||
|
this.obj = vision
|
||||||
|
this.selected = selected
|
||||||
|
this.clickCallback = clickCallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
@file:JsModule("react-dom/client")
|
||||||
|
@file:JsNonModule
|
||||||
|
|
||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import react.dom.client.Root
|
||||||
|
import react.dom.client.RootOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compatibility method to work with old browser API
|
||||||
|
*/
|
||||||
|
public external fun createRoot(
|
||||||
|
container: Element,
|
||||||
|
options: RootOptions = definedExternally,
|
||||||
|
): Root
|
@ -0,0 +1,10 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import react.Props
|
||||||
|
import react.RBuilder
|
||||||
|
import react.createElement
|
||||||
|
import react.dom.client.Root
|
||||||
|
|
||||||
|
public fun Root.render(block: RBuilder.() -> Unit) {
|
||||||
|
render(createElement<Props>(block))
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.Display
|
||||||
|
import kotlinx.css.FlexDirection
|
||||||
|
import kotlinx.css.display
|
||||||
|
import kotlinx.css.flexDirection
|
||||||
|
import kotlinx.html.DIV
|
||||||
|
import react.RBuilder
|
||||||
|
import styled.StyledDOMBuilder
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
|
||||||
|
public inline fun RBuilder.flexColumn(
|
||||||
|
block: StyledDOMBuilder<DIV>.() -> Unit
|
||||||
|
): Unit = styledDiv {
|
||||||
|
css {
|
||||||
|
display = Display.flex
|
||||||
|
flexDirection = FlexDirection.column
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun RBuilder.flexRow(
|
||||||
|
block: StyledDOMBuilder<DIV>.() -> Unit
|
||||||
|
): Unit = styledDiv {
|
||||||
|
css {
|
||||||
|
display = Display.flex
|
||||||
|
flexDirection = FlexDirection.row
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
@ -0,0 +1,175 @@
|
|||||||
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import kotlinx.css.*
|
||||||
|
import kotlinx.html.InputType
|
||||||
|
import kotlinx.html.js.onChangeFunction
|
||||||
|
import kotlinx.html.js.onKeyDownFunction
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
import org.w3c.dom.HTMLSelectElement
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import react.FC
|
||||||
|
import react.Props
|
||||||
|
import react.dom.attrs
|
||||||
|
import react.dom.option
|
||||||
|
import react.fc
|
||||||
|
import react.useState
|
||||||
|
import space.kscience.dataforge.meta.*
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.descriptors.allowedValues
|
||||||
|
import space.kscience.visionforge.Colors
|
||||||
|
import space.kscience.visionforge.widgetType
|
||||||
|
import styled.css
|
||||||
|
import styled.styledInput
|
||||||
|
import styled.styledSelect
|
||||||
|
import three.math.Color
|
||||||
|
|
||||||
|
public external interface ValueChooserProps : Props {
|
||||||
|
public var descriptor: MetaDescriptor?
|
||||||
|
public var state: EditorPropertyState
|
||||||
|
public var value: Value?
|
||||||
|
public var onValueChange: (Value?) -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser") { props ->
|
||||||
|
var value by useState(props.value?.string ?: "")
|
||||||
|
val keyDown: (Event) -> Unit = { event ->
|
||||||
|
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
|
||||||
|
value = (event.target as HTMLInputElement).value
|
||||||
|
props.onValueChange(value.asValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val handleChange: (Event) -> Unit = {
|
||||||
|
value = (it.target as HTMLInputElement).value
|
||||||
|
}
|
||||||
|
styledInput(type = InputType.text) {
|
||||||
|
css {
|
||||||
|
width = 100.pct
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
this.value = value
|
||||||
|
onKeyDownFunction = keyDown
|
||||||
|
onChangeFunction = handleChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser") { props ->
|
||||||
|
val handleChange: (Event) -> Unit = {
|
||||||
|
val newValue = (it.target as HTMLInputElement).checked
|
||||||
|
props.onValueChange(newValue.asValue())
|
||||||
|
}
|
||||||
|
styledInput(type = InputType.checkBox) {
|
||||||
|
css {
|
||||||
|
width = 100.pct
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
//this.attributes["indeterminate"] = (props.item == null).toString()
|
||||||
|
checked = props.value?.boolean ?: false
|
||||||
|
onChangeFunction = handleChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser") { props ->
|
||||||
|
var innerValue by useState(props.value?.string ?: "")
|
||||||
|
val keyDown: (Event) -> Unit = { event ->
|
||||||
|
if (event.type == "keydown" && event.asDynamic().key == "Enter") {
|
||||||
|
innerValue = (event.target as HTMLInputElement).value
|
||||||
|
val number = innerValue.toDoubleOrNull()
|
||||||
|
if (number == null) {
|
||||||
|
console.error("The input value $innerValue is not a number")
|
||||||
|
} else {
|
||||||
|
props.onValueChange(number.asValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val handleChange: (Event) -> Unit = {
|
||||||
|
innerValue = (it.target as HTMLInputElement).value
|
||||||
|
}
|
||||||
|
styledInput(type = InputType.number) {
|
||||||
|
css {
|
||||||
|
width = 100.pct
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
value = innerValue
|
||||||
|
onKeyDownFunction = keyDown
|
||||||
|
onChangeFunction = handleChange
|
||||||
|
props.descriptor?.attributes?.get("step").string?.let {
|
||||||
|
step = it
|
||||||
|
}
|
||||||
|
props.descriptor?.attributes?.get("min").string?.let {
|
||||||
|
min = it
|
||||||
|
}
|
||||||
|
props.descriptor?.attributes?.get("max").string?.let {
|
||||||
|
max = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") { props ->
|
||||||
|
var selected by useState(props.value?.string ?: "")
|
||||||
|
val handleChange: (Event) -> Unit = {
|
||||||
|
selected = (it.target as HTMLSelectElement).value
|
||||||
|
props.onValueChange(selected.asValue())
|
||||||
|
}
|
||||||
|
styledSelect {
|
||||||
|
css {
|
||||||
|
width = 100.pct
|
||||||
|
}
|
||||||
|
props.descriptor?.allowedValues?.forEach {
|
||||||
|
option {
|
||||||
|
+it.string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
this.value = props.value?.string ?: ""
|
||||||
|
multiple = false
|
||||||
|
onChangeFunction = handleChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") { props ->
|
||||||
|
val handleChange: (Event) -> Unit = {
|
||||||
|
props.onValueChange((it.target as HTMLInputElement).value.asValue())
|
||||||
|
}
|
||||||
|
styledInput(type = InputType.color) {
|
||||||
|
css {
|
||||||
|
width = 100.pct
|
||||||
|
margin = Margin(0.px)
|
||||||
|
}
|
||||||
|
attrs {
|
||||||
|
this.value = props.value?.let { value ->
|
||||||
|
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
||||||
|
else "#" + Color(value.string).getHexString()
|
||||||
|
} ?: "#000000"
|
||||||
|
onChangeFunction = handleChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ValueChooser: FC<ValueChooserProps> = fc("ValueChooser") { props ->
|
||||||
|
val rawInput by useState(false)
|
||||||
|
|
||||||
|
val descriptor = props.descriptor
|
||||||
|
val type = descriptor?.valueTypes?.firstOrNull()
|
||||||
|
|
||||||
|
when {
|
||||||
|
rawInput -> child(StringValueChooser, props)
|
||||||
|
descriptor?.widgetType == "color" -> child(ColorValueChooser, props)
|
||||||
|
descriptor?.widgetType == "multiSelect" -> child(MultiSelectChooser, props)
|
||||||
|
descriptor?.widgetType == "range" -> child(RangeValueChooser, props)
|
||||||
|
type == ValueType.BOOLEAN -> child(BooleanValueChooser, props)
|
||||||
|
type == ValueType.NUMBER -> child(NumberValueChooser, props)
|
||||||
|
descriptor?.allowedValues?.isNotEmpty() ?: false -> child(ComboValueChooser, props)
|
||||||
|
//TODO handle lists
|
||||||
|
else -> child(StringValueChooser, props)
|
||||||
|
}
|
||||||
|
}
|
4
ui/ring/README.md
Normal file
4
ui/ring/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Module ring
|
||||||
|
|
||||||
|
|
||||||
|
|
25
ui/ring/build.gradle.kts
Normal file
25
ui/ring/build.gradle.kts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
plugins {
|
||||||
|
id("space.kscience.gradle.mpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataforgeVersion: String by rootProject.extra
|
||||||
|
|
||||||
|
kscience{
|
||||||
|
js{
|
||||||
|
useCommonJs()
|
||||||
|
browser {
|
||||||
|
commonWebpackConfig {
|
||||||
|
cssSupport{
|
||||||
|
enabled.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsMain{
|
||||||
|
api(projects.ui.react)
|
||||||
|
api("org.jetbrains.kotlin-wrappers:kotlin-ring-ui")
|
||||||
|
|
||||||
|
implementation(npm("core-js","3.12.1"))
|
||||||
|
implementation(npm("file-saver", "2.0.2"))
|
||||||
|
}
|
||||||
|
}
|
20
ui/ring/src/jsMain/kotlin/ringui/Loader.kt
Normal file
20
ui/ring/src/jsMain/kotlin/ringui/Loader.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@file:JsModule("@jetbrains/ring-ui/components/loader/loader")
|
||||||
|
@file:JsNonModule
|
||||||
|
|
||||||
|
package ringui
|
||||||
|
|
||||||
|
import react.ComponentClass
|
||||||
|
import react.PropsWithClassName
|
||||||
|
|
||||||
|
|
||||||
|
// https://github.com/JetBrains/ring-ui/blob/master/components/loader/loader.js
|
||||||
|
public external interface LoaderProps : PropsWithClassName {
|
||||||
|
public var size: Number
|
||||||
|
public var colors: Array<String>
|
||||||
|
public var message: String
|
||||||
|
public var stop: Boolean
|
||||||
|
public var deterministic: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsName("default")
|
||||||
|
public external val Loader: ComponentClass<LoaderProps>
|
16
ui/ring/src/jsMain/kotlin/ringui/LoaderScreen.kt
Normal file
16
ui/ring/src/jsMain/kotlin/ringui/LoaderScreen.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@file:JsModule("@jetbrains/ring-ui/components/loader-screen/loader-screen")
|
||||||
|
@file:JsNonModule
|
||||||
|
|
||||||
|
package ringui
|
||||||
|
|
||||||
|
import react.ComponentClass
|
||||||
|
import react.PropsWithClassName
|
||||||
|
|
||||||
|
// https://github.com/JetBrains/ring-ui/blob/master/components/loader-screen/loader-screen.js
|
||||||
|
public external interface LoaderScreenProps : PropsWithClassName {
|
||||||
|
public var containerClassName: String
|
||||||
|
public var message: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsName("default")
|
||||||
|
public external val LoaderScreen: ComponentClass<LoaderScreenProps>
|
@ -0,0 +1,212 @@
|
|||||||
|
package space.kscience.visionforge.ring
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.css.*
|
||||||
|
import react.*
|
||||||
|
import react.dom.b
|
||||||
|
import react.dom.div
|
||||||
|
import react.dom.p
|
||||||
|
import react.dom.span
|
||||||
|
import ringui.*
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.isEmpty
|
||||||
|
import space.kscience.dataforge.names.length
|
||||||
|
import space.kscience.visionforge.*
|
||||||
|
import space.kscience.visionforge.react.*
|
||||||
|
import space.kscience.visionforge.solid.Solid
|
||||||
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
|
import space.kscience.visionforge.solid.Solids
|
||||||
|
import space.kscience.visionforge.solid.solidGroup
|
||||||
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import styled.css
|
||||||
|
import styled.styledDiv
|
||||||
|
|
||||||
|
public external interface ThreeCanvasWithControlsProps : Props {
|
||||||
|
public var solids: Solids
|
||||||
|
public var builderOfSolid: Deferred<Solid?>
|
||||||
|
public var selected: Name?
|
||||||
|
public var options: Canvas3DOptions?
|
||||||
|
public var additionalTabs: Map<String, RBuilder.() -> Unit>?
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ThreeCanvasWithControlsProps.context get() = solids.context
|
||||||
|
|
||||||
|
public fun ThreeCanvasWithControlsProps.solid(block: SolidGroup.() -> Unit) {
|
||||||
|
builderOfSolid = context.async {
|
||||||
|
solids.solidGroup(null, block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun ThreeCanvasWithControlsProps.options(block: Canvas3DOptions.() -> Unit) {
|
||||||
|
options = Canvas3DOptions(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) {
|
||||||
|
additionalTabs = (additionalTabs ?: emptyMap()) + (title to block)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): Unit = styledDiv {
|
||||||
|
div {
|
||||||
|
Link {
|
||||||
|
attrs {
|
||||||
|
onClick = {
|
||||||
|
link(Name.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+"\u2302"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name != null) {
|
||||||
|
val tokens = ArrayList<NameToken>(name.length)
|
||||||
|
name.tokens.forEach { token ->
|
||||||
|
tokens.add(token)
|
||||||
|
val fullName = Name(tokens.toList())
|
||||||
|
span { +"." }
|
||||||
|
Link {
|
||||||
|
+token.toString()
|
||||||
|
attrs {
|
||||||
|
onClick = {
|
||||||
|
console.log("Selected = $fullName")
|
||||||
|
link(fullName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("ThreeViewWithControls") { props ->
|
||||||
|
var selected: Name? by useState { props.selected }
|
||||||
|
var solid: Solid? by useState(null)
|
||||||
|
|
||||||
|
useEffect {
|
||||||
|
props.context.launch {
|
||||||
|
solid = props.builderOfSolid.await()
|
||||||
|
//ensure that the solid is properly rooted
|
||||||
|
if (solid?.parent == null) {
|
||||||
|
solid?.setAsRoot(props.context.visionManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val onSelect: (Name?) -> Unit = {
|
||||||
|
selected = it
|
||||||
|
}
|
||||||
|
|
||||||
|
val options = useMemo(props.options) {
|
||||||
|
(props.options ?: Canvas3DOptions()).apply {
|
||||||
|
this.onSelect = onSelect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val selectedVision: Vision? = useMemo(props.builderOfSolid, selected) {
|
||||||
|
selected?.let {
|
||||||
|
when {
|
||||||
|
it.isEmpty() -> solid
|
||||||
|
else -> (solid as? SolidGroup)?.get(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
flexRow {
|
||||||
|
css {
|
||||||
|
height = 100.pct
|
||||||
|
width = 100.pct
|
||||||
|
flexWrap = FlexWrap.wrap
|
||||||
|
alignItems = Align.stretch
|
||||||
|
alignContent = Align.stretch
|
||||||
|
}
|
||||||
|
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
height = 100.pct
|
||||||
|
minWidth = 600.px
|
||||||
|
flex = Flex(10.0, 1.0, FlexBasis("600px"))
|
||||||
|
position = Position.relative
|
||||||
|
}
|
||||||
|
|
||||||
|
if (solid == null) {
|
||||||
|
LoaderScreen {
|
||||||
|
attrs {
|
||||||
|
message = "Loading Three vision"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
child(ThreeCanvasComponent) {
|
||||||
|
attrs {
|
||||||
|
this.context = props.context
|
||||||
|
this.solid = solid
|
||||||
|
this.selected = selected
|
||||||
|
this.options = options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedVision?.let { vision ->
|
||||||
|
styledDiv {
|
||||||
|
css {
|
||||||
|
position = Position.absolute
|
||||||
|
top = 5.px
|
||||||
|
right = 5.px
|
||||||
|
width = 450.px
|
||||||
|
}
|
||||||
|
Island {
|
||||||
|
IslandHeader {
|
||||||
|
attrs {
|
||||||
|
border = true
|
||||||
|
}
|
||||||
|
nameCrumbs(selected) { selected = it }
|
||||||
|
}
|
||||||
|
IslandContent {
|
||||||
|
child(PropertyEditor) {
|
||||||
|
attrs {
|
||||||
|
this.key = selected.toString()
|
||||||
|
this.meta = vision.properties.root()
|
||||||
|
this.updates = vision.properties.changes
|
||||||
|
this.descriptor = vision.descriptor
|
||||||
|
this.scope = props.context
|
||||||
|
this.getPropertyState = { name ->
|
||||||
|
if (vision.properties.own?.get(name) != null) {
|
||||||
|
EditorPropertyState.Defined
|
||||||
|
} else if (vision.properties.root()[name] != null) {
|
||||||
|
// TODO differentiate
|
||||||
|
EditorPropertyState.Default()
|
||||||
|
} else {
|
||||||
|
EditorPropertyState.Undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->
|
||||||
|
p {
|
||||||
|
b { +"Styles: " }
|
||||||
|
+styles.joinToString(separator = ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flexColumn {
|
||||||
|
css {
|
||||||
|
padding = Padding(4.px)
|
||||||
|
minWidth = 400.px
|
||||||
|
height = 100.pct
|
||||||
|
overflowY = Overflow.auto
|
||||||
|
flex = Flex(1.0, 10.0, FlexBasis("300px"))
|
||||||
|
}
|
||||||
|
ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
|||||||
|
package space.kscience.visionforge.ring
|
||||||
|
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import space.kscience.dataforge.context.AbstractPlugin
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
|
import space.kscience.dataforge.context.PluginFactory
|
||||||
|
import space.kscience.dataforge.context.PluginTag
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.asName
|
||||||
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.VisionClient
|
||||||
|
import space.kscience.visionforge.react.render
|
||||||
|
import space.kscience.visionforge.solid.Solid
|
||||||
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
|
|
||||||
|
public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||||
|
public val three: ThreePlugin by require(ThreePlugin)
|
||||||
|
|
||||||
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
|
override fun rateVision(vision: Vision): Int =
|
||||||
|
if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING
|
||||||
|
|
||||||
|
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||||
|
space.kscience.visionforge.react.createRoot(element).render {
|
||||||
|
child(ThreeCanvasWithControls) {
|
||||||
|
attrs {
|
||||||
|
this.solids = three.solids
|
||||||
|
this.options = Canvas3DOptions.read(meta)
|
||||||
|
this.builderOfSolid = context.async { vision as Solid }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun content(target: String): Map<Name, Any> {
|
||||||
|
return when (target) {
|
||||||
|
ElementVisionRenderer.TYPE -> mapOf("three.withControls".asName() to this)
|
||||||
|
else -> super.content(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object : PluginFactory<ThreeWithControlsPlugin> {
|
||||||
|
override val tag: PluginTag = PluginTag("vision.threejs.withControls", PluginTag.DATAFORGE_GROUP)
|
||||||
|
|
||||||
|
override fun build(context: Context, meta: Meta): ThreeWithControlsPlugin = ThreeWithControlsPlugin()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package space.kscience.visionforge.ring
|
||||||
|
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.p
|
||||||
|
import ringui.Island
|
||||||
|
import ringui.SmartTabs
|
||||||
|
import ringui.Tab
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.getStyle
|
||||||
|
import space.kscience.visionforge.react.*
|
||||||
|
import space.kscience.visionforge.root
|
||||||
|
import space.kscience.visionforge.solid.SolidReference
|
||||||
|
import space.kscience.visionforge.styles
|
||||||
|
|
||||||
|
public fun RBuilder.ringPropertyEditor(
|
||||||
|
vision: Vision,
|
||||||
|
descriptor: MetaDescriptor? = vision.descriptor,
|
||||||
|
key: Any? = null,
|
||||||
|
) {
|
||||||
|
val styles = if (vision is SolidReference) {
|
||||||
|
(vision.styles + vision.prototype.styles).distinct()
|
||||||
|
} else {
|
||||||
|
vision.styles
|
||||||
|
}
|
||||||
|
|
||||||
|
flexColumn {
|
||||||
|
Island("Properties") {
|
||||||
|
child(PropertyEditor) {
|
||||||
|
attrs {
|
||||||
|
this.key = key?.toString()
|
||||||
|
this.meta = vision.properties.root()
|
||||||
|
this.updates = vision.properties.changes
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
|
||||||
|
this.getPropertyState = {name->
|
||||||
|
if(vision.properties.own?.get(name)!= null){
|
||||||
|
EditorPropertyState.Defined
|
||||||
|
} else if(vision.properties.root()[name] != null){
|
||||||
|
// TODO differentiate
|
||||||
|
EditorPropertyState.Default()
|
||||||
|
} else {
|
||||||
|
EditorPropertyState.Undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styles.isNotEmpty()) {
|
||||||
|
Island("Styles") {
|
||||||
|
if (styles.size == 1) {
|
||||||
|
val styleName = styles.first()
|
||||||
|
p {
|
||||||
|
+styleName
|
||||||
|
}
|
||||||
|
val style = vision.getStyle(styleName)
|
||||||
|
if (style != null) {
|
||||||
|
Tab(styleName, id = styleName) {
|
||||||
|
metaViewer(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SmartTabs {
|
||||||
|
styles.forEach { styleName ->
|
||||||
|
val style = vision.getStyle(styleName)
|
||||||
|
if (style != null) {
|
||||||
|
Tab(styleName, id = styleName) {
|
||||||
|
metaViewer(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public fun Element.ringPropertyEditor(
|
||||||
|
item: Vision,
|
||||||
|
descriptor: MetaDescriptor? = item.descriptor,
|
||||||
|
): Unit = createRoot(this).render {
|
||||||
|
ringPropertyEditor(item, descriptor = descriptor)
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
package space.kscience.visionforge.ring
|
||||||
|
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.css.*
|
||||||
|
import kotlinx.html.js.onClickFunction
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import org.w3c.files.Blob
|
||||||
|
import org.w3c.files.BlobPropertyBag
|
||||||
|
import react.FC
|
||||||
|
import react.Props
|
||||||
|
import react.RBuilder
|
||||||
|
import react.dom.attrs
|
||||||
|
import react.dom.button
|
||||||
|
import react.fc
|
||||||
|
import ringui.Island
|
||||||
|
import ringui.SmartTabs
|
||||||
|
import ringui.Tab
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.encodeToString
|
||||||
|
import space.kscience.visionforge.react.flexColumn
|
||||||
|
import space.kscience.visionforge.react.flexRow
|
||||||
|
import space.kscience.visionforge.react.propertyEditor
|
||||||
|
import space.kscience.visionforge.react.visionTree
|
||||||
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
|
import styled.css
|
||||||
|
|
||||||
|
internal fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
val fileSaver = kotlinext.js.require<dynamic>("file-saver")
|
||||||
|
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
|
||||||
|
fileSaver.saveAs(blob, fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun RBuilder.canvasControls(options: Canvas3DOptions, vision: Vision?): Unit {
|
||||||
|
child(CanvasControls) {
|
||||||
|
attrs {
|
||||||
|
this.options = options
|
||||||
|
this.vision = vision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal external interface CanvasControlsProps : Props {
|
||||||
|
public var options: Canvas3DOptions
|
||||||
|
public var vision: Vision?
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
internal val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
|
||||||
|
flexColumn {
|
||||||
|
flexRow {
|
||||||
|
css {
|
||||||
|
border = Border(1.px, BorderStyle.solid, Color.blue)
|
||||||
|
padding = Padding(4.px)
|
||||||
|
}
|
||||||
|
props.vision?.let { vision ->
|
||||||
|
button {
|
||||||
|
+"Export"
|
||||||
|
attrs {
|
||||||
|
onClickFunction = {
|
||||||
|
val json = vision.encodeToString()
|
||||||
|
saveData(it, "object.json", "text/json") {
|
||||||
|
json
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
propertyEditor(
|
||||||
|
scope = props.vision?.manager?.context ?: GlobalScope,
|
||||||
|
properties = props.options.meta,
|
||||||
|
descriptor = Canvas3DOptions.descriptor,
|
||||||
|
expanded = false
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public external interface ThreeControlsProps : Props {
|
||||||
|
public var canvasOptions: Canvas3DOptions
|
||||||
|
public var vision: Vision?
|
||||||
|
public var selected: Name?
|
||||||
|
public var onSelect: (Name?) -> Unit
|
||||||
|
public var additionalTabs: Map<String, RBuilder.() -> Unit>
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
public val ThreeControls: FC<ThreeControlsProps> = fc { props ->
|
||||||
|
SmartTabs("Tree") {
|
||||||
|
props.vision?.let {
|
||||||
|
Tab("Tree") {
|
||||||
|
Island("Vision tree") {
|
||||||
|
visionTree(it, props.selected, props.onSelect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tab("Settings") {
|
||||||
|
Island("Canvas configuration") {
|
||||||
|
canvasControls(props.canvasOptions, props.vision)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.additionalTabs.forEach { (name, handler) ->
|
||||||
|
Tab(name) {
|
||||||
|
handler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun RBuilder.ringThreeControls(
|
||||||
|
canvasOptions: Canvas3DOptions,
|
||||||
|
vision: Vision?,
|
||||||
|
selected: Name?,
|
||||||
|
onSelect: (Name?) -> Unit = {},
|
||||||
|
additionalTabs: Map<String, RBuilder.() -> Unit>? = null
|
||||||
|
): Unit = child(ThreeControls) {
|
||||||
|
attrs {
|
||||||
|
this.canvasOptions = canvasOptions
|
||||||
|
this.vision = vision
|
||||||
|
this.selected = selected
|
||||||
|
this.onSelect = onSelect
|
||||||
|
this.additionalTabs = additionalTabs ?: emptyMap()
|
||||||
|
}
|
||||||
|
}
|
3
ui/ring/webpack.config.d/01.ring.js
vendored
Normal file
3
ui/ring/webpack.config.d/01.ring.js
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
||||||
|
|
||||||
|
config.module.rules.push(...ringConfig.module.rules)
|
@ -4,8 +4,9 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
js()
|
|
||||||
jvm()
|
jvm()
|
||||||
|
js()
|
||||||
|
// wasm()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
@ -14,17 +15,23 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.visionforgeCore)
|
api(projects.visionforgeCore)
|
||||||
//need this to placate compose compiler in MPP applications
|
|
||||||
api(compose.runtime)
|
api(compose.runtime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsMain{
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
|
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:0.1.15")
|
||||||
api("app.softwork:bootstrap-compose-icons:0.1.15")
|
api("app.softwork:bootstrap-compose-icons:0.1.15")
|
||||||
|
|
||||||
api(compose.html.core)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import org.jetbrains.compose.web.css.Style
|
import org.jetbrains.compose.web.css.Style
|
||||||
@ -7,20 +7,22 @@ import org.jetbrains.compose.web.renderComposable
|
|||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.VisionClient
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An [ElementVisionRenderer] that could be used directly in Compose-html as well as a stand-alone renderer
|
* An [ElementVisionRenderer] that could be used directly in Compose-html as well as a stand-alone renderer
|
||||||
*/
|
*/
|
||||||
public interface ComposeHtmlVisionRenderer : ElementVisionRenderer {
|
public interface ComposeVisionRenderer: ElementVisionRenderer {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
public fun DOMScope<Element>.render(name: Name, vision: Vision, meta: Meta)
|
public fun DOMScope<Element>.render(client: VisionClient, name: Name, vision: Vision, meta: Meta)
|
||||||
|
|
||||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||||
renderComposable(element) {
|
renderComposable(element) {
|
||||||
Style(VisionForgeStyles)
|
Style(VisionForgeStyles)
|
||||||
render(name, vision, meta)
|
render(client, name, vision, meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import org.jetbrains.compose.web.css.AlignItems
|
import org.jetbrains.compose.web.css.AlignItems
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import org.jetbrains.compose.web.dom.*
|
import org.jetbrains.compose.web.dom.*
|
@ -1,7 +1,8 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import app.softwork.bootstrapcompose.CloseButton
|
import app.softwork.bootstrapcompose.CloseButton
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
@ -38,6 +39,7 @@ public sealed class EditorPropertyState {
|
|||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
public fun PropertyEditor(
|
public fun PropertyEditor(
|
||||||
|
scope: CoroutineScope,
|
||||||
rootMeta: MutableMeta,
|
rootMeta: MutableMeta,
|
||||||
getPropertyState: (Name) -> EditorPropertyState,
|
getPropertyState: (Name) -> EditorPropertyState,
|
||||||
updates: Flow<Name>,
|
updates: Flow<Name>,
|
||||||
@ -134,7 +136,7 @@ public fun PropertyEditor(
|
|||||||
Div({
|
Div({
|
||||||
classes(TreeStyles.treeItem)
|
classes(TreeStyles.treeItem)
|
||||||
}) {
|
}) {
|
||||||
PropertyEditor(rootMeta, getPropertyState, updates, name + token, rootDescriptor, expanded)
|
PropertyEditor(scope, rootMeta, getPropertyState, updates, name + token, rootDescriptor, expanded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,12 +145,13 @@ public fun PropertyEditor(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
public fun PropertyEditor(
|
public fun PropertyEditor(
|
||||||
|
scope: CoroutineScope,
|
||||||
properties: ObservableMutableMeta,
|
properties: ObservableMutableMeta,
|
||||||
descriptor: MetaDescriptor? = null,
|
descriptor: MetaDescriptor? = null,
|
||||||
expanded: Boolean? = null,
|
expanded: Boolean? = null,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
PropertyEditor(
|
PropertyEditor(
|
||||||
|
scope = scope,
|
||||||
rootMeta = properties,
|
rootMeta = properties,
|
||||||
getPropertyState = { name ->
|
getPropertyState = { name ->
|
||||||
if (properties[name] != null) {
|
if (properties[name] != null) {
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import app.softwork.bootstrapcompose.Card
|
import app.softwork.bootstrapcompose.Card
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
||||||
import org.jetbrains.compose.web.css.*
|
import org.jetbrains.compose.web.css.*
|
||||||
@ -67,4 +67,26 @@ public object TreeStyles : StyleSheet(VisionForgeStyles) {
|
|||||||
public val treeLabelSelected: String by style {
|
public val treeLabelSelected: String by style {
|
||||||
backgroundColor(Color.lightblue)
|
backgroundColor(Color.lightblue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public val propertyEditorButton: String by style {
|
||||||
|
width(24.px)
|
||||||
|
alignSelf(AlignSelf.Stretch)
|
||||||
|
marginAll(1.px, 5.px)
|
||||||
|
backgroundColor(Color.white)
|
||||||
|
border {
|
||||||
|
style(LineStyle.Solid)
|
||||||
|
}
|
||||||
|
borderRadius(2.px)
|
||||||
|
textAlign("center")
|
||||||
|
textDecoration("none")
|
||||||
|
cursor("pointer")
|
||||||
|
(self + disabled) {
|
||||||
|
cursor("auto")
|
||||||
|
border {
|
||||||
|
style(LineStyle.Dashed)
|
||||||
|
}
|
||||||
|
color(Color.lightgray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import org.jetbrains.compose.web.css.StyleSheet
|
||||||
|
|
||||||
|
public object VisionForgeStyles: StyleSheet() {
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import org.jetbrains.compose.web.css.Color
|
import org.jetbrains.compose.web.css.Color
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import org.jetbrains.compose.web.dom.H5
|
import org.jetbrains.compose.web.dom.H5
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
@ -48,7 +48,7 @@ public fun Vision(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(vision, name, renderer, meta) {
|
DisposableEffect(vision, name, renderer, meta) {
|
||||||
renderer.render(scopeElement, name, vision, meta)
|
renderer.render(scopeElement, client, name, vision, meta)
|
||||||
onDispose {
|
onDispose {
|
||||||
scopeElement.clear()
|
scopeElement.clear()
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import org.jetbrains.compose.web.css.*
|
import org.jetbrains.compose.web.css.*
|
||||||
import org.jetbrains.compose.web.css.keywords.CSSAutoKeyword
|
import org.jetbrains.compose.web.css.keywords.CSSAutoKeyword
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import org.jetbrains.compose.web.css.DisplayStyle
|
import org.jetbrains.compose.web.css.DisplayStyle
|
@ -1,6 +1,6 @@
|
|||||||
@file:Suppress("UNUSED_PARAMETER")
|
@file:Suppress("UNUSED_PARAMETER")
|
||||||
|
|
||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import kotlinx.uuid.UUID
|
import kotlinx.uuid.UUID
|
@ -1,28 +0,0 @@
|
|||||||
package space.kscience.visionforge.html
|
|
||||||
|
|
||||||
import org.jetbrains.compose.web.css.*
|
|
||||||
|
|
||||||
public object VisionForgeStyles: StyleSheet() {
|
|
||||||
|
|
||||||
public val propertyEditorButton: String by style {
|
|
||||||
width(24.px)
|
|
||||||
alignSelf(AlignSelf.Stretch)
|
|
||||||
marginAll(1.px, 5.px)
|
|
||||||
backgroundColor(Color.white)
|
|
||||||
border {
|
|
||||||
style(LineStyle.Solid)
|
|
||||||
}
|
|
||||||
borderRadius(2.px)
|
|
||||||
textAlign("center")
|
|
||||||
textDecoration("none")
|
|
||||||
cursor("pointer")
|
|
||||||
(self + disabled) {
|
|
||||||
cursor("auto")
|
|
||||||
border {
|
|
||||||
style(LineStyle.Dashed)
|
|
||||||
}
|
|
||||||
color(Color.lightgray)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
# Module visionforge-compose-multiplatform
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
## Artifact:
|
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-compose-multiplatform:0.4.0-dev-3`.
|
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
|
||||||
```kotlin
|
|
||||||
repositories {
|
|
||||||
maven("https://repo.kotlin.link")
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation("space.kscience:visionforge-compose-multiplatform:0.4.0-dev-3")
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,35 +0,0 @@
|
|||||||
import space.kscience.gradle.Maturity
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("space.kscience.gradle.mpp")
|
|
||||||
alias(spclibs.plugins.compose)
|
|
||||||
}
|
|
||||||
|
|
||||||
kscience {
|
|
||||||
jvm()
|
|
||||||
// wasm()
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
// android()
|
|
||||||
sourceSets {
|
|
||||||
commonMain {
|
|
||||||
dependencies {
|
|
||||||
api(projects.visionforgeCore)
|
|
||||||
api(compose.foundation)
|
|
||||||
api(compose.runtime)
|
|
||||||
api(compose.material)
|
|
||||||
api(compose.materialIconsExtended)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jvmMain {
|
|
||||||
dependencies {
|
|
||||||
implementation("com.eygraber:compose-color-picker:0.0.17")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readme {
|
|
||||||
maturity = Maturity.EXPERIMENTAL
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
package space.kscience.visionforge.compose
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.key
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
|
||||||
import space.kscience.dataforge.context.*
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.meta.int
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.dataforge.names.NameToken
|
|
||||||
import space.kscience.dataforge.names.asName
|
|
||||||
import space.kscience.visionforge.*
|
|
||||||
import space.kscience.visionforge.html.VisionOutput
|
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Kotlin-browser plugin that renders visions based on provided renderers and governs communication with the server.
|
|
||||||
*/
|
|
||||||
public class ComposeVisionClient : AbstractPlugin(), VisionClient {
|
|
||||||
override val tag: PluginTag get() = Companion.tag
|
|
||||||
override val visionManager: VisionManager by require(VisionManager)
|
|
||||||
|
|
||||||
|
|
||||||
private val renderers by lazy { context.gather<ComposeVisionRenderer>(ComposeVisionRenderer.TYPE).values }
|
|
||||||
|
|
||||||
private fun findRendererFor(vision: Vision): ComposeVisionRenderer? = renderers.mapNotNull {
|
|
||||||
val rating = it.rateVision(vision)
|
|
||||||
if (rating > 0) {
|
|
||||||
rating to it
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}.maxByOrNull { it.first }?.second
|
|
||||||
|
|
||||||
|
|
||||||
private val mutex = Mutex()
|
|
||||||
|
|
||||||
|
|
||||||
private val rootChangeCollector = VisionChangeBuilder()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Communicate vision property changed from rendering engine to model
|
|
||||||
*/
|
|
||||||
override fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
|
|
||||||
context.launch {
|
|
||||||
mutex.withLock {
|
|
||||||
rootChangeCollector.propertyChanged(visionName, propertyName, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val eventCollector = MutableSharedFlow<Pair<Name, VisionEvent>>(meta["feedback.eventCache"].int ?: 100)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a custom feedback event
|
|
||||||
*/
|
|
||||||
override suspend fun sendEvent(targetName: Name, event: VisionEvent) {
|
|
||||||
eventCollector.emit(targetName to event)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun renderVision(name: Name, vision: Vision, outputMeta: Meta) {
|
|
||||||
val renderer: ComposeVisionRenderer = remember(vision) {
|
|
||||||
findRendererFor(vision) ?: error("Could not find renderer for ${vision::class}")
|
|
||||||
}
|
|
||||||
|
|
||||||
key(vision) {
|
|
||||||
vision.setAsRoot(visionManager)
|
|
||||||
}
|
|
||||||
//subscribe to a backwards events propagation for control visions
|
|
||||||
if (vision is ControlVision) {
|
|
||||||
LaunchedEffect(vision) {
|
|
||||||
vision.controlEventFlow.collect {
|
|
||||||
sendEvent(name, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.render(name, vision, outputMeta)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// override fun content(target: String): Map<Name, Any> = if (target == ComposeVisionRenderer.TYPE) {
|
|
||||||
// listOf(
|
|
||||||
// htmlVisionRenderer,
|
|
||||||
// inputVisionRenderer,
|
|
||||||
// checkboxVisionRenderer,
|
|
||||||
// numberVisionRenderer,
|
|
||||||
// textVisionRenderer,
|
|
||||||
// rangeVisionRenderer,
|
|
||||||
// formVisionRenderer,
|
|
||||||
// buttonVisionRenderer
|
|
||||||
// ).associateBy { it.toString().asName() }
|
|
||||||
// } else super<AbstractPlugin>.content(target)
|
|
||||||
|
|
||||||
public companion object : PluginFactory<ComposeVisionClient> {
|
|
||||||
override fun build(context: Context, meta: Meta): ComposeVisionClient = ComposeVisionClient()
|
|
||||||
|
|
||||||
override val tag: PluginTag = PluginTag(name = "vision.client.compose", group = PluginTag.DATAFORGE_GROUP)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render an Element vision via injected vision renderer inside compose-html
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
public fun Vision(
|
|
||||||
context: Context,
|
|
||||||
vision: Vision,
|
|
||||||
name: Name? = null,
|
|
||||||
meta: Meta = Meta.EMPTY,
|
|
||||||
) {
|
|
||||||
val actualName = name ?: NameToken(VisionTagConsumer.DEFAULT_VISION_NAME, vision.hashCode().toUInt().toString()).asName()
|
|
||||||
context.request(ComposeVisionClient).renderVision(actualName, vision, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun Vision(
|
|
||||||
context: Context,
|
|
||||||
name: Name? = null,
|
|
||||||
meta: Meta = Meta.EMPTY,
|
|
||||||
buildOutput: VisionOutput.() -> Vision,
|
|
||||||
) {
|
|
||||||
val actualName = name ?: NameToken(VisionTagConsumer.DEFAULT_VISION_NAME, buildOutput.hashCode().toUInt().toString()).asName()
|
|
||||||
val output = VisionOutput(context, actualName)
|
|
||||||
val vision = output.buildOutput()
|
|
||||||
context.request(ComposeVisionClient).renderVision(actualName, vision, meta)
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package space.kscience.visionforge.compose
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.misc.DfType
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.visionforge.Vision
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.cast
|
|
||||||
|
|
||||||
@DfType(ComposeVisionRenderer.TYPE)
|
|
||||||
public interface ComposeVisionRenderer {
|
|
||||||
public fun rateVision(vision: Vision): Int
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun render(name: Name, vision: Vision, meta: Meta)
|
|
||||||
|
|
||||||
public companion object {
|
|
||||||
public const val TYPE: String = "composeVisionRenderer"
|
|
||||||
public const val ZERO_RATING: Int = 0
|
|
||||||
public const val DEFAULT_RATING: Int = 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SingleTypeComposeRenderer<T : Vision>(
|
|
||||||
public val kClass: KClass<T>,
|
|
||||||
private val acceptRating: Int = ComposeVisionRenderer.DEFAULT_RATING,
|
|
||||||
private val renderFunction: @Composable (name: Name, vision: T, meta: Meta) -> Unit,
|
|
||||||
) : ComposeVisionRenderer {
|
|
||||||
|
|
||||||
override fun rateVision(vision: Vision): Int =
|
|
||||||
if (vision::class == kClass) acceptRating else ComposeVisionRenderer.ZERO_RATING
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun render(
|
|
||||||
name: Name,
|
|
||||||
vision: Vision,
|
|
||||||
meta: Meta,
|
|
||||||
) {
|
|
||||||
renderFunction(name, kClass.cast(vision), meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public inline fun <reified T : Vision> ComposeVisionRenderer(
|
|
||||||
acceptRating: Int = ComposeVisionRenderer.DEFAULT_RATING,
|
|
||||||
noinline renderFunction: @Composable (name: Name, vision: T, meta: Meta) -> Unit,
|
|
||||||
): ComposeVisionRenderer = SingleTypeComposeRenderer(T::class, acceptRating, renderFunction)
|
|
@ -1,69 +0,0 @@
|
|||||||
package space.kscience.visionforge.compose
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.material.Icon
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.material.TextButton
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.ExpandLess
|
|
||||||
import androidx.compose.material.icons.filled.ExpandMore
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
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.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
|
|
||||||
|
|
||||||
|
|
||||||
@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() ?: ""
|
|
||||||
|
|
||||||
Row(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
if (actualMeta?.isLeaf == false) {
|
|
||||||
TextButton({ expanded = !expanded }) {
|
|
||||||
if (expanded) {
|
|
||||||
Icon(Icons.Filled.ExpandLess, "collapse")
|
|
||||||
} else {
|
|
||||||
Icon(Icons.Filled.ExpandMore, "expand")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text(token, color = if (item == null) Color.Gray else Color.Unspecified)
|
|
||||||
Spacer(Modifier.weight(1f))
|
|
||||||
Text(actualValue.toString())
|
|
||||||
}
|
|
||||||
if (expanded) {
|
|
||||||
Column {
|
|
||||||
val keys = buildSet {
|
|
||||||
descriptorItem?.nodes?.keys?.forEach {
|
|
||||||
add(NameToken(it))
|
|
||||||
}
|
|
||||||
actualMeta!!.items.keys.let { addAll(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.filter { !it.body.startsWith("@") }.forEach { token ->
|
|
||||||
MetaViewerItem(root, name + token, rootDescriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun MetaViewer(meta: Meta, descriptor: MetaDescriptor? = null) {
|
|
||||||
MetaViewerItem(meta, Name.EMPTY, descriptor)
|
|
||||||
}
|
|
@ -1,174 +0,0 @@
|
|||||||
package space.kscience.visionforge.compose
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.material.Icon
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.material.TextButton
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Clear
|
|
||||||
import androidx.compose.material.icons.filled.ExpandLess
|
|
||||||
import androidx.compose.material.icons.filled.ExpandMore
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
|
||||||
import space.kscience.dataforge.meta.ObservableMutableMeta
|
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.ValueRestriction
|
|
||||||
import space.kscience.dataforge.meta.descriptors.get
|
|
||||||
import space.kscience.dataforge.meta.remove
|
|
||||||
import space.kscience.dataforge.names.*
|
|
||||||
import space.kscience.visionforge.hidden
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The display state of a property
|
|
||||||
*/
|
|
||||||
public sealed class EditorPropertyState {
|
|
||||||
public data object Defined : EditorPropertyState()
|
|
||||||
public data class Default(public val source: String = "unknown") : EditorPropertyState()
|
|
||||||
public data object Undefined : EditorPropertyState()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param rootMeta Root config object - always non-null
|
|
||||||
* @param rootDescriptor Full path to the displayed node in [rootMeta]. Could be empty
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
public fun PropertyEditor(
|
|
||||||
rootMeta: MutableMeta,
|
|
||||||
getPropertyState: (Name) -> EditorPropertyState,
|
|
||||||
updates: Flow<Name>,
|
|
||||||
name: Name,
|
|
||||||
rootDescriptor: MetaDescriptor?,
|
|
||||||
initialExpanded: Boolean? = null,
|
|
||||||
) {
|
|
||||||
var expanded: Boolean by remember { mutableStateOf(initialExpanded ?: true) }
|
|
||||||
val descriptor: MetaDescriptor? by derivedStateOf { rootDescriptor?.get(name) }
|
|
||||||
var displayedValue by remember { mutableStateOf(rootMeta.getValue(name)) }
|
|
||||||
var editorPropertyState: EditorPropertyState by remember { mutableStateOf(getPropertyState(name)) }
|
|
||||||
|
|
||||||
fun buildKeys() = buildSet {
|
|
||||||
descriptor?.nodes?.filterNot {
|
|
||||||
it.key.startsWith("@") || it.value.hidden
|
|
||||||
}?.forEach {
|
|
||||||
add(NameToken(it.key))
|
|
||||||
}
|
|
||||||
rootMeta[name]?.items?.keys?.filterNot { it.body.startsWith("@") }?.let { addAll(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var keys by remember { mutableStateOf(buildKeys()) }
|
|
||||||
|
|
||||||
val token = name.lastOrNull()?.toString() ?: "Properties"
|
|
||||||
|
|
||||||
fun update() {
|
|
||||||
displayedValue = rootMeta.getValue(name)
|
|
||||||
editorPropertyState = getPropertyState(name)
|
|
||||||
keys = buildKeys()
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(rootMeta) {
|
|
||||||
updates.collect { updatedName ->
|
|
||||||
if (name.startsWith(updatedName)) {
|
|
||||||
update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 20.dp)) {
|
|
||||||
Row(modifier = Modifier.fillMaxWidth().padding(start = 20.dp)) {
|
|
||||||
//if node has children
|
|
||||||
if (keys.isNotEmpty()) {
|
|
||||||
TextButton(
|
|
||||||
{ expanded = !expanded },
|
|
||||||
modifier = Modifier.align(Alignment.CenterVertically).width(40.dp)
|
|
||||||
) {
|
|
||||||
if (expanded) {
|
|
||||||
Icon(Icons.Filled.ExpandLess, "collapse")
|
|
||||||
} else {
|
|
||||||
Icon(Icons.Filled.ExpandMore, "expand")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
token,
|
|
||||||
color = when (editorPropertyState) {
|
|
||||||
is EditorPropertyState.Default, EditorPropertyState.Undefined -> Color.Gray
|
|
||||||
else -> Color.Unspecified
|
|
||||||
},
|
|
||||||
modifier = Modifier.align(Alignment.CenterVertically)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
|
|
||||||
if (!name.isEmpty() && descriptor?.valueRestriction != ValueRestriction.ABSENT) {
|
|
||||||
Box(modifier = Modifier.padding(1.dp, 5.dp).width(160.dp)) {
|
|
||||||
ValueChooser(descriptor, editorPropertyState, displayedValue) {
|
|
||||||
rootMeta.setValue(name, it)
|
|
||||||
update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
TextButton(
|
|
||||||
onClick = {
|
|
||||||
rootMeta.remove(name)
|
|
||||||
update()
|
|
||||||
},
|
|
||||||
enabled = editorPropertyState == EditorPropertyState.Defined,
|
|
||||||
modifier = Modifier.align(Alignment.CenterVertically).width(50.dp)
|
|
||||||
) {
|
|
||||||
if (editorPropertyState == EditorPropertyState.Defined) {
|
|
||||||
Icon(Icons.Filled.Clear, "Reset")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (expanded) {
|
|
||||||
Column(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
keys.forEach { token ->
|
|
||||||
PropertyEditor(rootMeta, getPropertyState, updates, name + token, rootDescriptor, expanded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun PropertyEditor(
|
|
||||||
properties: ObservableMutableMeta,
|
|
||||||
descriptor: MetaDescriptor? = null,
|
|
||||||
expanded: Boolean? = null,
|
|
||||||
) {
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
PropertyEditor(
|
|
||||||
rootMeta = properties,
|
|
||||||
getPropertyState = { name ->
|
|
||||||
if (properties[name] != null) {
|
|
||||||
EditorPropertyState.Defined
|
|
||||||
} else if (descriptor?.get(name)?.defaultValue != null) {
|
|
||||||
EditorPropertyState.Default("descriptor")
|
|
||||||
} else {
|
|
||||||
EditorPropertyState.Undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updates = callbackFlow {
|
|
||||||
properties.onChange(scope) { name ->
|
|
||||||
scope.launch {
|
|
||||||
send(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
awaitClose { properties.removeListener(scope) }
|
|
||||||
},
|
|
||||||
name = Name.EMPTY,
|
|
||||||
rootDescriptor = descriptor,
|
|
||||||
initialExpanded = expanded,
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,270 +0,0 @@
|
|||||||
@file:Suppress("UNUSED_PARAMETER")
|
|
||||||
|
|
||||||
package space.kscience.visionforge.compose
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
|
||||||
import androidx.compose.material.*
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.CheckBox
|
|
||||||
import androidx.compose.material.icons.filled.CheckBoxOutlineBlank
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.isSpecified
|
|
||||||
import androidx.compose.ui.graphics.toArgb
|
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
|
||||||
import com.eygraber.compose.colorpicker.ColorPicker
|
|
||||||
import space.kscience.dataforge.meta.*
|
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|
||||||
import space.kscience.dataforge.meta.descriptors.allowedValues
|
|
||||||
import space.kscience.visionforge.widgetType
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun StringValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
var stringValue by remember(value, descriptor) { mutableStateOf(value?.string ?: "") }
|
|
||||||
TextField(
|
|
||||||
value = stringValue,
|
|
||||||
onValueChange = {
|
|
||||||
stringValue = it
|
|
||||||
onValueChange(it.asValue())
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun BooleanValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
var innerValue by remember(value, descriptor) {
|
|
||||||
mutableStateOf(
|
|
||||||
value?.boolean ?: descriptor?.defaultValue?.boolean ?: false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
innerValue = !innerValue
|
|
||||||
onValueChange(innerValue.asValue())
|
|
||||||
},
|
|
||||||
colors = if (innerValue) ButtonDefaults.buttonColors(Color.Green) else ButtonDefaults.buttonColors(Color.Gray)
|
|
||||||
) {
|
|
||||||
if (innerValue) {
|
|
||||||
Text("On")
|
|
||||||
} else {
|
|
||||||
Text("Off")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun NumberValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
var stringValue by remember(value, descriptor) { mutableStateOf(value?.string ?: descriptor?.defaultValue?.string) }
|
|
||||||
|
|
||||||
TextField(
|
|
||||||
value = stringValue ?: "",
|
|
||||||
onValueChange = { newValue ->
|
|
||||||
stringValue = newValue
|
|
||||||
newValue.toDoubleOrNull()?.let { onValueChange(it.asValue()) }
|
|
||||||
},
|
|
||||||
isError = stringValue?.toDoubleOrNull() != null,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
|
||||||
public fun ComboValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
var selected by remember(value, descriptor) { mutableStateOf(value?.string ?: "") }
|
|
||||||
|
|
||||||
ExposedDropdownMenuBox(
|
|
||||||
expanded = expanded,
|
|
||||||
onExpandedChange = {
|
|
||||||
expanded = !expanded
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
TextField(
|
|
||||||
value = selected,
|
|
||||||
onValueChange = {},
|
|
||||||
readOnly = true,
|
|
||||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
|
||||||
)
|
|
||||||
|
|
||||||
ExposedDropdownMenu(
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false }
|
|
||||||
) {
|
|
||||||
descriptor?.allowedValues?.forEach { item: Value ->
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
selected = item.string
|
|
||||||
expanded = false
|
|
||||||
onValueChange(selected.asValue())
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Text(item.string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun ColorValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
//var innerValue by remember { mutableStateOf(value ?: descriptor?.defaultValue) }
|
|
||||||
|
|
||||||
Box(Modifier.fillMaxWidth()) {
|
|
||||||
ColorPicker(Modifier.fillMaxWidth()) {
|
|
||||||
if (it.isSpecified) {
|
|
||||||
onValueChange(it.toArgb().asValue())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
|
||||||
public fun MultiSelectChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
var selected: Set<Value> by remember(value) {
|
|
||||||
mutableStateOf(value?.list?.toSet() ?: emptySet<Value>())
|
|
||||||
}
|
|
||||||
|
|
||||||
ExposedDropdownMenuBox(
|
|
||||||
expanded = expanded,
|
|
||||||
onExpandedChange = {
|
|
||||||
expanded = !expanded
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
TextField(
|
|
||||||
value = selected.joinToString(prefix = "[", postfix = "]"),
|
|
||||||
onValueChange = {},
|
|
||||||
readOnly = true,
|
|
||||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
|
||||||
)
|
|
||||||
|
|
||||||
ExposedDropdownMenu(
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false }
|
|
||||||
) {
|
|
||||||
descriptor?.allowedValues?.forEach { item: Value ->
|
|
||||||
val currentlySelected = item in selected
|
|
||||||
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
selected = if (currentlySelected) {
|
|
||||||
selected - item
|
|
||||||
} else {
|
|
||||||
selected + item
|
|
||||||
}
|
|
||||||
onValueChange(selected.asValue())
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (currentlySelected) {
|
|
||||||
Icon(Icons.Default.CheckBox, "checked")
|
|
||||||
} else {
|
|
||||||
Icon(Icons.Default.CheckBoxOutlineBlank, "checked")
|
|
||||||
}
|
|
||||||
Text(item.string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun RangeValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
var innerValue by remember(value, descriptor) { mutableStateOf(value?.number ?: descriptor?.defaultValue?.number) }
|
|
||||||
val min by derivedStateOf {
|
|
||||||
descriptor?.attributes?.get("min").float ?: 0f
|
|
||||||
}
|
|
||||||
|
|
||||||
val max by derivedStateOf {
|
|
||||||
descriptor?.attributes?.get("max").float ?: 0f
|
|
||||||
}
|
|
||||||
|
|
||||||
val step by derivedStateOf {
|
|
||||||
descriptor?.attributes?.get("step").float ?: 0.1f
|
|
||||||
}
|
|
||||||
|
|
||||||
Slider(
|
|
||||||
value = innerValue?.toFloat() ?: 0f,
|
|
||||||
onValueChange = {
|
|
||||||
innerValue = it
|
|
||||||
onValueChange(it.asValue())
|
|
||||||
},
|
|
||||||
valueRange = min..max,
|
|
||||||
steps = ((max - min) / step).roundToInt(),
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun ValueChooser(
|
|
||||||
descriptor: MetaDescriptor?,
|
|
||||||
state: EditorPropertyState,
|
|
||||||
value: Value?,
|
|
||||||
onValueChange: (Value?) -> Unit,
|
|
||||||
) {
|
|
||||||
val rawInput by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val type = descriptor?.valueTypes?.firstOrNull()
|
|
||||||
|
|
||||||
when {
|
|
||||||
rawInput -> StringValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
descriptor?.widgetType == "color" -> ColorValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
descriptor?.widgetType == "multiSelect" -> MultiSelectChooser(descriptor, state, value, onValueChange)
|
|
||||||
descriptor?.widgetType == "range" -> RangeValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
type == ValueType.BOOLEAN -> BooleanValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
type == ValueType.NUMBER -> NumberValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
descriptor?.allowedValues?.isNotEmpty() ?: false -> ComboValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
//TODO handle lists
|
|
||||||
else -> StringValueChooser(descriptor, state, value, onValueChange)
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-core:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-core:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-core:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-core:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1,16 +1,3 @@
|
|||||||
public abstract class space/kscience/visionforge/AbstractControlVision : space/kscience/visionforge/AbstractVision, space/kscience/visionforge/ControlVision {
|
|
||||||
public static final field Companion Lspace/kscience/visionforge/AbstractControlVision$Companion;
|
|
||||||
public fun <init> ()V
|
|
||||||
public synthetic fun <init> (ILspace/kscience/dataforge/meta/MutableMeta;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
|
||||||
public fun dispatchControlEvent (Lspace/kscience/visionforge/VisionControlEvent;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
|
||||||
public fun getControlEventFlow ()Lkotlinx/coroutines/flow/SharedFlow;
|
|
||||||
public static final synthetic fun write$Self (Lspace/kscience/visionforge/AbstractControlVision;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/AbstractControlVision$Companion {
|
|
||||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class space/kscience/visionforge/AbstractVision : space/kscience/visionforge/Vision {
|
public abstract class space/kscience/visionforge/AbstractVision : space/kscience/visionforge/Vision {
|
||||||
public static final field Companion Lspace/kscience/visionforge/AbstractVision$Companion;
|
public static final field Companion Lspace/kscience/visionforge/AbstractVision$Companion;
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
@ -47,20 +34,29 @@ public final class space/kscience/visionforge/AbstractVisionGroup$Companion {
|
|||||||
public static synthetic fun updateProperties$default (Lspace/kscience/visionforge/AbstractVisionGroup$Companion;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)V
|
public static synthetic fun updateProperties$default (Lspace/kscience/visionforge/AbstractVisionGroup$Companion;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
public class space/kscience/visionforge/AbstractVisionProperties : space/kscience/visionforge/MutableVisionProperties {
|
public abstract class space/kscience/visionforge/AbstractVisionProperties : space/kscience/visionforge/MutableVisionProperties {
|
||||||
public fun <init> (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/MutableMeta;)V
|
public fun <init> (Lspace/kscience/visionforge/Vision;)V
|
||||||
public fun flowChanges ()Lkotlinx/coroutines/flow/Flow;
|
public synthetic fun getChanges ()Lkotlinx/coroutines/flow/Flow;
|
||||||
|
public fun getChanges ()Lkotlinx/coroutines/flow/SharedFlow;
|
||||||
protected final fun getChangesInternal ()Lkotlinx/coroutines/flow/MutableSharedFlow;
|
protected final fun getChangesInternal ()Lkotlinx/coroutines/flow/MutableSharedFlow;
|
||||||
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
||||||
public synthetic fun getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
protected final fun getOrCreateProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
public final fun getOwn ()Lspace/kscience/dataforge/meta/MutableMeta;
|
public fun getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
||||||
|
protected abstract fun getProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
public fun getValue (Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;)Lspace/kscience/dataforge/meta/Value;
|
public fun getValue (Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;)Lspace/kscience/dataforge/meta/Value;
|
||||||
public final fun getVision ()Lspace/kscience/visionforge/Vision;
|
public final fun getVision ()Lspace/kscience/visionforge/Vision;
|
||||||
public fun invalidate (Lspace/kscience/dataforge/names/Name;)V
|
public fun invalidate (Lspace/kscience/dataforge/names/Name;)V
|
||||||
public fun set (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Z)V
|
public fun set (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Z)V
|
||||||
|
protected abstract fun setProperties (Lspace/kscience/dataforge/meta/MutableMeta;)V
|
||||||
public fun setValue (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Value;Z)V
|
public fun setValue (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Value;Z)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract interface class space/kscience/visionforge/ClickControl : space/kscience/visionforge/ControlVision {
|
||||||
|
public fun click (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public static synthetic fun click$default (Lspace/kscience/visionforge/ClickControl;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
|
||||||
|
public static synthetic fun click$suspendImpl (Lspace/kscience/visionforge/ClickControl;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/Colors {
|
public final class space/kscience/visionforge/Colors {
|
||||||
public static final field BLUE_KEY Ljava/lang/String;
|
public static final field BLUE_KEY Ljava/lang/String;
|
||||||
public static final field GREEN_KEY Ljava/lang/String;
|
public static final field GREEN_KEY Ljava/lang/String;
|
||||||
@ -227,21 +223,13 @@ public abstract interface class space/kscience/visionforge/ControlVision : space
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/ControlVisionKt {
|
public final class space/kscience/visionforge/ControlVisionKt {
|
||||||
|
public static final fun VisionClickEvent (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/visionforge/VisionClickEvent;
|
||||||
|
public static synthetic fun VisionClickEvent$default (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/visionforge/VisionClickEvent;
|
||||||
public static final fun VisionInputEvent (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/visionforge/VisionInputEvent;
|
public static final fun VisionInputEvent (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/visionforge/VisionInputEvent;
|
||||||
public static synthetic fun VisionInputEvent$default (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/visionforge/VisionInputEvent;
|
public static synthetic fun VisionInputEvent$default (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/visionforge/VisionInputEvent;
|
||||||
public static final fun VisionSubmitEvent (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/visionforge/VisionSubmitEvent;
|
|
||||||
public static synthetic fun VisionSubmitEvent$default (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/visionforge/VisionSubmitEvent;
|
|
||||||
public static final fun VisionValueChangeEvent (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/visionforge/VisionValueChangeEvent;
|
public static final fun VisionValueChangeEvent (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/visionforge/VisionValueChangeEvent;
|
||||||
public static synthetic fun VisionValueChangeEvent$default (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/visionforge/VisionValueChangeEvent;
|
public static synthetic fun VisionValueChangeEvent$default (Lspace/kscience/dataforge/meta/Value;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/visionforge/VisionValueChangeEvent;
|
||||||
public static final fun asyncControlEvent (Lspace/kscience/visionforge/ControlVision;Lspace/kscience/visionforge/VisionControlEvent;Lkotlinx/coroutines/CoroutineScope;)V
|
public static final fun onClick (Lspace/kscience/visionforge/ClickControl;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
||||||
public static synthetic fun asyncControlEvent$default (Lspace/kscience/visionforge/ControlVision;Lspace/kscience/visionforge/VisionControlEvent;Lkotlinx/coroutines/CoroutineScope;ILjava/lang/Object;)V
|
|
||||||
public static final fun onSubmit (Lspace/kscience/visionforge/DataControl;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract interface class space/kscience/visionforge/DataControl : space/kscience/visionforge/ControlVision {
|
|
||||||
public fun submit (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
|
||||||
public static synthetic fun submit$default (Lspace/kscience/visionforge/DataControl;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
|
|
||||||
public static synthetic fun submit$suspendImpl (Lspace/kscience/visionforge/DataControl;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/FlowPropertyKt {
|
public final class space/kscience/visionforge/FlowPropertyKt {
|
||||||
@ -332,9 +320,9 @@ public final class space/kscience/visionforge/StyleReference {
|
|||||||
|
|
||||||
public final class space/kscience/visionforge/StyleReferenceKt {
|
public final class space/kscience/visionforge/StyleReferenceKt {
|
||||||
public static final fun style (Lspace/kscience/visionforge/Vision;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty;
|
public static final fun style (Lspace/kscience/visionforge/Vision;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty;
|
||||||
public static final fun style (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/SchemeSpec;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty;
|
public static final fun style (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Specification;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty;
|
||||||
public static synthetic fun style$default (Lspace/kscience/visionforge/Vision;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
|
public static synthetic fun style$default (Lspace/kscience/visionforge/Vision;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
|
||||||
public static synthetic fun style$default (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/SchemeSpec;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
|
public static synthetic fun style$default (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Specification;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
|
||||||
public static final fun useStyle (Lspace/kscience/visionforge/Vision;Lspace/kscience/visionforge/StyleReference;Z)V
|
public static final fun useStyle (Lspace/kscience/visionforge/Vision;Lspace/kscience/visionforge/StyleReference;Z)V
|
||||||
public static synthetic fun useStyle$default (Lspace/kscience/visionforge/Vision;Lspace/kscience/visionforge/StyleReference;ZILjava/lang/Object;)V
|
public static synthetic fun useStyle$default (Lspace/kscience/visionforge/Vision;Lspace/kscience/visionforge/StyleReference;ZILjava/lang/Object;)V
|
||||||
}
|
}
|
||||||
@ -376,9 +364,7 @@ public final class space/kscience/visionforge/StyleSheetKt {
|
|||||||
|
|
||||||
public final class space/kscience/visionforge/UsePropertyKt {
|
public final class space/kscience/visionforge/UsePropertyKt {
|
||||||
public static final fun onPropertyChange (Lspace/kscience/visionforge/Vision;Lkotlin/reflect/KProperty1;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/Job;
|
public static final fun onPropertyChange (Lspace/kscience/visionforge/Vision;Lkotlin/reflect/KProperty1;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/Job;
|
||||||
public static final fun onPropertyChange (Lspace/kscience/visionforge/Vision;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
|
||||||
public static synthetic fun onPropertyChange$default (Lspace/kscience/visionforge/Vision;Lkotlin/reflect/KProperty1;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
|
public static synthetic fun onPropertyChange$default (Lspace/kscience/visionforge/Vision;Lkotlin/reflect/KProperty1;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
|
||||||
public static synthetic fun onPropertyChange$default (Lspace/kscience/visionforge/Vision;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
|
|
||||||
public static final fun useProperty (Lspace/kscience/visionforge/Vision;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job;
|
public static final fun useProperty (Lspace/kscience/visionforge/Vision;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job;
|
||||||
public static final fun useProperty (Lspace/kscience/visionforge/Vision;Lkotlin/reflect/KProperty1;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
public static final fun useProperty (Lspace/kscience/visionforge/Vision;Lkotlin/reflect/KProperty1;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
||||||
public static final fun useProperty (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job;
|
public static final fun useProperty (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job;
|
||||||
@ -476,6 +462,30 @@ public final class space/kscience/visionforge/VisionChildren$Companion {
|
|||||||
public final fun empty (Lspace/kscience/visionforge/Vision;)Lspace/kscience/visionforge/VisionChildren;
|
public final fun empty (Lspace/kscience/visionforge/Vision;)Lspace/kscience/visionforge/VisionChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/VisionClickEvent : space/kscience/visionforge/VisionControlEvent {
|
||||||
|
public static final field Companion Lspace/kscience/visionforge/VisionClickEvent$Companion;
|
||||||
|
public fun <init> (Lspace/kscience/dataforge/meta/Meta;)V
|
||||||
|
public fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
|
||||||
|
public final fun getName ()Lspace/kscience/dataforge/names/Name;
|
||||||
|
public final fun getPayload ()Lspace/kscience/dataforge/meta/Meta;
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/VisionClickEvent$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||||
|
public static final field INSTANCE Lspace/kscience/visionforge/VisionClickEvent$$serializer;
|
||||||
|
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||||
|
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||||
|
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/visionforge/VisionClickEvent;
|
||||||
|
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||||
|
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||||
|
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/visionforge/VisionClickEvent;)V
|
||||||
|
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/VisionClickEvent$Companion {
|
||||||
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface class space/kscience/visionforge/VisionClient : space/kscience/dataforge/context/Plugin {
|
public abstract interface class space/kscience/visionforge/VisionClient : space/kscience/dataforge/context/Plugin {
|
||||||
public abstract fun getVisionManager ()Lspace/kscience/visionforge/VisionManager;
|
public abstract fun getVisionManager ()Lspace/kscience/visionforge/VisionManager;
|
||||||
public abstract fun notifyPropertyChanged (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)V
|
public abstract fun notifyPropertyChanged (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)V
|
||||||
@ -579,6 +589,8 @@ public final class space/kscience/visionforge/VisionInputEvent$Companion {
|
|||||||
|
|
||||||
public final class space/kscience/visionforge/VisionKt {
|
public final class space/kscience/visionforge/VisionKt {
|
||||||
public static final fun getVisible (Lspace/kscience/visionforge/Vision;)Ljava/lang/Boolean;
|
public static final fun getVisible (Lspace/kscience/visionforge/Vision;)Ljava/lang/Boolean;
|
||||||
|
public static final fun onPropertyChange (Lspace/kscience/visionforge/Vision;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
||||||
|
public static synthetic fun onPropertyChange$default (Lspace/kscience/visionforge/Vision;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
|
||||||
public static final fun setVisible (Lspace/kscience/visionforge/Vision;Ljava/lang/Boolean;)V
|
public static final fun setVisible (Lspace/kscience/visionforge/Vision;Ljava/lang/Boolean;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,10 +659,10 @@ public abstract class space/kscience/visionforge/VisionPlugin : space/kscience/d
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface class space/kscience/visionforge/VisionProperties : space/kscience/dataforge/meta/MetaProvider {
|
public abstract interface class space/kscience/visionforge/VisionProperties : space/kscience/dataforge/meta/MetaProvider {
|
||||||
public abstract fun flowChanges ()Lkotlinx/coroutines/flow/Flow;
|
|
||||||
public fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Meta;
|
public fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Meta;
|
||||||
public abstract fun get (Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;)Lspace/kscience/dataforge/meta/Meta;
|
public abstract fun get (Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;)Lspace/kscience/dataforge/meta/Meta;
|
||||||
public static synthetic fun get$default (Lspace/kscience/visionforge/VisionProperties;Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
|
public static synthetic fun get$default (Lspace/kscience/visionforge/VisionProperties;Lspace/kscience/dataforge/names/Name;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
|
||||||
|
public abstract fun getChanges ()Lkotlinx/coroutines/flow/Flow;
|
||||||
public abstract fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
public abstract fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
||||||
public abstract fun getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
public abstract fun getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
||||||
public fun getValue (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Value;
|
public fun getValue (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Value;
|
||||||
@ -673,30 +685,6 @@ public final class space/kscience/visionforge/VisionPropertiesKt {
|
|||||||
public static synthetic fun root$default (Lspace/kscience/visionforge/MutableVisionProperties;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMeta;
|
public static synthetic fun root$default (Lspace/kscience/visionforge/MutableVisionProperties;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/VisionSubmitEvent : space/kscience/visionforge/VisionControlEvent {
|
|
||||||
public static final field Companion Lspace/kscience/visionforge/VisionSubmitEvent$Companion;
|
|
||||||
public fun <init> (Lspace/kscience/dataforge/meta/Meta;)V
|
|
||||||
public fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
|
|
||||||
public final fun getName ()Lspace/kscience/dataforge/names/Name;
|
|
||||||
public final fun getPayload ()Lspace/kscience/dataforge/meta/Meta;
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/VisionSubmitEvent$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
|
||||||
public static final field INSTANCE Lspace/kscience/visionforge/VisionSubmitEvent$$serializer;
|
|
||||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
|
||||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
|
||||||
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/visionforge/VisionSubmitEvent;
|
|
||||||
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
|
||||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
|
||||||
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/visionforge/VisionSubmitEvent;)V
|
|
||||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/VisionSubmitEvent$Companion {
|
|
||||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/VisionValueChangeEvent : space/kscience/visionforge/VisionControlEvent {
|
public final class space/kscience/visionforge/VisionValueChangeEvent : space/kscience/visionforge/VisionControlEvent {
|
||||||
public static final field Companion Lspace/kscience/visionforge/VisionValueChangeEvent$Companion;
|
public static final field Companion Lspace/kscience/visionforge/VisionValueChangeEvent$Companion;
|
||||||
public fun <init> (Lspace/kscience/dataforge/meta/Meta;)V
|
public fun <init> (Lspace/kscience/dataforge/meta/Meta;)V
|
||||||
@ -762,10 +750,10 @@ public abstract interface class space/kscience/visionforge/html/HtmlVisionFragme
|
|||||||
|
|
||||||
public final class space/kscience/visionforge/html/HtmlVisionRendererKt {
|
public final class space/kscience/visionforge/html/HtmlVisionRendererKt {
|
||||||
public static final fun appendTo (Lspace/kscience/visionforge/html/HtmlVisionFragment;Lspace/kscience/visionforge/html/VisionTagConsumer;)V
|
public static final fun appendTo (Lspace/kscience/visionforge/html/HtmlVisionFragment;Lspace/kscience/visionforge/html/VisionTagConsumer;)V
|
||||||
public static final fun visionFragment (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
|
public static final fun visionFragment (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
|
||||||
public static final fun visionFragment (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
|
public static final fun visionFragment (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
|
||||||
public static synthetic fun visionFragment$default (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
|
public static synthetic fun visionFragment$default (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
|
||||||
public static synthetic fun visionFragment$default (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
|
public static synthetic fun visionFragment$default (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/InputFeedbackMode : java/lang/Enum {
|
public final class space/kscience/visionforge/html/InputFeedbackMode : java/lang/Enum {
|
||||||
@ -794,21 +782,6 @@ public final class space/kscience/visionforge/html/ResourceLocation : java/lang/
|
|||||||
public abstract interface annotation class space/kscience/visionforge/html/VisionDSL : java/lang/annotation/Annotation {
|
public abstract interface annotation class space/kscience/visionforge/html/VisionDSL : java/lang/annotation/Annotation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionDisplay {
|
|
||||||
public fun <init> (Lspace/kscience/visionforge/VisionManager;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;)V
|
|
||||||
public final fun component1 ()Lspace/kscience/visionforge/VisionManager;
|
|
||||||
public final fun component2 ()Lspace/kscience/visionforge/Vision;
|
|
||||||
public final fun component3 ()Lspace/kscience/dataforge/meta/Meta;
|
|
||||||
public final fun copy (Lspace/kscience/visionforge/VisionManager;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/visionforge/html/VisionDisplay;
|
|
||||||
public static synthetic fun copy$default (Lspace/kscience/visionforge/html/VisionDisplay;Lspace/kscience/visionforge/VisionManager;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;ILjava/lang/Object;)Lspace/kscience/visionforge/html/VisionDisplay;
|
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
|
|
||||||
public final fun getVision ()Lspace/kscience/visionforge/Vision;
|
|
||||||
public final fun getVisionManager ()Lspace/kscience/visionforge/VisionManager;
|
|
||||||
public fun hashCode ()I
|
|
||||||
public fun toString ()Ljava/lang/String;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionOfCheckbox : space/kscience/visionforge/html/VisionOfHtmlInput {
|
public final class space/kscience/visionforge/html/VisionOfCheckbox : space/kscience/visionforge/html/VisionOfHtmlInput {
|
||||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfCheckbox$Companion;
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfCheckbox$Companion;
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
@ -831,14 +804,20 @@ public final class space/kscience/visionforge/html/VisionOfCheckbox$Companion {
|
|||||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface class space/kscience/visionforge/html/VisionOfHtml : space/kscience/visionforge/Vision {
|
public abstract class space/kscience/visionforge/html/VisionOfHtml : space/kscience/visionforge/AbstractVision {
|
||||||
public fun getClasses ()Ljava/util/Set;
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtml$Companion;
|
||||||
public fun getStyleString ()Ljava/lang/String;
|
public fun <init> ()V
|
||||||
public fun setClasses (Ljava/util/Set;)V
|
public synthetic fun <init> (ILspace/kscience/dataforge/meta/MutableMeta;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||||
public fun setStyleString (Ljava/lang/String;)V
|
public final fun getClasses ()Ljava/util/Set;
|
||||||
|
public final fun setClasses (Ljava/util/Set;)V
|
||||||
|
public static final synthetic fun write$Self (Lspace/kscience/visionforge/html/VisionOfHtml;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionOfHtmlButton : space/kscience/visionforge/AbstractControlVision, space/kscience/visionforge/DataControl, space/kscience/visionforge/html/VisionOfHtml {
|
public final class space/kscience/visionforge/html/VisionOfHtml$Companion {
|
||||||
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/html/VisionOfHtmlButton : space/kscience/visionforge/html/VisionOfHtmlControl, space/kscience/visionforge/ClickControl {
|
||||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlButton$Companion;
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlButton$Companion;
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
public final fun getLabel ()Ljava/lang/String;
|
public final fun getLabel ()Ljava/lang/String;
|
||||||
@ -860,7 +839,20 @@ public final class space/kscience/visionforge/html/VisionOfHtmlButton$Companion
|
|||||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionOfHtmlForm : space/kscience/visionforge/AbstractControlVision, space/kscience/visionforge/DataControl, space/kscience/visionforge/html/VisionOfHtml {
|
public abstract class space/kscience/visionforge/html/VisionOfHtmlControl : space/kscience/visionforge/html/VisionOfHtml, space/kscience/visionforge/ControlVision {
|
||||||
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlControl$Companion;
|
||||||
|
public fun <init> ()V
|
||||||
|
public synthetic fun <init> (ILspace/kscience/dataforge/meta/MutableMeta;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||||
|
public fun dispatchControlEvent (Lspace/kscience/visionforge/VisionControlEvent;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public fun getControlEventFlow ()Lkotlinx/coroutines/flow/SharedFlow;
|
||||||
|
public static final synthetic fun write$Self (Lspace/kscience/visionforge/html/VisionOfHtmlControl;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/html/VisionOfHtmlControl$Companion {
|
||||||
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/html/VisionOfHtmlForm : space/kscience/visionforge/html/VisionOfHtmlControl {
|
||||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlForm$Companion;
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlForm$Companion;
|
||||||
public fun <init> (Ljava/lang/String;)V
|
public fun <init> (Ljava/lang/String;)V
|
||||||
public final fun getFormId ()Ljava/lang/String;
|
public final fun getFormId ()Ljava/lang/String;
|
||||||
@ -884,14 +876,12 @@ public final class space/kscience/visionforge/html/VisionOfHtmlForm$Companion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionOfHtmlFormKt {
|
public final class space/kscience/visionforge/html/VisionOfHtmlFormKt {
|
||||||
|
public static final fun bindForm (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/html/VisionOfHtmlForm;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||||
public static final fun button (Lspace/kscience/visionforge/html/VisionOutput;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lspace/kscience/visionforge/html/VisionOfHtmlButton;
|
public static final fun button (Lspace/kscience/visionforge/html/VisionOutput;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lspace/kscience/visionforge/html/VisionOfHtmlButton;
|
||||||
public static synthetic fun button$default (Lspace/kscience/visionforge/html/VisionOutput;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/visionforge/html/VisionOfHtmlButton;
|
public static synthetic fun button$default (Lspace/kscience/visionforge/html/VisionOutput;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/visionforge/html/VisionOfHtmlButton;
|
||||||
public static final fun onFormSubmit (Lspace/kscience/visionforge/html/VisionOfHtmlForm;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job;
|
|
||||||
public static final fun visionOfForm (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/html/VisionOfHtmlForm;Ljava/lang/String;Lkotlinx/html/FormEncType;Lkotlinx/html/FormMethod;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
|
||||||
public static synthetic fun visionOfForm$default (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/html/VisionOfHtmlForm;Ljava/lang/String;Lkotlinx/html/FormEncType;Lkotlinx/html/FormMethod;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class space/kscience/visionforge/html/VisionOfHtmlInput : space/kscience/visionforge/AbstractControlVision, space/kscience/visionforge/html/VisionOfHtml {
|
public class space/kscience/visionforge/html/VisionOfHtmlInput : space/kscience/visionforge/html/VisionOfHtmlControl {
|
||||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlInput$Companion;
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlInput$Companion;
|
||||||
public synthetic fun <init> (ILspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
public synthetic fun <init> (ILspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||||
public fun <init> (Ljava/lang/String;)V
|
public fun <init> (Ljava/lang/String;)V
|
||||||
@ -961,7 +951,7 @@ public final class space/kscience/visionforge/html/VisionOfNumberField$Companion
|
|||||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionOfPlainHtml : space/kscience/visionforge/AbstractVision, space/kscience/visionforge/html/VisionOfHtml {
|
public final class space/kscience/visionforge/html/VisionOfPlainHtml : space/kscience/visionforge/html/VisionOfHtml {
|
||||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfPlainHtml$Companion;
|
public static final field Companion Lspace/kscience/visionforge/html/VisionOfPlainHtml$Companion;
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
public final fun getContent ()Ljava/lang/String;
|
public final fun getContent ()Ljava/lang/String;
|
||||||
@ -1037,6 +1027,7 @@ public final class space/kscience/visionforge/html/VisionOutput : space/kscience
|
|||||||
public final fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
|
public final fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
|
||||||
public final fun getName ()Lspace/kscience/dataforge/names/Name;
|
public final fun getName ()Lspace/kscience/dataforge/names/Name;
|
||||||
public final fun getVisionManager ()Lspace/kscience/visionforge/VisionManager;
|
public final fun getVisionManager ()Lspace/kscience/visionforge/VisionManager;
|
||||||
|
public final fun meta (Lkotlin/jvm/functions/Function1;)V
|
||||||
public final fun requirePlugin (Lspace/kscience/dataforge/context/PluginFactory;)V
|
public final fun requirePlugin (Lspace/kscience/dataforge/context/PluginFactory;)V
|
||||||
public final fun setMeta (Lspace/kscience/dataforge/meta/Meta;)V
|
public final fun setMeta (Lspace/kscience/dataforge/meta/Meta;)V
|
||||||
}
|
}
|
||||||
@ -1107,11 +1098,6 @@ public abstract class space/kscience/visionforge/html/VisionTagConsumer : kotlin
|
|||||||
public final class space/kscience/visionforge/html/VisionTagConsumer$Companion {
|
public final class space/kscience/visionforge/html/VisionTagConsumer$Companion {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/html/VisionTagConsumerKt {
|
|
||||||
public static final fun meta (Lspace/kscience/visionforge/html/VisionOutput;Lkotlin/jvm/functions/Function1;)V
|
|
||||||
public static final fun meta (Lspace/kscience/visionforge/html/VisionOutput;Lspace/kscience/dataforge/meta/MetaRepr;)V
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class space/kscience/visionforge/visitor/CountDistinctKt {
|
public final class space/kscience/visionforge/visitor/CountDistinctKt {
|
||||||
public static final fun countDistinct (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public static final fun countDistinct (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
public static final fun countDistinctBy (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public static final fun countDistinctBy (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
@ -8,7 +8,7 @@ kscience {
|
|||||||
jvm()
|
jvm()
|
||||||
js()
|
js()
|
||||||
native()
|
native()
|
||||||
wasm()
|
// wasm()
|
||||||
useCoroutines()
|
useCoroutines()
|
||||||
commonMain {
|
commonMain {
|
||||||
api("space.kscience:dataforge-context:$dataforgeVersion")
|
api("space.kscience:dataforge-context:$dataforgeVersion")
|
||||||
|
@ -2,11 +2,12 @@ package space.kscience.visionforge
|
|||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.parseAsName
|
import space.kscience.dataforge.names.parseAsName
|
||||||
@ -22,9 +23,6 @@ public abstract class VisionControlEvent : VisionEvent, MetaRepr {
|
|||||||
public interface ControlVision : Vision {
|
public interface ControlVision : Vision {
|
||||||
public val controlEventFlow: SharedFlow<VisionControlEvent>
|
public val controlEventFlow: SharedFlow<VisionControlEvent>
|
||||||
|
|
||||||
/**
|
|
||||||
* Fire a [VisionControlEvent] on this [ControlVision]
|
|
||||||
*/
|
|
||||||
public suspend fun dispatchControlEvent(event: VisionControlEvent)
|
public suspend fun dispatchControlEvent(event: VisionControlEvent)
|
||||||
|
|
||||||
override suspend fun receiveEvent(event: VisionEvent) {
|
override suspend fun receiveEvent(event: VisionEvent) {
|
||||||
@ -34,28 +32,6 @@ public interface ControlVision : Vision {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun ControlVision.asyncControlEvent(
|
|
||||||
event: VisionControlEvent,
|
|
||||||
scope: CoroutineScope = manager?.context ?: error("Can't fire asynchronous event for an orphan vision. Provide a scope."),
|
|
||||||
) {
|
|
||||||
scope.launch { dispatchControlEvent(event) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
public abstract class AbstractControlVision : AbstractVision(), ControlVision {
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private val mutableControlEventFlow = MutableSharedFlow<VisionControlEvent>()
|
|
||||||
|
|
||||||
override val controlEventFlow: SharedFlow<VisionControlEvent>
|
|
||||||
get() = mutableControlEventFlow
|
|
||||||
|
|
||||||
override suspend fun dispatchControlEvent(event: VisionControlEvent) {
|
|
||||||
mutableControlEventFlow.emit(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event for submitting changes
|
* An event for submitting changes
|
||||||
|
@ -64,7 +64,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of style names applied to this object. Order matters. Not inherited.
|
* List of names of styles applied to this object. Order matters. Not inherited.
|
||||||
*/
|
*/
|
||||||
public var Vision.styles: List<String>
|
public var Vision.styles: List<String>
|
||||||
get() = properties.own[Vision.STYLE_KEY]?.stringList ?: emptyList()
|
get() = properties.own[Vision.STYLE_KEY]?.stringList ?: emptyList()
|
||||||
|
@ -132,8 +132,6 @@ public class RootVision(override val manager: VisionManager) : AbstractVisionGro
|
|||||||
* Designate this [Vision] as a root and assign a [VisionManager] as its parent
|
* Designate this [Vision] as a root and assign a [VisionManager] as its parent
|
||||||
*/
|
*/
|
||||||
public fun Vision.setAsRoot(manager: VisionManager) {
|
public fun Vision.setAsRoot(manager: VisionManager) {
|
||||||
//do nothing if vision is already rooted
|
|
||||||
if(this.manager == manager) return
|
|
||||||
if (parent != null) error("Vision $this already has a parent. It could not be set as root")
|
if (parent != null) error("Vision $this already has a parent. It could not be set as root")
|
||||||
parent = RootVision(manager)
|
parent = RootVision(manager)
|
||||||
}
|
}
|
@ -2,44 +2,31 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.html.DIV
|
import kotlinx.html.DIV
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.InputType
|
||||||
import kotlinx.html.div
|
import kotlinx.html.div
|
||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
|
||||||
|
|
||||||
public interface VisionOfHtml : Vision {
|
@Serializable
|
||||||
|
public abstract class VisionOfHtml : AbstractVision() {
|
||||||
/**
|
|
||||||
* Html class strings for this instance. Does not use vision inheritance, but uses styles
|
|
||||||
*/
|
|
||||||
public var classes: Set<String>
|
public var classes: Set<String>
|
||||||
get() = properties[::classes.name, false, true].stringList?.toSet() ?: emptySet()
|
get() = properties[::classes.name, false].stringList?.toSet() ?: emptySet()
|
||||||
set(value) {
|
set(value) {
|
||||||
properties[::classes.name] = value.map { it.asValue() }
|
properties[::classes.name] = value.map { it.asValue() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom style string
|
|
||||||
*/
|
|
||||||
public var styleString: String?
|
|
||||||
get() = properties[::styleString.name,false,true].string
|
|
||||||
set(value){
|
|
||||||
properties[::styleString.name] = value?.asValue()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.plain")
|
@SerialName("html.plain")
|
||||||
public class VisionOfPlainHtml : AbstractVision(), VisionOfHtml {
|
public class VisionOfPlainHtml : VisionOfHtml() {
|
||||||
public var content: String? by properties.string()
|
public var content: String? by properties.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,14 +59,30 @@ public enum class InputFeedbackMode {
|
|||||||
NONE
|
NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public abstract class VisionOfHtmlControl: VisionOfHtml(), ControlVision{
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private val mutableControlEventFlow = MutableSharedFlow<VisionControlEvent>()
|
||||||
|
|
||||||
|
override val controlEventFlow: SharedFlow<VisionControlEvent>
|
||||||
|
get() = mutableControlEventFlow
|
||||||
|
|
||||||
|
override suspend fun dispatchControlEvent(event: VisionControlEvent) {
|
||||||
|
mutableControlEventFlow.emit(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.input")
|
@SerialName("html.input")
|
||||||
public open class VisionOfHtmlInput(
|
public open class VisionOfHtmlInput(
|
||||||
public val inputType: String,
|
public val inputType: String,
|
||||||
) : AbstractControlVision(), VisionOfHtml {
|
) : VisionOfHtmlControl() {
|
||||||
public var value: Value? by properties.value()
|
public var value: Value? by properties.value()
|
||||||
public var disabled: Boolean by properties.boolean { false }
|
public var disabled: Boolean by properties.boolean { false }
|
||||||
public var fieldName: String? by properties.string()
|
public var fieldName: String? by properties.string()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,6 @@ import kotlinx.serialization.Serializable
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.node
|
import space.kscience.dataforge.meta.node
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.visionforge.AbstractControlVision
|
|
||||||
import space.kscience.visionforge.DataControl
|
import space.kscience.visionforge.DataControl
|
||||||
import space.kscience.visionforge.onSubmit
|
import space.kscience.visionforge.onSubmit
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ import space.kscience.visionforge.onSubmit
|
|||||||
@SerialName("html.form")
|
@SerialName("html.form")
|
||||||
public class VisionOfHtmlForm(
|
public class VisionOfHtmlForm(
|
||||||
public val formId: String,
|
public val formId: String,
|
||||||
) : AbstractControlVision(), DataControl, VisionOfHtml {
|
) : VisionOfHtmlControl(), DataControl {
|
||||||
public var values: Meta? by properties.node()
|
public var values: Meta? by properties.node()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +45,7 @@ public fun VisionOfHtmlForm.onFormSubmit(scope: CoroutineScope, block: (Meta?) -
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.button")
|
@SerialName("html.button")
|
||||||
public class VisionOfHtmlButton : AbstractControlVision(), DataControl, VisionOfHtml {
|
public class VisionOfHtmlButton : VisionOfHtmlControl(), DataControl {
|
||||||
public var label: String? by properties.string()
|
public var label: String? by properties.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ public annotation class VisionDSL
|
|||||||
* A placeholder object to attach inline vision builders.
|
* A placeholder object to attach inline vision builders.
|
||||||
*/
|
*/
|
||||||
@VisionDSL
|
@VisionDSL
|
||||||
public class VisionOutput(override val context: Context, public val name: Name): ContextAware {
|
public class VisionOutput @PublishedApi internal constructor(override val context: Context, public val name: Name): ContextAware {
|
||||||
public var meta: Meta = Meta.EMPTY
|
public var meta: Meta = Meta.EMPTY
|
||||||
|
|
||||||
private val requirements: MutableSet<PluginFactory<*>> = HashSet()
|
private val requirements: MutableSet<PluginFactory<*>> = HashSet()
|
||||||
|
@ -10,7 +10,6 @@ import space.kscience.dataforge.context.Global
|
|||||||
import space.kscience.dataforge.context.request
|
import space.kscience.dataforge.context.request
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import kotlin.test.Ignore
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
@ -92,7 +91,6 @@ internal class VisionPropertyTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
fun testChildrenPropertyFlow() = runTest(timeout = 500.milliseconds) {
|
fun testChildrenPropertyFlow() = runTest(timeout = 500.milliseconds) {
|
||||||
val group = Global.request(VisionManager).group {
|
val group = Global.request(VisionManager).group {
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.dom.clear
|
import kotlinx.dom.clear
|
||||||
import kotlinx.html.TagConsumer
|
import kotlinx.html.TagConsumer
|
||||||
@ -8,7 +8,6 @@ import org.w3c.dom.HTMLElement
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.misc.DfType
|
import space.kscience.dataforge.misc.DfType
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Vision
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.cast
|
import kotlin.reflect.cast
|
||||||
|
|
||||||
@ -31,6 +30,7 @@ public interface ElementVisionRenderer {
|
|||||||
*/
|
*/
|
||||||
public fun render(
|
public fun render(
|
||||||
element: Element,
|
element: Element,
|
||||||
|
client: VisionClient,
|
||||||
name: Name,
|
name: Name,
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
@ -49,7 +49,7 @@ public interface ElementVisionRenderer {
|
|||||||
public class SingleTypeVisionRenderer<T : Vision>(
|
public class SingleTypeVisionRenderer<T : Vision>(
|
||||||
public val kClass: KClass<T>,
|
public val kClass: KClass<T>,
|
||||||
private val acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
private val acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
||||||
private val renderFunction: TagConsumer<HTMLElement>.(name: Name, vision: T, meta: Meta) -> Unit,
|
private val renderFunction: TagConsumer<HTMLElement>.(name: Name, client: VisionClient, vision: T, meta: Meta) -> Unit,
|
||||||
) : ElementVisionRenderer {
|
) : ElementVisionRenderer {
|
||||||
|
|
||||||
override fun rateVision(vision: Vision): Int =
|
override fun rateVision(vision: Vision): Int =
|
||||||
@ -57,18 +57,19 @@ public class SingleTypeVisionRenderer<T : Vision>(
|
|||||||
|
|
||||||
override fun render(
|
override fun render(
|
||||||
element: Element,
|
element: Element,
|
||||||
|
client: VisionClient,
|
||||||
name: Name,
|
name: Name,
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
) {
|
) {
|
||||||
element.clear()
|
element.clear()
|
||||||
element.append {
|
element.append {
|
||||||
renderFunction(name, kClass.cast(vision), meta)
|
renderFunction(name, client, kClass.cast(vision), meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <reified T : Vision> ElementVisionRenderer(
|
public inline fun <reified T : Vision> ElementVisionRenderer(
|
||||||
acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
||||||
noinline renderFunction: TagConsumer<HTMLElement>.(name: Name, vision: T, meta: Meta) -> Unit,
|
noinline renderFunction: TagConsumer<HTMLElement>.(name: Name, client: VisionClient, vision: T, meta: Meta) -> Unit,
|
||||||
): ElementVisionRenderer = SingleTypeVisionRenderer(T::class, acceptRating, renderFunction)
|
): ElementVisionRenderer = SingleTypeVisionRenderer(T::class, acceptRating, renderFunction)
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
@ -23,7 +23,7 @@ import space.kscience.dataforge.meta.int
|
|||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.parseAsName
|
import space.kscience.dataforge.names.parseAsName
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.html.VisionTagConsumer
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_ENDPOINT_ATTRIBUTE
|
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_ENDPOINT_ATTRIBUTE
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_FETCH_ATTRIBUTE
|
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_FETCH_ATTRIBUTE
|
||||||
@ -92,6 +92,13 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
eventCollector.emit(targetName to event)
|
eventCollector.emit(targetName to event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) {
|
||||||
|
vision.setAsRoot(visionManager)
|
||||||
|
val renderer: ElementVisionRenderer =
|
||||||
|
findRendererFor(vision) ?: error("Could not find renderer for ${vision::class}")
|
||||||
|
renderer.render(element, this, name, vision, outputMeta)
|
||||||
|
}
|
||||||
|
|
||||||
private fun startVisionUpdate(element: Element, visionName: Name, vision: Vision, outputMeta: Meta) {
|
private fun startVisionUpdate(element: Element, visionName: Name, vision: Vision, outputMeta: Meta) {
|
||||||
element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr ->
|
element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr ->
|
||||||
val wsUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) {
|
val wsUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) {
|
||||||
@ -174,24 +181,6 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) {
|
|
||||||
vision.setAsRoot(visionManager)
|
|
||||||
val renderer: ElementVisionRenderer =
|
|
||||||
findRendererFor(vision) ?: error("Could not find renderer for ${vision::class}")
|
|
||||||
//render vision
|
|
||||||
renderer.render(element, name, vision, outputMeta)
|
|
||||||
//start vision update from backend model
|
|
||||||
startVisionUpdate(element, name, vision, outputMeta)
|
|
||||||
//subscribe to a backwards events propagation for control visions
|
|
||||||
if(vision is ControlVision){
|
|
||||||
vision.controlEventFlow.onEach {
|
|
||||||
sendEvent(name,it)
|
|
||||||
}.launchIn(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch from server and render a vision, described in a given with [VisionTagConsumer.OUTPUT_CLASS] class.
|
* Fetch from server and render a vision, described in a given with [VisionTagConsumer.OUTPUT_CLASS] class.
|
||||||
*/
|
*/
|
||||||
@ -235,6 +224,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
response.text().then { text ->
|
response.text().then { text ->
|
||||||
val vision = visionManager.decodeFromString(text)
|
val vision = visionManager.decodeFromString(text)
|
||||||
renderVision(element, name, vision, outputMeta)
|
renderVision(element, name, vision, outputMeta)
|
||||||
|
startVisionUpdate(element, name, vision, outputMeta)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error { "Failed to fetch initial vision state from $fetchUrl" }
|
logger.error { "Failed to fetch initial vision state from $fetchUrl" }
|
||||||
@ -250,6 +240,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
}
|
}
|
||||||
logger.info { "Found embedded vision for output with name $name" }
|
logger.info { "Found embedded vision for output with name $name" }
|
||||||
renderVision(element, name, embeddedVision, outputMeta)
|
renderVision(element, name, embeddedVision, outputMeta)
|
||||||
|
startVisionUpdate(element, name, embeddedVision, outputMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Try to load vision via websocket
|
//Try to load vision via websocket
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -12,7 +12,8 @@ import space.kscience.dataforge.context.debug
|
|||||||
import space.kscience.dataforge.context.logger
|
import space.kscience.dataforge.context.logger
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.html.VisionOfHtmlButton
|
||||||
|
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert form data to Meta
|
* Convert form data to Meta
|
||||||
@ -48,7 +49,7 @@ public fun VisionClient.sendMetaEvent(targetName: Name, payload: MetaRepr): Unit
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val formVisionRenderer: ElementVisionRenderer =
|
internal val formVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ ->
|
ElementVisionRenderer<VisionOfHtmlForm> { name, client, vision, _ ->
|
||||||
|
|
||||||
val form = document.getElementById(vision.formId) as? HTMLFormElement
|
val form = document.getElementById(vision.formId) as? HTMLFormElement
|
||||||
?: error("An element with id = '${vision.formId} is not a form")
|
?: error("An element with id = '${vision.formId} is not a form")
|
||||||
@ -68,18 +69,22 @@ internal val formVisionRenderer: ElementVisionRenderer =
|
|||||||
form.onsubmit = { event ->
|
form.onsubmit = { event ->
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
val formData = FormData(form).toMeta()
|
val formData = FormData(form).toMeta()
|
||||||
vision.asyncControlEvent(VisionSubmitEvent(name = name, payload = formData))
|
client.context.launch {
|
||||||
|
client.sendEvent(name, VisionSubmitEvent(name = name, payload = formData))
|
||||||
|
}
|
||||||
console.info("Sent form data: ${formData.toMap()}")
|
console.info("Sent form data: ${formData.toMap()}")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val buttonVisionRenderer: ElementVisionRenderer =
|
internal val buttonVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfHtmlButton> { name, vision, _ ->
|
ElementVisionRenderer<VisionOfHtmlButton> { name, client, vision, _ ->
|
||||||
button(type = ButtonType.button).also { button ->
|
button(type = ButtonType.button).also { button ->
|
||||||
button.subscribeToVision(vision)
|
button.subscribeToVision(vision)
|
||||||
button.onclick = {
|
button.onclick = {
|
||||||
vision.asyncControlEvent(VisionSubmitEvent(name = name))
|
client.context.launch {
|
||||||
|
client.sendEvent(name, VisionSubmitEvent(name = name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vision.useProperty(VisionOfHtmlButton::label) {
|
vision.useProperty(VisionOfHtmlButton::label) {
|
||||||
button.innerHTML = it ?: ""
|
button.innerHTML = it ?: ""
|
@ -1,4 +1,4 @@
|
|||||||
package space.kscience.visionforge.html
|
package space.kscience.visionforge
|
||||||
|
|
||||||
import kotlinx.dom.clear
|
import kotlinx.dom.clear
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.InputType
|
||||||
@ -9,10 +9,7 @@ import org.w3c.dom.HTMLInputElement
|
|||||||
import space.kscience.dataforge.meta.asValue
|
import space.kscience.dataforge.meta.asValue
|
||||||
import space.kscience.dataforge.meta.double
|
import space.kscience.dataforge.meta.double
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import space.kscience.visionforge.VisionInputEvent
|
import space.kscience.visionforge.html.*
|
||||||
import space.kscience.visionforge.VisionValueChangeEvent
|
|
||||||
import space.kscience.visionforge.asyncControlEvent
|
|
||||||
import space.kscience.visionforge.useProperty
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes the HTML element to a given vision.
|
* Subscribes the HTML element to a given vision.
|
||||||
@ -23,10 +20,6 @@ internal fun HTMLElement.subscribeToVision(vision: VisionOfHtml) {
|
|||||||
vision.useProperty(VisionOfHtml::classes) {
|
vision.useProperty(VisionOfHtml::classes) {
|
||||||
classList.value = classes.joinToString(separator = " ")
|
classList.value = classes.joinToString(separator = " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
vision.useProperty(VisionOfHtml::styleString) {
|
|
||||||
style.cssText = it ?: ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +35,7 @@ private fun HTMLInputElement.subscribeToInput(inputVision: VisionOfHtmlInput) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val htmlVisionRenderer: ElementVisionRenderer =
|
internal val htmlVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfPlainHtml> { _, vision, _ ->
|
ElementVisionRenderer<VisionOfPlainHtml> { _, _, vision, _ ->
|
||||||
div().also { div ->
|
div().also { div ->
|
||||||
div.subscribeToVision(vision)
|
div.subscribeToVision(vision)
|
||||||
vision.useProperty(VisionOfPlainHtml::content) {
|
vision.useProperty(VisionOfPlainHtml::content) {
|
||||||
@ -54,18 +47,17 @@ internal val htmlVisionRenderer: ElementVisionRenderer =
|
|||||||
|
|
||||||
internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlInput>(
|
internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlInput>(
|
||||||
acceptRating = ElementVisionRenderer.DEFAULT_RATING - 1
|
acceptRating = ElementVisionRenderer.DEFAULT_RATING - 1
|
||||||
) { name, vision, _ ->
|
) { name, client, vision, _ ->
|
||||||
|
|
||||||
input {
|
input {
|
||||||
type = InputType.text
|
type = InputType.text
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.subscribeToInput(vision)
|
htmlInputElement.subscribeToInput(vision)
|
||||||
@ -76,17 +68,17 @@ internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val checkboxVisionRenderer: ElementVisionRenderer =
|
internal val checkboxVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfCheckbox> { name, vision, _ ->
|
ElementVisionRenderer<VisionOfCheckbox> { name, client, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.checkBox
|
type = InputType.checkBox
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -98,17 +90,17 @@ internal val checkboxVisionRenderer: ElementVisionRenderer =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val textVisionRenderer: ElementVisionRenderer =
|
internal val textVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfTextField> { name, vision, _ ->
|
ElementVisionRenderer<VisionOfTextField> { name, client, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.text
|
type = InputType.text
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.subscribeToInput(vision)
|
htmlInputElement.subscribeToInput(vision)
|
||||||
@ -119,20 +111,20 @@ internal val textVisionRenderer: ElementVisionRenderer =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val numberVisionRenderer: ElementVisionRenderer =
|
internal val numberVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfNumberField> { name, vision, _ ->
|
ElementVisionRenderer<VisionOfNumberField> { name, client, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.number
|
type = InputType.number
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
vision.asyncControlEvent(VisionValueChangeEvent(it.asValue(), name))
|
client.sendEventAsync(name, VisionValueChangeEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
vision.asyncControlEvent(VisionInputEvent(it.asValue(), name))
|
client.sendEventAsync(name, VisionInputEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +137,7 @@ internal val numberVisionRenderer: ElementVisionRenderer =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val rangeVisionRenderer: ElementVisionRenderer =
|
internal val rangeVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfRangeField> { name, vision, _ ->
|
ElementVisionRenderer<VisionOfRangeField> { name, client, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.range
|
type = InputType.range
|
||||||
min = vision.min.toString()
|
min = vision.min.toString()
|
||||||
@ -155,13 +147,13 @@ internal val rangeVisionRenderer: ElementVisionRenderer =
|
|||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
vision.asyncControlEvent(VisionValueChangeEvent(it.asValue(), name))
|
client.sendEventAsync(name, VisionValueChangeEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
vision.asyncControlEvent(VisionInputEvent(it.asValue(), name))
|
client.sendEventAsync(name, VisionInputEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ import org.w3c.xhr.FormData
|
|||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.dataforge.meta.stringList
|
import space.kscience.dataforge.meta.stringList
|
||||||
import space.kscience.visionforge.html.toMeta
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
package space.kscience.visionforge.meta
|
|
||||||
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.jupiter.api.Timeout
|
|
||||||
import space.kscience.dataforge.context.Global
|
|
||||||
import space.kscience.dataforge.context.request
|
|
||||||
import space.kscience.dataforge.meta.*
|
|
||||||
import space.kscience.visionforge.*
|
|
||||||
import kotlin.test.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
internal class PropertyFlowTest {
|
|
||||||
|
|
||||||
private val manager = Global.request(VisionManager)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Timeout(200)
|
|
||||||
fun testChildrenPropertyFlow() = runBlocking{
|
|
||||||
val group = Global.request(VisionManager).group {
|
|
||||||
|
|
||||||
properties {
|
|
||||||
"test" put 11
|
|
||||||
}
|
|
||||||
|
|
||||||
group("child") {
|
|
||||||
properties {
|
|
||||||
"test" put 22
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
val child = group.children["child"]!!
|
|
||||||
|
|
||||||
val changesFlow = child.flowPropertyValue("test", inherit = true).map {
|
|
||||||
it!!.int
|
|
||||||
}
|
|
||||||
|
|
||||||
val collectedValues = ArrayList<Int>(5)
|
|
||||||
|
|
||||||
val collectorJob = changesFlow.onEach {
|
|
||||||
collectedValues.add(it)
|
|
||||||
}.launchIn(this)
|
|
||||||
|
|
||||||
|
|
||||||
delay(2)
|
|
||||||
assertEquals(22, child.properties["test", true].int)
|
|
||||||
|
|
||||||
child.properties.remove("test")
|
|
||||||
delay(2)
|
|
||||||
|
|
||||||
assertEquals(11, child.properties["test", true].int)
|
|
||||||
group.properties["test"] = 33
|
|
||||||
delay(2)
|
|
||||||
|
|
||||||
assertEquals(33, child.properties["test", true].int)
|
|
||||||
|
|
||||||
collectorJob.cancel()
|
|
||||||
assertEquals(listOf(22, 11, 33), collectedValues)
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-gdml:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-gdml:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-gdml:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-gdml:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Common visionforge jupyter module
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-jupyter:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-jupyter:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-jupyter:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-jupyter:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -8,10 +8,10 @@ import space.kscience.dataforge.context.Context
|
|||||||
import space.kscience.dataforge.context.PluginFactory
|
import space.kscience.dataforge.context.PluginFactory
|
||||||
import space.kscience.dataforge.context.PluginTag
|
import space.kscience.dataforge.context.PluginTag
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.visionforge.html.JsVisionClient
|
import space.kscience.visionforge.JsVisionClient
|
||||||
import space.kscience.visionforge.html.renderAllVisions
|
import space.kscience.visionforge.renderAllVisions
|
||||||
import space.kscience.visionforge.html.renderAllVisionsById
|
import space.kscience.visionforge.renderAllVisionsById
|
||||||
import space.kscience.visionforge.html.renderAllVisionsIn
|
import space.kscience.visionforge.renderAllVisionsIn
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
public class VFNotebookClient : AbstractPlugin() {
|
public class VFNotebookClient : AbstractPlugin() {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package space.kscience.visionforge.gdml.jupyter
|
package space.kscience.visionforge.gdml.jupyter
|
||||||
|
|
||||||
import space.kscience.visionforge.html.runVisionClient
|
|
||||||
import space.kscience.visionforge.jupyter.VFNotebookClient
|
import space.kscience.visionforge.jupyter.VFNotebookClient
|
||||||
import space.kscience.visionforge.markup.MarkupPlugin
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
|
import space.kscience.visionforge.runVisionClient
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
import space.kscience.visionforge.tables.TableVisionJsPlugin
|
import space.kscience.visionforge.tables.TableVisionJsPlugin
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-markdown:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-markdown:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-markdown:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-markdown:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -13,13 +13,9 @@ import space.kscience.dataforge.context.PluginTag
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.VisionPlugin
|
|
||||||
import space.kscience.visionforge.html.ElementVisionRenderer
|
|
||||||
import space.kscience.visionforge.html.JsVisionClient
|
|
||||||
import space.kscience.visionforge.markup.VisionOfMarkup.Companion.COMMONMARK_FORMAT
|
import space.kscience.visionforge.markup.VisionOfMarkup.Companion.COMMONMARK_FORMAT
|
||||||
import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT
|
import space.kscience.visionforge.markup.VisionOfMarkup.Companion.GFM_FORMAT
|
||||||
import space.kscience.visionforge.useProperty
|
|
||||||
|
|
||||||
public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
|
public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||||
public val visionClient: JsVisionClient by require(JsVisionClient)
|
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||||
@ -31,7 +27,7 @@ public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
|
|||||||
else -> ElementVisionRenderer.ZERO_RATING
|
else -> ElementVisionRenderer.ZERO_RATING
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(element: Element,name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||||
require(vision is VisionOfMarkup) { "The vision is not a markup vision" }
|
require(vision is VisionOfMarkup) { "The vision is not a markup vision" }
|
||||||
val div = document.createElement("div")
|
val div = document.createElement("div")
|
||||||
val flavour = when (vision.format) {
|
val flavour = when (vision.format) {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-plotly:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-plotly:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-plotly:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-plotly:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -10,10 +10,7 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.plotly.PlotlyConfig
|
import space.kscience.plotly.PlotlyConfig
|
||||||
import space.kscience.plotly.plot
|
import space.kscience.plotly.plot
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.VisionPlugin
|
|
||||||
import space.kscience.visionforge.html.ElementVisionRenderer
|
|
||||||
import space.kscience.visionforge.html.JsVisionClient
|
|
||||||
|
|
||||||
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||||
public val visionClient: JsVisionClient by require(JsVisionClient)
|
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||||
@ -27,7 +24,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
|||||||
else -> ElementVisionRenderer.ZERO_RATING
|
else -> ElementVisionRenderer.ZERO_RATING
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||||
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
||||||
val config = PlotlyConfig.read(meta)
|
val config = PlotlyConfig.read(meta)
|
||||||
element.plot(config, plot)
|
element.plot(config, plot)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-server:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-server:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-server:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-server:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:visionforge-solid:0.4.0-dev-3`.
|
The Maven coordinates of this project are `space.kscience:visionforge-solid:0.3.0-rc`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:visionforge-solid:0.4.0-dev-3")
|
implementation("space.kscience:visionforge-solid:0.3.0-rc")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -747,7 +747,6 @@ public final class space/kscience/visionforge/solid/SolidKt {
|
|||||||
public static final fun getY (Lspace/kscience/visionforge/solid/Solid;)Ljava/lang/Number;
|
public static final fun getY (Lspace/kscience/visionforge/solid/Solid;)Ljava/lang/Number;
|
||||||
public static final fun getZ (Lspace/kscience/visionforge/solid/Solid;)Ljava/lang/Number;
|
public static final fun getZ (Lspace/kscience/visionforge/solid/Solid;)Ljava/lang/Number;
|
||||||
public static final fun rotate (Lspace/kscience/visionforge/solid/Solid;Lspace/kscience/kmath/geometry/Angle;Lspace/kscience/kmath/geometry/Vector3D;)V
|
public static final fun rotate (Lspace/kscience/visionforge/solid/Solid;Lspace/kscience/kmath/geometry/Angle;Lspace/kscience/kmath/geometry/Vector3D;)V
|
||||||
public static final fun scale (Lspace/kscience/visionforge/solid/Solid;Ljava/lang/Number;)V
|
|
||||||
public static final fun setDetail (Lspace/kscience/visionforge/solid/Solid;Ljava/lang/Integer;)V
|
public static final fun setDetail (Lspace/kscience/visionforge/solid/Solid;Ljava/lang/Integer;)V
|
||||||
public static final fun setIgnore (Lspace/kscience/visionforge/Vision;Ljava/lang/Boolean;)V
|
public static final fun setIgnore (Lspace/kscience/visionforge/Vision;Ljava/lang/Boolean;)V
|
||||||
public static final fun setLayer (Lspace/kscience/visionforge/solid/Solid;I)V
|
public static final fun setLayer (Lspace/kscience/visionforge/solid/Solid;I)V
|
||||||
@ -803,10 +802,8 @@ public final class space/kscience/visionforge/solid/SolidMaterial : space/kscien
|
|||||||
public final fun getEmissiveColor ()Lspace/kscience/visionforge/solid/ColorAccessor;
|
public final fun getEmissiveColor ()Lspace/kscience/visionforge/solid/ColorAccessor;
|
||||||
public final fun getOpacity ()F
|
public final fun getOpacity ()F
|
||||||
public final fun getSpecularColor ()Lspace/kscience/visionforge/solid/ColorAccessor;
|
public final fun getSpecularColor ()Lspace/kscience/visionforge/solid/ColorAccessor;
|
||||||
public final fun getType ()Ljava/lang/String;
|
|
||||||
public final fun getWireframe ()Z
|
public final fun getWireframe ()Z
|
||||||
public final fun setOpacity (F)V
|
public final fun setOpacity (F)V
|
||||||
public final fun setType (Ljava/lang/String;)V
|
|
||||||
public final fun setWireframe (Z)V
|
public final fun setWireframe (Z)V
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1090,6 +1087,23 @@ public final class space/kscience/visionforge/solid/SurfaceKt {
|
|||||||
public static synthetic fun surface$default (Lspace/kscience/visionforge/MutableVisionContainer;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/visionforge/solid/Surface;
|
public static synthetic fun surface$default (Lspace/kscience/visionforge/MutableVisionContainer;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/visionforge/solid/Surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/solid/specifications/AxesScheme : space/kscience/dataforge/meta/Scheme {
|
||||||
|
public static final field AXIS_SIZE D
|
||||||
|
public static final field AXIS_WIDTH D
|
||||||
|
public static final field Companion Lspace/kscience/visionforge/solid/specifications/AxesScheme$Companion;
|
||||||
|
public fun <init> ()V
|
||||||
|
public final fun getSize ()D
|
||||||
|
public final fun getVisible ()Z
|
||||||
|
public final fun getWidth ()D
|
||||||
|
public final fun setSize (D)V
|
||||||
|
public final fun setVisible (Z)V
|
||||||
|
public final fun setWidth (D)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/visionforge/solid/specifications/AxesScheme$Companion : space/kscience/dataforge/meta/SchemeSpec {
|
||||||
|
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/solid/specifications/CameraScheme : space/kscience/dataforge/meta/Scheme {
|
public final class space/kscience/visionforge/solid/specifications/CameraScheme : space/kscience/dataforge/meta/Scheme {
|
||||||
public static final field Companion Lspace/kscience/visionforge/solid/specifications/CameraScheme$Companion;
|
public static final field Companion Lspace/kscience/visionforge/solid/specifications/CameraScheme$Companion;
|
||||||
public static final field FAR_CLIP D
|
public static final field FAR_CLIP D
|
||||||
@ -1124,15 +1138,15 @@ public final class space/kscience/visionforge/solid/specifications/CameraSchemeK
|
|||||||
public final class space/kscience/visionforge/solid/specifications/Canvas3DOptions : space/kscience/dataforge/meta/Scheme {
|
public final class space/kscience/visionforge/solid/specifications/Canvas3DOptions : space/kscience/dataforge/meta/Scheme {
|
||||||
public static final field Companion Lspace/kscience/visionforge/solid/specifications/Canvas3DOptions$Companion;
|
public static final field Companion Lspace/kscience/visionforge/solid/specifications/Canvas3DOptions$Companion;
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
|
public final fun getAxes ()Lspace/kscience/visionforge/solid/specifications/AxesScheme;
|
||||||
public final fun getCamera ()Lspace/kscience/visionforge/solid/specifications/CameraScheme;
|
public final fun getCamera ()Lspace/kscience/visionforge/solid/specifications/CameraScheme;
|
||||||
public final fun getCanvasName ()Ljava/lang/String;
|
|
||||||
public final fun getClipping ()Lspace/kscience/visionforge/solid/specifications/PointScheme;
|
public final fun getClipping ()Lspace/kscience/visionforge/solid/specifications/PointScheme;
|
||||||
public final fun getControls ()Lspace/kscience/visionforge/solid/specifications/Canvas3DUIScheme;
|
public final fun getControls ()Lspace/kscience/visionforge/solid/specifications/Canvas3DUIScheme;
|
||||||
public final fun getLayers ()Ljava/util/List;
|
public final fun getLayers ()Ljava/util/List;
|
||||||
public final fun getOnSelect ()Lkotlin/jvm/functions/Function1;
|
public final fun getOnSelect ()Lkotlin/jvm/functions/Function1;
|
||||||
public final fun getSize ()Lspace/kscience/visionforge/solid/specifications/CanvasSize;
|
public final fun getSize ()Lspace/kscience/visionforge/solid/specifications/CanvasSize;
|
||||||
|
public final fun setAxes (Lspace/kscience/visionforge/solid/specifications/AxesScheme;)V
|
||||||
public final fun setCamera (Lspace/kscience/visionforge/solid/specifications/CameraScheme;)V
|
public final fun setCamera (Lspace/kscience/visionforge/solid/specifications/CameraScheme;)V
|
||||||
public final fun setCanvasName (Ljava/lang/String;)V
|
|
||||||
public final fun setClipping (Lspace/kscience/visionforge/solid/specifications/PointScheme;)V
|
public final fun setClipping (Lspace/kscience/visionforge/solid/specifications/PointScheme;)V
|
||||||
public final fun setControls (Lspace/kscience/visionforge/solid/specifications/Canvas3DUIScheme;)V
|
public final fun setControls (Lspace/kscience/visionforge/solid/specifications/Canvas3DUIScheme;)V
|
||||||
public final fun setLayers (Ljava/util/List;)V
|
public final fun setLayers (Ljava/util/List;)V
|
||||||
@ -1157,7 +1171,6 @@ public final class space/kscience/visionforge/solid/specifications/Canvas3DUISch
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/solid/specifications/Canvas3DUIScheme$Companion : space/kscience/dataforge/meta/SchemeSpec {
|
public final class space/kscience/visionforge/solid/specifications/Canvas3DUIScheme$Companion : space/kscience/dataforge/meta/SchemeSpec {
|
||||||
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class space/kscience/visionforge/solid/specifications/CanvasSize : space/kscience/dataforge/meta/Scheme {
|
public final class space/kscience/visionforge/solid/specifications/CanvasSize : space/kscience/dataforge/meta/Scheme {
|
||||||
|
@ -8,7 +8,6 @@ kscience {
|
|||||||
jvm()
|
jvm()
|
||||||
js()
|
js()
|
||||||
native()
|
native()
|
||||||
// wasm()
|
|
||||||
useSerialization {
|
useSerialization {
|
||||||
json()
|
json()
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user