Compare commits
3 Commits
cbf3f4941a
...
f0db286ce6
Author | SHA1 | Date | |
---|---|---|---|
f0db286ce6 | |||
d90c1edc6c | |||
38d6a9c419 |
15
CHANGELOG.md
15
CHANGELOG.md
@ -5,8 +5,6 @@
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
- **Breaking API** Move vision cache to upper level for renderers to avoid re-creating visions for page reload.
|
||||
- **Breaking API** Forms refactor
|
||||
|
||||
### Deprecated
|
||||
|
||||
@ -16,6 +14,19 @@
|
||||
|
||||
### 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
|
||||
|
||||
### Added
|
||||
|
26
README.md
26
README.md
@ -70,7 +70,11 @@ To learn more about DataForge, please consult the following URLs:
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [ui](ui)
|
||||
### [visionforge-compose-html](visionforge-compose-html)
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [visionforge-compose-multiplatform](visionforge-compose-multiplatform)
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
@ -111,6 +115,10 @@ To learn more about DataForge, please consult the following URLs:
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/compose-desktop-demo](demo/compose-desktop-demo)
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/gdml](demo/gdml)
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
@ -135,22 +143,6 @@ To learn more about DataForge, please consult the following URLs:
|
||||
>
|
||||
> **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)
|
||||
> Jupyter api artifact including all common modules
|
||||
>
|
||||
|
@ -10,7 +10,7 @@ val dataforgeVersion by extra("0.8.0")
|
||||
|
||||
allprojects {
|
||||
group = "space.kscience"
|
||||
version = "0.4.0-dev-3"
|
||||
version = "0.4.0"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
4
demo/compose-desktop-demo/README.md
Normal file
4
demo/compose-desktop-demo/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module compose-desktop-demo
|
||||
|
||||
|
||||
|
17
demo/compose-desktop-demo/api/compose-desktop-demo.api
Normal file
17
demo/compose-desktop-demo/api/compose-desktop-demo.api
Normal file
@ -0,0 +1,17 @@
|
||||
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
|
||||
}
|
||||
|
40
demo/compose-desktop-demo/build.gradle.kts
Normal file
40
demo/compose-desktop-demo/build.gradle.kts
Normal file
@ -0,0 +1,40 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
demo/compose-desktop-demo/src/jvmMain/kotlin/main.kt
Normal file
33
demo/compose-desktop-demo/src/jvmMain/kotlin/main.kt
Normal file
@ -0,0 +1,33 @@
|
||||
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 space.kscience.dataforge.context.Context
|
||||
import space.kscience.gdml.GdmlShowCase
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.compose.TreeStyles
|
||||
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.invoke
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.startApplication
|
||||
|
||||
|
||||
private class GDMLDemoApp : Application {
|
||||
@ -33,7 +33,7 @@ private class GDMLDemoApp : Application {
|
||||
}
|
||||
|
||||
renderComposable(element) {
|
||||
Style(TreeStyles)
|
||||
Style(VisionForgeStyles)
|
||||
Style {
|
||||
"html" {
|
||||
height(100.percent)
|
||||
|
@ -5,16 +5,16 @@ import org.w3c.dom.Document
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.plotly.scatter
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.compose.Tabs
|
||||
import space.kscience.visionforge.compose.TreeStyles
|
||||
import space.kscience.visionforge.html.Application
|
||||
import space.kscience.visionforge.html.Tabs
|
||||
import space.kscience.visionforge.html.VisionForgeStyles
|
||||
import space.kscience.visionforge.html.startApplication
|
||||
import space.kscience.visionforge.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.solid.three.compose.ThreeView
|
||||
import space.kscience.visionforge.startApplication
|
||||
import kotlin.random.Random
|
||||
|
||||
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")
|
||||
|
||||
renderComposable(element) {
|
||||
Style(TreeStyles)
|
||||
Style(VisionForgeStyles)
|
||||
Div({
|
||||
style {
|
||||
padding(0.pt)
|
||||
|
@ -15,8 +15,8 @@ import space.kscience.plotly.Plot
|
||||
import space.kscience.plotly.layout
|
||||
import space.kscience.plotly.models.Trace
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.compose.Vision
|
||||
import space.kscience.visionforge.compose.zIndex
|
||||
import space.kscience.visionforge.html.Vision
|
||||
import space.kscience.visionforge.html.zIndex
|
||||
import space.kscience.visionforge.markup.VisionOfMarkup
|
||||
import space.kscience.visionforge.plotly.asVision
|
||||
import space.kscience.visionforge.solid.*
|
||||
|
@ -1,4 +1,5 @@
|
||||
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 fun <init> (ILjava/util/List;Ljava/util/Collection;)V
|
||||
public final fun component1 ()I
|
||||
@ -15,6 +16,7 @@ public final class ru/mipt/npm/muon/monitor/Event {
|
||||
}
|
||||
|
||||
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 fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
@ -30,6 +32,7 @@ public final class ru/mipt/npm/muon/monitor/Event$Companion {
|
||||
}
|
||||
|
||||
public final class ru/mipt/npm/muon/monitor/Model {
|
||||
public static final field $stable I
|
||||
public fun <init> (Lspace/kscience/visionforge/VisionManager;)V
|
||||
public final fun displayEvent (Lru/mipt/npm/muon/monitor/Event;)V
|
||||
public final fun encodeToString ()Ljava/lang/String;
|
||||
@ -40,6 +43,7 @@ public final class ru/mipt/npm/muon/monitor/Model {
|
||||
}
|
||||
|
||||
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 GEOMETRY_TOLERANCE D
|
||||
public static final field INSTANCE Lru/mipt/npm/muon/monitor/Monitor;
|
||||
@ -57,6 +61,7 @@ public final class ru/mipt/npm/muon/monitor/ReadResourceKt {
|
||||
}
|
||||
|
||||
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 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;
|
||||
@ -67,6 +72,7 @@ public final class ru/mipt/npm/muon/monitor/SC1 {
|
||||
}
|
||||
|
||||
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 final fun getCenter ()Lspace/kscience/visionforge/solid/Float32Vector3D;
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
@ -81,6 +87,7 @@ 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 static final field $stable I
|
||||
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 fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
||||
@ -91,6 +98,7 @@ 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 static final field $stable I
|
||||
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 fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
||||
@ -134,6 +142,7 @@ 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 static final field $stable I
|
||||
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 fun generate ()Lorg/apache/commons/math3/geometry/euclidean/threed/Line;
|
||||
|
@ -44,8 +44,10 @@ kscience {
|
||||
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
||||
}
|
||||
}
|
||||
kotlin{
|
||||
explicitApi = null
|
||||
}
|
||||
|
||||
kotlin.explicitApi = null
|
||||
|
||||
application {
|
||||
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 space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.VisionManager
|
||||
import space.kscience.visionforge.compose.VisionForgeStyles
|
||||
import space.kscience.visionforge.html.Application
|
||||
import space.kscience.visionforge.html.VisionForgeStyles
|
||||
import space.kscience.visionforge.html.startApplication
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.startApplication
|
||||
|
||||
private class MMDemoApp : Application {
|
||||
|
||||
|
@ -53,6 +53,11 @@ public final class space/kscience/visionforge/examples/GenerateSchemaKt {
|
||||
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 static final fun main ()V
|
||||
public static synthetic fun main ([Ljava/lang/String;)V
|
||||
|
@ -1,8 +1,8 @@
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.visionforge.html.runVisionClient
|
||||
import space.kscience.visionforge.jupyter.VFNotebookClient
|
||||
import space.kscience.visionforge.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.runVisionClient
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.tables.TableVisionJsPlugin
|
||||
|
||||
|
@ -4,10 +4,10 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import org.w3c.dom.Document
|
||||
import space.kscience.visionforge.Application
|
||||
import space.kscience.visionforge.html.Application
|
||||
import space.kscience.visionforge.html.startApplication
|
||||
import space.kscience.visionforge.solid.x
|
||||
import space.kscience.visionforge.solid.y
|
||||
import space.kscience.visionforge.startApplication
|
||||
import kotlin.random.Random
|
||||
|
||||
private class ThreeDemoApp : Application {
|
||||
|
@ -40,13 +40,9 @@ dependencyResolutionManagement {
|
||||
}
|
||||
|
||||
include(
|
||||
// ":ui",
|
||||
// ":ui:react",
|
||||
// ":ui:ring",
|
||||
// ":ui:material",
|
||||
// ":ui:bootstrap",
|
||||
":visionforge-compose-html",
|
||||
":visionforge-core",
|
||||
":visionforge-compose-html",
|
||||
":visionforge-compose-multiplatform",
|
||||
":visionforge-solid",
|
||||
// ":visionforge-fx",
|
||||
":visionforge-threejs",
|
||||
@ -64,6 +60,7 @@ include(
|
||||
":demo:playground",
|
||||
// ":demo:plotly-fx",
|
||||
":demo:js-playground",
|
||||
":demo:compose-desktop-demo",
|
||||
":visionforge-jupyter",
|
||||
":visionforge-jupyter:visionforge-jupyter-common"
|
||||
)
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Module ui
|
||||
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Module bootstrap
|
||||
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
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"))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
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()
|
||||
// }
|
||||
//}
|
@ -1,77 +0,0 @@
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
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()
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
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()
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
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)
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*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;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
# Module react
|
||||
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,277 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
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
|
||||
}
|
||||
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
|
||||
@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
|
@ -1,10 +0,0 @@
|
||||
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))
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
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()
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
# Module ring
|
||||
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
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"))
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
@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>
|
@ -1,16 +0,0 @@
|
||||
@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>
|
@ -1,212 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
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)
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
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
3
ui/ring/webpack.config.d/01.ring.js
vendored
@ -1,3 +0,0 @@
|
||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
||||
|
||||
config.module.rules.push(...ringConfig.module.rules)
|
@ -4,9 +4,8 @@ plugins {
|
||||
}
|
||||
|
||||
kscience {
|
||||
jvm()
|
||||
js()
|
||||
// wasm()
|
||||
jvm()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@ -15,23 +14,17 @@ kotlin {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(projects.visionforgeCore)
|
||||
//need this to placate compose compiler in MPP applications
|
||||
api(compose.runtime)
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by getting {
|
||||
jsMain{
|
||||
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-icons:0.1.15")
|
||||
|
||||
api(compose.html.core)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
package space.kscience.visionforge.compose
|
||||
|
||||
import org.jetbrains.compose.web.css.StyleSheet
|
||||
|
||||
public object VisionForgeStyles: StyleSheet() {
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.web.css.Style
|
||||
@ -7,22 +7,20 @@ import org.jetbrains.compose.web.renderComposable
|
||||
import org.w3c.dom.Element
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.ElementVisionRenderer
|
||||
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
|
||||
*/
|
||||
public interface ComposeVisionRenderer: ElementVisionRenderer {
|
||||
public interface ComposeHtmlVisionRenderer : ElementVisionRenderer {
|
||||
|
||||
@Composable
|
||||
public fun DOMScope<Element>.render(client: VisionClient, name: Name, vision: Vision, meta: Meta)
|
||||
public fun DOMScope<Element>.render(name: Name, vision: Vision, meta: Meta)
|
||||
|
||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
renderComposable(element) {
|
||||
Style(VisionForgeStyles)
|
||||
render(client, name, vision, meta)
|
||||
render(name, vision, meta)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import org.jetbrains.compose.web.css.AlignItems
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.web.dom.*
|
@ -1,8 +1,7 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import app.softwork.bootstrapcompose.CloseButton
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
@ -39,7 +38,6 @@ public sealed class EditorPropertyState {
|
||||
*/
|
||||
@Composable
|
||||
public fun PropertyEditor(
|
||||
scope: CoroutineScope,
|
||||
rootMeta: MutableMeta,
|
||||
getPropertyState: (Name) -> EditorPropertyState,
|
||||
updates: Flow<Name>,
|
||||
@ -136,7 +134,7 @@ public fun PropertyEditor(
|
||||
Div({
|
||||
classes(TreeStyles.treeItem)
|
||||
}) {
|
||||
PropertyEditor(scope, rootMeta, getPropertyState, updates, name + token, rootDescriptor, expanded)
|
||||
PropertyEditor(rootMeta, getPropertyState, updates, name + token, rootDescriptor, expanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,13 +143,12 @@ public fun PropertyEditor(
|
||||
|
||||
@Composable
|
||||
public fun PropertyEditor(
|
||||
scope: CoroutineScope,
|
||||
properties: ObservableMutableMeta,
|
||||
descriptor: MetaDescriptor? = null,
|
||||
expanded: Boolean? = null,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
PropertyEditor(
|
||||
scope = scope,
|
||||
rootMeta = properties,
|
||||
getPropertyState = { name ->
|
||||
if (properties[name] != null) {
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import app.softwork.bootstrapcompose.Card
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
||||
import org.jetbrains.compose.web.css.*
|
||||
@ -67,26 +67,4 @@ public object TreeStyles : StyleSheet(VisionForgeStyles) {
|
||||
public val treeLabelSelected: String by style {
|
||||
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,28 @@
|
||||
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,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import org.jetbrains.compose.web.css.Color
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.web.dom.H5
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@ -48,7 +48,7 @@ public fun Vision(
|
||||
}
|
||||
|
||||
DisposableEffect(vision, name, renderer, meta) {
|
||||
renderer.render(scopeElement, client, name, vision, meta)
|
||||
renderer.render(scopeElement, name, vision, meta)
|
||||
onDispose {
|
||||
scopeElement.clear()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import org.jetbrains.compose.web.css.*
|
||||
import org.jetbrains.compose.web.css.keywords.CSSAutoKeyword
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.web.css.DisplayStyle
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
package space.kscience.visionforge.compose
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.uuid.UUID
|
21
visionforge-compose-multiplatform/README.md
Normal file
21
visionforge-compose-multiplatform/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# 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")
|
||||
}
|
||||
```
|
35
visionforge-compose-multiplatform/build.gradle.kts
Normal file
35
visionforge-compose-multiplatform/build.gradle.kts
Normal file
@ -0,0 +1,35 @@
|
||||
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
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
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)
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
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)
|
@ -0,0 +1,69 @@
|
||||
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)
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
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,
|
||||
)
|
||||
}
|
@ -0,0 +1,270 @@
|
||||
@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:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-core:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-core:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-core:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-core:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -1,3 +1,16 @@
|
||||
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 static final field Companion Lspace/kscience/visionforge/AbstractVision$Companion;
|
||||
public fun <init> ()V
|
||||
@ -34,29 +47,20 @@ 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 abstract class space/kscience/visionforge/AbstractVisionProperties : space/kscience/visionforge/MutableVisionProperties {
|
||||
public fun <init> (Lspace/kscience/visionforge/Vision;)V
|
||||
public synthetic fun getChanges ()Lkotlinx/coroutines/flow/Flow;
|
||||
public fun getChanges ()Lkotlinx/coroutines/flow/SharedFlow;
|
||||
public class space/kscience/visionforge/AbstractVisionProperties : space/kscience/visionforge/MutableVisionProperties {
|
||||
public fun <init> (Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/MutableMeta;)V
|
||||
public fun flowChanges ()Lkotlinx/coroutines/flow/Flow;
|
||||
protected final fun getChangesInternal ()Lkotlinx/coroutines/flow/MutableSharedFlow;
|
||||
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
||||
protected final fun getOrCreateProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||
public fun getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
||||
protected abstract fun getProperties ()Lspace/kscience/dataforge/meta/MutableMeta;
|
||||
public synthetic fun getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
||||
public final fun getOwn ()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 final fun getVision ()Lspace/kscience/visionforge/Vision;
|
||||
public fun invalidate (Lspace/kscience/dataforge/names/Name;)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 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 static final field BLUE_KEY Ljava/lang/String;
|
||||
public static final field GREEN_KEY Ljava/lang/String;
|
||||
@ -223,13 +227,21 @@ public abstract interface class space/kscience/visionforge/ControlVision : space
|
||||
}
|
||||
|
||||
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 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 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 onClick (Lspace/kscience/visionforge/ClickControl;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
||||
public static final fun asyncControlEvent (Lspace/kscience/visionforge/ControlVision;Lspace/kscience/visionforge/VisionControlEvent;Lkotlinx/coroutines/CoroutineScope;)V
|
||||
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 {
|
||||
@ -320,9 +332,9 @@ public final class space/kscience/visionforge/StyleReference {
|
||||
|
||||
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;Lspace/kscience/dataforge/meta/Specification;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 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/Specification;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 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
|
||||
}
|
||||
@ -364,7 +376,9 @@ public final class space/kscience/visionforge/StyleSheetKt {
|
||||
|
||||
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;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;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;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;
|
||||
@ -462,30 +476,6 @@ public final class space/kscience/visionforge/VisionChildren$Companion {
|
||||
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 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
|
||||
@ -589,8 +579,6 @@ public final class space/kscience/visionforge/VisionInputEvent$Companion {
|
||||
|
||||
public final class space/kscience/visionforge/VisionKt {
|
||||
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
|
||||
}
|
||||
|
||||
@ -659,10 +647,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 fun flowChanges ()Lkotlinx/coroutines/flow/Flow;
|
||||
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 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 getOwn ()Lspace/kscience/dataforge/meta/Meta;
|
||||
public fun getValue (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Value;
|
||||
@ -685,6 +673,30 @@ 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 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 static final field Companion Lspace/kscience/visionforge/VisionValueChangeEvent$Companion;
|
||||
public fun <init> (Lspace/kscience/dataforge/meta/Meta;)V
|
||||
@ -750,10 +762,10 @@ public abstract interface class space/kscience/visionforge/html/HtmlVisionFragme
|
||||
|
||||
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 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;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;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;Lkotlin/jvm/functions/Function2;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)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/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 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/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 final class space/kscience/visionforge/html/InputFeedbackMode : java/lang/Enum {
|
||||
@ -782,6 +794,21 @@ 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 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 static final field Companion Lspace/kscience/visionforge/html/VisionOfCheckbox$Companion;
|
||||
public fun <init> ()V
|
||||
@ -804,20 +831,14 @@ public final class space/kscience/visionforge/html/VisionOfCheckbox$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public abstract class space/kscience/visionforge/html/VisionOfHtml : space/kscience/visionforge/AbstractVision {
|
||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtml$Companion;
|
||||
public fun <init> ()V
|
||||
public synthetic fun <init> (ILspace/kscience/dataforge/meta/MutableMeta;Lkotlinx/serialization/internal/SerializationConstructorMarker;)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 abstract interface class space/kscience/visionforge/html/VisionOfHtml : space/kscience/visionforge/Vision {
|
||||
public fun getClasses ()Ljava/util/Set;
|
||||
public fun getStyleString ()Ljava/lang/String;
|
||||
public fun setClasses (Ljava/util/Set;)V
|
||||
public fun setStyleString (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
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 final class space/kscience/visionforge/html/VisionOfHtmlButton : space/kscience/visionforge/AbstractControlVision, space/kscience/visionforge/DataControl, space/kscience/visionforge/html/VisionOfHtml {
|
||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlButton$Companion;
|
||||
public fun <init> ()V
|
||||
public final fun getLabel ()Ljava/lang/String;
|
||||
@ -839,20 +860,7 @@ public final class space/kscience/visionforge/html/VisionOfHtmlButton$Companion
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
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 final class space/kscience/visionforge/html/VisionOfHtmlForm : space/kscience/visionforge/AbstractControlVision, space/kscience/visionforge/DataControl, space/kscience/visionforge/html/VisionOfHtml {
|
||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlForm$Companion;
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public final fun getFormId ()Ljava/lang/String;
|
||||
@ -876,12 +884,14 @@ public final class space/kscience/visionforge/html/VisionOfHtmlForm$Companion {
|
||||
}
|
||||
|
||||
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 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/html/VisionOfHtmlControl {
|
||||
public class space/kscience/visionforge/html/VisionOfHtmlInput : space/kscience/visionforge/AbstractControlVision, space/kscience/visionforge/html/VisionOfHtml {
|
||||
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 fun <init> (Ljava/lang/String;)V
|
||||
@ -951,7 +961,7 @@ public final class space/kscience/visionforge/html/VisionOfNumberField$Companion
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class space/kscience/visionforge/html/VisionOfPlainHtml : space/kscience/visionforge/html/VisionOfHtml {
|
||||
public final class space/kscience/visionforge/html/VisionOfPlainHtml : space/kscience/visionforge/AbstractVision, space/kscience/visionforge/html/VisionOfHtml {
|
||||
public static final field Companion Lspace/kscience/visionforge/html/VisionOfPlainHtml$Companion;
|
||||
public fun <init> ()V
|
||||
public final fun getContent ()Ljava/lang/String;
|
||||
@ -1027,7 +1037,6 @@ public final class space/kscience/visionforge/html/VisionOutput : space/kscience
|
||||
public final fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
|
||||
public final fun getName ()Lspace/kscience/dataforge/names/Name;
|
||||
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 setMeta (Lspace/kscience/dataforge/meta/Meta;)V
|
||||
}
|
||||
@ -1098,6 +1107,11 @@ 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/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 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;
|
||||
|
@ -8,7 +8,7 @@ kscience {
|
||||
jvm()
|
||||
js()
|
||||
native()
|
||||
// wasm()
|
||||
wasm()
|
||||
useCoroutines()
|
||||
commonMain {
|
||||
api("space.kscience:dataforge-context:$dataforgeVersion")
|
||||
|
@ -2,12 +2,11 @@ package space.kscience.visionforge
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
@ -23,6 +22,9 @@ public abstract class VisionControlEvent : VisionEvent, MetaRepr {
|
||||
public interface ControlVision : Vision {
|
||||
public val controlEventFlow: SharedFlow<VisionControlEvent>
|
||||
|
||||
/**
|
||||
* Fire a [VisionControlEvent] on this [ControlVision]
|
||||
*/
|
||||
public suspend fun dispatchControlEvent(event: VisionControlEvent)
|
||||
|
||||
override suspend fun receiveEvent(event: VisionEvent) {
|
||||
@ -32,6 +34,28 @@ 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
|
||||
|
@ -64,7 +64,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
|
||||
}
|
||||
|
||||
/**
|
||||
* List of names of styles applied to this object. Order matters. Not inherited.
|
||||
* List of style names applied to this object. Order matters. Not inherited.
|
||||
*/
|
||||
public var Vision.styles: List<String>
|
||||
get() = properties.own[Vision.STYLE_KEY]?.stringList ?: emptyList()
|
||||
|
@ -132,6 +132,8 @@ public class RootVision(override val manager: VisionManager) : AbstractVisionGro
|
||||
* Designate this [Vision] as a root and assign a [VisionManager] as its parent
|
||||
*/
|
||||
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")
|
||||
parent = RootVision(manager)
|
||||
}
|
@ -2,31 +2,44 @@ package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.html.DIV
|
||||
import kotlinx.html.InputType
|
||||
import kotlinx.html.div
|
||||
import kotlinx.html.stream.createHTML
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.visionforge.*
|
||||
|
||||
|
||||
@Serializable
|
||||
public abstract class VisionOfHtml : AbstractVision() {
|
||||
public interface VisionOfHtml : Vision {
|
||||
|
||||
/**
|
||||
* Html class strings for this instance. Does not use vision inheritance, but uses styles
|
||||
*/
|
||||
public var classes: Set<String>
|
||||
get() = properties[::classes.name, false].stringList?.toSet() ?: emptySet()
|
||||
get() = properties[::classes.name, false, true].stringList?.toSet() ?: emptySet()
|
||||
set(value) {
|
||||
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
|
||||
@SerialName("html.plain")
|
||||
public class VisionOfPlainHtml : VisionOfHtml() {
|
||||
public class VisionOfPlainHtml : AbstractVision(), VisionOfHtml {
|
||||
public var content: String? by properties.string()
|
||||
}
|
||||
|
||||
@ -59,30 +72,14 @@ public enum class InputFeedbackMode {
|
||||
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
|
||||
@SerialName("html.input")
|
||||
public open class VisionOfHtmlInput(
|
||||
public val inputType: String,
|
||||
) : VisionOfHtmlControl() {
|
||||
) : AbstractControlVision(), VisionOfHtml {
|
||||
public var value: Value? by properties.value()
|
||||
public var disabled: Boolean by properties.boolean { false }
|
||||
public var fieldName: String? by properties.string()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,7 @@ import kotlinx.serialization.Serializable
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.node
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.visionforge.AbstractControlVision
|
||||
import space.kscience.visionforge.DataControl
|
||||
import space.kscience.visionforge.onSubmit
|
||||
|
||||
@ -18,7 +19,7 @@ import space.kscience.visionforge.onSubmit
|
||||
@SerialName("html.form")
|
||||
public class VisionOfHtmlForm(
|
||||
public val formId: String,
|
||||
) : VisionOfHtmlControl(), DataControl {
|
||||
) : AbstractControlVision(), DataControl, VisionOfHtml {
|
||||
public var values: Meta? by properties.node()
|
||||
}
|
||||
|
||||
@ -45,7 +46,7 @@ public fun VisionOfHtmlForm.onFormSubmit(scope: CoroutineScope, block: (Meta?) -
|
||||
|
||||
@Serializable
|
||||
@SerialName("html.button")
|
||||
public class VisionOfHtmlButton : VisionOfHtmlControl(), DataControl {
|
||||
public class VisionOfHtmlButton : AbstractControlVision(), DataControl, VisionOfHtml {
|
||||
public var label: String? by properties.string()
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ public annotation class VisionDSL
|
||||
* A placeholder object to attach inline vision builders.
|
||||
*/
|
||||
@VisionDSL
|
||||
public class VisionOutput @PublishedApi internal constructor(override val context: Context, public val name: Name): ContextAware {
|
||||
public class VisionOutput(override val context: Context, public val name: Name): ContextAware {
|
||||
public var meta: Meta = Meta.EMPTY
|
||||
|
||||
private val requirements: MutableSet<PluginFactory<*>> = HashSet()
|
||||
|
@ -10,6 +10,7 @@ import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.visionforge.*
|
||||
import kotlin.test.Ignore
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
@ -91,6 +92,7 @@ internal class VisionPropertyTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
fun testChildrenPropertyFlow() = runTest(timeout = 500.milliseconds) {
|
||||
val group = Global.request(VisionManager).group {
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -46,7 +46,7 @@ public interface Application: CoroutineScope {
|
||||
}
|
||||
|
||||
public fun startApplication(builder: () -> Application) {
|
||||
fun start(document: Document, state: dynamic): Application{
|
||||
fun start(document: Document, state: dynamic): Application {
|
||||
val application = builder()
|
||||
|
||||
@Suppress("UnsafeCastFromDynamic")
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.dom.clear
|
||||
import kotlinx.html.TagConsumer
|
||||
@ -8,6 +8,7 @@ import org.w3c.dom.HTMLElement
|
||||
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
|
||||
|
||||
@ -30,7 +31,6 @@ public interface ElementVisionRenderer {
|
||||
*/
|
||||
public fun render(
|
||||
element: Element,
|
||||
client: VisionClient,
|
||||
name: Name,
|
||||
vision: Vision,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
@ -49,7 +49,7 @@ public interface ElementVisionRenderer {
|
||||
public class SingleTypeVisionRenderer<T : Vision>(
|
||||
public val kClass: KClass<T>,
|
||||
private val acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
||||
private val renderFunction: TagConsumer<HTMLElement>.(name: Name, client: VisionClient, vision: T, meta: Meta) -> Unit,
|
||||
private val renderFunction: TagConsumer<HTMLElement>.(name: Name, vision: T, meta: Meta) -> Unit,
|
||||
) : ElementVisionRenderer {
|
||||
|
||||
override fun rateVision(vision: Vision): Int =
|
||||
@ -57,19 +57,18 @@ public class SingleTypeVisionRenderer<T : Vision>(
|
||||
|
||||
override fun render(
|
||||
element: Element,
|
||||
client: VisionClient,
|
||||
name: Name,
|
||||
vision: Vision,
|
||||
meta: Meta,
|
||||
) {
|
||||
element.clear()
|
||||
element.append {
|
||||
renderFunction(name, client, kClass.cast(vision), meta)
|
||||
renderFunction(name, kClass.cast(vision), meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun <reified T : Vision> ElementVisionRenderer(
|
||||
acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
||||
noinline renderFunction: TagConsumer<HTMLElement>.(name: Name, client: VisionClient, vision: T, meta: Meta) -> Unit,
|
||||
noinline renderFunction: TagConsumer<HTMLElement>.(name: Name, vision: T, meta: Meta) -> Unit,
|
||||
): ElementVisionRenderer = SingleTypeVisionRenderer(T::class, acceptRating, renderFunction)
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.browser.document
|
||||
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.asName
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.html.VisionTagConsumer
|
||||
import space.kscience.visionforge.*
|
||||
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_FETCH_ATTRIBUTE
|
||||
@ -92,13 +92,6 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
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) {
|
||||
element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr ->
|
||||
val wsUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) {
|
||||
@ -181,6 +174,24 @@ 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.
|
||||
*/
|
||||
@ -224,7 +235,6 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
response.text().then { text ->
|
||||
val vision = visionManager.decodeFromString(text)
|
||||
renderVision(element, name, vision, outputMeta)
|
||||
startVisionUpdate(element, name, vision, outputMeta)
|
||||
}
|
||||
} else {
|
||||
logger.error { "Failed to fetch initial vision state from $fetchUrl" }
|
||||
@ -240,7 +250,6 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
||||
}
|
||||
logger.info { "Found embedded vision for output with name $name" }
|
||||
renderVision(element, name, embeddedVision, outputMeta)
|
||||
startVisionUpdate(element, name, embeddedVision, outputMeta)
|
||||
}
|
||||
|
||||
//Try to load vision via websocket
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.coroutines.launch
|
||||
@ -12,8 +12,7 @@ import space.kscience.dataforge.context.debug
|
||||
import space.kscience.dataforge.context.logger
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.html.VisionOfHtmlButton
|
||||
import space.kscience.visionforge.html.VisionOfHtmlForm
|
||||
import space.kscience.visionforge.*
|
||||
|
||||
/**
|
||||
* Convert form data to Meta
|
||||
@ -49,7 +48,7 @@ public fun VisionClient.sendMetaEvent(targetName: Name, payload: MetaRepr): Unit
|
||||
}
|
||||
|
||||
internal val formVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfHtmlForm> { name, client, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ ->
|
||||
|
||||
val form = document.getElementById(vision.formId) as? HTMLFormElement
|
||||
?: error("An element with id = '${vision.formId} is not a form")
|
||||
@ -69,22 +68,18 @@ internal val formVisionRenderer: ElementVisionRenderer =
|
||||
form.onsubmit = { event ->
|
||||
event.preventDefault()
|
||||
val formData = FormData(form).toMeta()
|
||||
client.context.launch {
|
||||
client.sendEvent(name, VisionSubmitEvent(name = name, payload = formData))
|
||||
}
|
||||
vision.asyncControlEvent(VisionSubmitEvent(name = name, payload = formData))
|
||||
console.info("Sent form data: ${formData.toMap()}")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
internal val buttonVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfHtmlButton> { name, client, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfHtmlButton> { name, vision, _ ->
|
||||
button(type = ButtonType.button).also { button ->
|
||||
button.subscribeToVision(vision)
|
||||
button.onclick = {
|
||||
client.context.launch {
|
||||
client.sendEvent(name, VisionSubmitEvent(name = name))
|
||||
}
|
||||
vision.asyncControlEvent(VisionSubmitEvent(name = name))
|
||||
}
|
||||
vision.useProperty(VisionOfHtmlButton::label) {
|
||||
button.innerHTML = it ?: ""
|
@ -1,4 +1,4 @@
|
||||
package space.kscience.visionforge
|
||||
package space.kscience.visionforge.html
|
||||
|
||||
import kotlinx.dom.clear
|
||||
import kotlinx.html.InputType
|
||||
@ -9,7 +9,10 @@ import org.w3c.dom.HTMLInputElement
|
||||
import space.kscience.dataforge.meta.asValue
|
||||
import space.kscience.dataforge.meta.double
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.visionforge.html.*
|
||||
import space.kscience.visionforge.VisionInputEvent
|
||||
import space.kscience.visionforge.VisionValueChangeEvent
|
||||
import space.kscience.visionforge.asyncControlEvent
|
||||
import space.kscience.visionforge.useProperty
|
||||
|
||||
/**
|
||||
* Subscribes the HTML element to a given vision.
|
||||
@ -20,6 +23,10 @@ internal fun HTMLElement.subscribeToVision(vision: VisionOfHtml) {
|
||||
vision.useProperty(VisionOfHtml::classes) {
|
||||
classList.value = classes.joinToString(separator = " ")
|
||||
}
|
||||
|
||||
vision.useProperty(VisionOfHtml::styleString) {
|
||||
style.cssText = it ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,7 +42,7 @@ private fun HTMLInputElement.subscribeToInput(inputVision: VisionOfHtmlInput) {
|
||||
}
|
||||
|
||||
internal val htmlVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfPlainHtml> { _, _, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfPlainHtml> { _, vision, _ ->
|
||||
div().also { div ->
|
||||
div.subscribeToVision(vision)
|
||||
vision.useProperty(VisionOfPlainHtml::content) {
|
||||
@ -47,17 +54,18 @@ internal val htmlVisionRenderer: ElementVisionRenderer =
|
||||
|
||||
internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlInput>(
|
||||
acceptRating = ElementVisionRenderer.DEFAULT_RATING - 1
|
||||
) { name, client, vision, _ ->
|
||||
) { name, vision, _ ->
|
||||
|
||||
input {
|
||||
type = InputType.text
|
||||
}.also { htmlInputElement ->
|
||||
|
||||
htmlInputElement.onchange = {
|
||||
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||
}
|
||||
|
||||
htmlInputElement.oninput = {
|
||||
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||
}
|
||||
|
||||
htmlInputElement.subscribeToInput(vision)
|
||||
@ -68,17 +76,17 @@ internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<
|
||||
}
|
||||
|
||||
internal val checkboxVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfCheckbox> { name, client, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfCheckbox> { name, vision, _ ->
|
||||
input {
|
||||
type = InputType.checkBox
|
||||
}.also { htmlInputElement ->
|
||||
|
||||
htmlInputElement.onchange = {
|
||||
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||
}
|
||||
|
||||
htmlInputElement.oninput = {
|
||||
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||
}
|
||||
|
||||
|
||||
@ -90,17 +98,17 @@ internal val checkboxVisionRenderer: ElementVisionRenderer =
|
||||
}
|
||||
|
||||
internal val textVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfTextField> { name, client, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfTextField> { name, vision, _ ->
|
||||
input {
|
||||
type = InputType.text
|
||||
}.also { htmlInputElement ->
|
||||
|
||||
htmlInputElement.onchange = {
|
||||
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||
}
|
||||
|
||||
htmlInputElement.oninput = {
|
||||
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||
}
|
||||
|
||||
htmlInputElement.subscribeToInput(vision)
|
||||
@ -111,20 +119,20 @@ internal val textVisionRenderer: ElementVisionRenderer =
|
||||
}
|
||||
|
||||
internal val numberVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfNumberField> { name, client, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfNumberField> { name, vision, _ ->
|
||||
input {
|
||||
type = InputType.number
|
||||
}.also { htmlInputElement ->
|
||||
|
||||
htmlInputElement.onchange = {
|
||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||
client.sendEventAsync(name, VisionValueChangeEvent(it.asValue(), name))
|
||||
vision.asyncControlEvent(VisionValueChangeEvent(it.asValue(), name))
|
||||
}
|
||||
}
|
||||
|
||||
htmlInputElement.oninput = {
|
||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||
client.sendEventAsync(name, VisionInputEvent(it.asValue(), name))
|
||||
vision.asyncControlEvent(VisionInputEvent(it.asValue(), name))
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +145,7 @@ internal val numberVisionRenderer: ElementVisionRenderer =
|
||||
}
|
||||
|
||||
internal val rangeVisionRenderer: ElementVisionRenderer =
|
||||
ElementVisionRenderer<VisionOfRangeField> { name, client, vision, _ ->
|
||||
ElementVisionRenderer<VisionOfRangeField> { name, vision, _ ->
|
||||
input {
|
||||
type = InputType.range
|
||||
min = vision.min.toString()
|
||||
@ -147,13 +155,13 @@ internal val rangeVisionRenderer: ElementVisionRenderer =
|
||||
|
||||
htmlInputElement.onchange = {
|
||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||
client.sendEventAsync(name, VisionValueChangeEvent(it.asValue(), name))
|
||||
vision.asyncControlEvent(VisionValueChangeEvent(it.asValue(), name))
|
||||
}
|
||||
}
|
||||
|
||||
htmlInputElement.oninput = {
|
||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||
client.sendEventAsync(name, VisionInputEvent(it.asValue(), name))
|
||||
vision.asyncControlEvent(VisionInputEvent(it.asValue(), name))
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import org.w3c.xhr.FormData
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.stringList
|
||||
import space.kscience.visionforge.html.toMeta
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
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:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-gdml:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-gdml:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-gdml:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-gdml:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -6,7 +6,7 @@ Common visionforge jupyter module
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-jupyter:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-jupyter:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-jupyter:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-jupyter:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -8,10 +8,10 @@ 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.visionforge.JsVisionClient
|
||||
import space.kscience.visionforge.renderAllVisions
|
||||
import space.kscience.visionforge.renderAllVisionsById
|
||||
import space.kscience.visionforge.renderAllVisionsIn
|
||||
import space.kscience.visionforge.html.JsVisionClient
|
||||
import space.kscience.visionforge.html.renderAllVisions
|
||||
import space.kscience.visionforge.html.renderAllVisionsById
|
||||
import space.kscience.visionforge.html.renderAllVisionsIn
|
||||
|
||||
@JsExport
|
||||
public class VFNotebookClient : AbstractPlugin() {
|
||||
|
@ -1,9 +1,9 @@
|
||||
package space.kscience.visionforge.gdml.jupyter
|
||||
|
||||
import space.kscience.visionforge.html.runVisionClient
|
||||
import space.kscience.visionforge.jupyter.VFNotebookClient
|
||||
import space.kscience.visionforge.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.runVisionClient
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.tables.TableVisionJsPlugin
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-markdown:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-markdown:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-markdown:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-markdown:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -13,9 +13,13 @@ 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.*
|
||||
import space.kscience.visionforge.Vision
|
||||
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.GFM_FORMAT
|
||||
import space.kscience.visionforge.useProperty
|
||||
|
||||
public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||
@ -27,7 +31,7 @@ public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
else -> ElementVisionRenderer.ZERO_RATING
|
||||
}
|
||||
|
||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element,name: Name, vision: Vision, meta: Meta) {
|
||||
require(vision is VisionOfMarkup) { "The vision is not a markup vision" }
|
||||
val div = document.createElement("div")
|
||||
val flavour = when (vision.format) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-plotly:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-plotly:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-plotly:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-plotly:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -10,7 +10,10 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.plotly.PlotlyConfig
|
||||
import space.kscience.plotly.plot
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionPlugin
|
||||
import space.kscience.visionforge.html.ElementVisionRenderer
|
||||
import space.kscience.visionforge.html.JsVisionClient
|
||||
|
||||
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||
@ -24,7 +27,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
else -> ElementVisionRenderer.ZERO_RATING
|
||||
}
|
||||
|
||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
||||
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
||||
val config = PlotlyConfig.read(meta)
|
||||
element.plot(config, plot)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-server:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-server:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-server:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-server:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-solid:0.3.0-rc`.
|
||||
The Maven coordinates of this project are `space.kscience:visionforge-solid:0.4.0-dev-3`.
|
||||
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
@ -16,6 +16,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:visionforge-solid:0.3.0-rc")
|
||||
implementation("space.kscience:visionforge-solid:0.4.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
@ -747,6 +747,7 @@ 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 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 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 setIgnore (Lspace/kscience/visionforge/Vision;Ljava/lang/Boolean;)V
|
||||
public static final fun setLayer (Lspace/kscience/visionforge/solid/Solid;I)V
|
||||
@ -802,8 +803,10 @@ public final class space/kscience/visionforge/solid/SolidMaterial : space/kscien
|
||||
public final fun getEmissiveColor ()Lspace/kscience/visionforge/solid/ColorAccessor;
|
||||
public final fun getOpacity ()F
|
||||
public final fun getSpecularColor ()Lspace/kscience/visionforge/solid/ColorAccessor;
|
||||
public final fun getType ()Ljava/lang/String;
|
||||
public final fun getWireframe ()Z
|
||||
public final fun setOpacity (F)V
|
||||
public final fun setType (Ljava/lang/String;)V
|
||||
public final fun setWireframe (Z)V
|
||||
}
|
||||
|
||||
@ -1087,23 +1090,6 @@ 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 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 static final field Companion Lspace/kscience/visionforge/solid/specifications/CameraScheme$Companion;
|
||||
public static final field FAR_CLIP D
|
||||
@ -1138,15 +1124,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 static final field Companion Lspace/kscience/visionforge/solid/specifications/Canvas3DOptions$Companion;
|
||||
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 getCanvasName ()Ljava/lang/String;
|
||||
public final fun getClipping ()Lspace/kscience/visionforge/solid/specifications/PointScheme;
|
||||
public final fun getControls ()Lspace/kscience/visionforge/solid/specifications/Canvas3DUIScheme;
|
||||
public final fun getLayers ()Ljava/util/List;
|
||||
public final fun getOnSelect ()Lkotlin/jvm/functions/Function1;
|
||||
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 setCanvasName (Ljava/lang/String;)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 setLayers (Ljava/util/List;)V
|
||||
@ -1171,6 +1157,7 @@ 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 fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
|
||||
}
|
||||
|
||||
public final class space/kscience/visionforge/solid/specifications/CanvasSize : space/kscience/dataforge/meta/Scheme {
|
||||
|
@ -8,6 +8,7 @@ kscience {
|
||||
jvm()
|
||||
js()
|
||||
native()
|
||||
// wasm()
|
||||
useSerialization {
|
||||
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