From da0f4c0ff04a516221d518aeb44842043ea31902 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 31 Dec 2023 18:09:36 +0300 Subject: [PATCH] Optimize UI --- demo/gdml/build.gradle.kts | 21 ++++++++++---- .../visionforge/gdml/demo/FileDrop.kt | 5 ++-- .../visionforge/gdml/demo/GDMLAppComponent.kt | 4 +-- .../src/jsMain/kotlin/JsPlaygroundApp.kt | 3 +- .../kotlin/ru/mipt/npm/sat/satServer.kt | 9 +++++- .../visionforge/solid/demo/VariableBox.kt | 2 +- .../compose/ComposeVisionRenderer.kt | 28 +++++++++++++++++++ .../visionforge/compose/PropertyEditor.kt | 6 ++-- .../space/kscience/visionforge/Vision.kt | 4 +-- .../visionforge/html/VisionTagConsumer.kt | 16 ++++++----- .../space/kscience/visionforge/useProperty.kt | 6 ++-- .../solid/three/ThreeCompositeFactory.kt | 2 +- .../visionforge/solid/three/ThreePlugin.kt | 17 +++++------ .../build.gradle.kts | 22 +++++++++++---- 14 files changed, 101 insertions(+), 44 deletions(-) create mode 100644 visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/ComposeVisionRenderer.kt diff --git a/demo/gdml/build.gradle.kts b/demo/gdml/build.gradle.kts index f715262b..03093d23 100644 --- a/demo/gdml/build.gradle.kts +++ b/demo/gdml/build.gradle.kts @@ -1,27 +1,36 @@ plugins { id("space.kscience.gradle.mpp") + alias(spclibs.plugins.compose) } group = "demo" kscience { - jvm() +// jvm() js { browser { binaries.executable() + commonWebpackConfig{ + cssSupport{ + enabled = true + } + scssSupport{ + enabled = true + } + sourceMaps = true + } } } dependencies { implementation(projects.visionforgeSolid) implementation(projects.visionforgeGdml) } - jvmMain { -// implementation(project(":visionforge-fx")) - implementation(spclibs.logback.classic) - } +// jvmMain { +//// implementation(project(":visionforge-fx")) +// implementation(spclibs.logback.classic) +// } jsMain { implementation(projects.visionforgeThreejs) - implementation(npm("react-file-drop", "3.0.6")) } } diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/FileDrop.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/FileDrop.kt index d26ea42d..3fdedb64 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/FileDrop.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/FileDrop.kt @@ -3,12 +3,12 @@ package space.kscience.visionforge.gdml.demo import androidx.compose.runtime.* +import app.softwork.bootstrapcompose.Container import app.softwork.bootstrapcompose.Icon import org.jetbrains.compose.web.ExperimentalComposeWebApi import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.name import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Input import org.jetbrains.compose.web.dom.Text import org.w3c.files.FileList @@ -22,7 +22,7 @@ fun FileDrop( ) { var dragOver by remember { mutableStateOf(false) } - Div({ + Container(attrs = { id("dropzone") style { border( @@ -69,7 +69,6 @@ fun FileDrop( } } }) { - Icon("cloud-upload"){ classes("dropzone-icon") } Text(title) Input(type = InputType.File, attrs = { diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt index 65a702e4..c3016145 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.* import kotlinx.browser.window import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.Div -import org.jetbrains.compose.web.dom.H2 +import org.jetbrains.compose.web.dom.P import org.jetbrains.compose.web.dom.Text import org.w3c.files.File import org.w3c.files.FileReader @@ -66,7 +66,7 @@ fun GDMLApp(solids: Solids, initialVision: Solid?, selected: Name? = null) { }) { ThreeView(solids, vision, selected) { Tab("Load") { - H2 { + P { Text("Drag and drop .gdml or .json VisionForge files here") } FileDrop("(drag file here)") { files -> diff --git a/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt b/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt index a612ab3e..3e53e866 100644 --- a/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt +++ b/demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt @@ -47,8 +47,7 @@ private class JsPlaygroundApp : Application { width(100.vw) } }) { - Tabs { - active = "gravity" + Tabs("gravity") { Tab("gravity") { GravityDemo(solids, client) } diff --git a/demo/sat-demo/src/jvmMain/kotlin/ru/mipt/npm/sat/satServer.kt b/demo/sat-demo/src/jvmMain/kotlin/ru/mipt/npm/sat/satServer.kt index 9f2f7e59..af4fbca4 100644 --- a/demo/sat-demo/src/jvmMain/kotlin/ru/mipt/npm/sat/satServer.kt +++ b/demo/sat-demo/src/jvmMain/kotlin/ru/mipt/npm/sat/satServer.kt @@ -14,10 +14,12 @@ import space.kscience.dataforge.meta.Null import space.kscience.dataforge.names.Name import space.kscience.visionforge.Colors import space.kscience.visionforge.html.VisionPage +import space.kscience.visionforge.html.meta import space.kscience.visionforge.server.close import space.kscience.visionforge.server.openInBrowser import space.kscience.visionforge.server.visionPage import space.kscience.visionforge.solid.* +import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.three.threeJsHeader import kotlin.random.Random @@ -47,7 +49,12 @@ fun main() { ) { div("flex-column") { h1 { +"Satellite detector demo" } - vision { sat } + vision { + meta(Canvas3DOptions { + controls.enabled = false + }) + sat + } } } diff --git a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt index 701df81b..5787b6b3 100644 --- a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt +++ b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt @@ -46,7 +46,7 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision mesh.scale.z = properties.getValue(VALUE)?.number?.toDouble() ?: 1.0 //add listener to object properties - onPropertyChange { name -> + onPropertyChange(three.context) { name -> when { name == VALUE -> { val value = properties.getValue(VALUE)?.int ?: 0 diff --git a/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/ComposeVisionRenderer.kt b/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/ComposeVisionRenderer.kt new file mode 100644 index 00000000..15eb93c1 --- /dev/null +++ b/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/ComposeVisionRenderer.kt @@ -0,0 +1,28 @@ +package space.kscience.visionforge.compose + +import androidx.compose.runtime.Composable +import org.jetbrains.compose.web.css.Style +import org.jetbrains.compose.web.dom.DOMScope +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 { + + @Composable + public fun DOMScope.render(client: VisionClient, name: Name, vision: Vision, meta: Meta) + + override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) { + renderComposable(element) { + Style(VisionForgeStyles) + render(client, name, vision, meta) + } + } +} \ No newline at end of file diff --git a/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/PropertyEditor.kt b/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/PropertyEditor.kt index cff16298..81d0b944 100644 --- a/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/PropertyEditor.kt +++ b/visionforge-compose-html/src/jsMain/kotlin/space/kscience/visionforge/compose/PropertyEditor.kt @@ -28,9 +28,9 @@ import space.kscience.visionforge.hidden * 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 data object Defined : EditorPropertyState() + public data class Default(public val source: String = "unknown") : EditorPropertyState() + public data object Undefined : EditorPropertyState() } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt index ece71edd..886a1574 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt @@ -79,8 +79,8 @@ public var Vision.visible: Boolean? * Subscribe on property updates. The subscription is bound to the given scope and canceled when the scope is canceled */ public fun Vision.onPropertyChange( - scope: CoroutineScope? = manager?.context, + scope: CoroutineScope, callback: suspend (Name) -> Unit, ): Job = properties.changes.onEach { callback(it) -}.launchIn(scope ?: error("Orphan Vision can't observe properties")) \ No newline at end of file +}.launchIn(scope) \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt index 99a8ea0d..19cfc80a 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt @@ -4,10 +4,7 @@ import kotlinx.html.* import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.ContextAware import space.kscience.dataforge.context.PluginFactory -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MetaSerializer -import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.meta.isEmpty +import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.asName @@ -46,9 +43,14 @@ public class VisionOutput @PublishedApi internal constructor(override val contex newContext.visionManager } - public inline fun meta(block: MutableMeta.() -> Unit) { - this.meta = Meta(block) - } +} + +public inline fun VisionOutput.meta(block: MutableMeta.() -> Unit) { + this.meta = Meta(block) +} + +public fun VisionOutput.meta(metaRepr: MetaRepr) { + this.meta = metaRepr.toMeta() } /** diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt index 8ffb272a..c396714b 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/useProperty.kt @@ -19,7 +19,7 @@ public fun Vision.useProperty( propertyName: Name, inherit: Boolean? = null, includeStyles: Boolean? = null, - scope: CoroutineScope? = manager?.context, + scope: CoroutineScope = manager?.context ?: error("Orphan Vision can't observe properties"), callback: (Meta) -> Unit, ): Job { //Pass initial value. @@ -28,14 +28,14 @@ public fun Vision.useProperty( if (name.startsWith(propertyName)) { callback(properties.get(propertyName, inherit, includeStyles)) } - }.launchIn(scope ?: error("Orphan Vision can't observe properties")) + }.launchIn(scope) } public fun Vision.useProperty( propertyName: String, inherit: Boolean? = null, includeStyles: Boolean? = null, - scope: CoroutineScope? = manager?.context, + scope: CoroutineScope = manager?.context ?: error("Orphan Vision can't observe properties"), callback: (Meta) -> Unit, ): Job = useProperty(propertyName.parseAsName(), inherit, includeStyles, scope, callback) diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt index e6e9641c..1117ba37 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreeCompositeFactory.kt @@ -52,7 +52,7 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory applyProperties(vision) if (observe) { - vision.onPropertyChange { name -> + vision.onPropertyChange(three.context) { name -> when { //name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) name.startsWith(EDGES_KEY) -> applyEdges(vision) diff --git a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt index e3a0f20b..026c9b18 100644 --- a/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt +++ b/visionforge-threejs/src/jsMain/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt @@ -1,14 +1,16 @@ package space.kscience.visionforge.solid.three +import androidx.compose.runtime.Composable import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import org.jetbrains.compose.web.renderComposable +import org.jetbrains.compose.web.dom.DOMScope import org.w3c.dom.Element import org.w3c.dom.HTMLElement import space.kscience.dataforge.context.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.names.* import space.kscience.visionforge.* +import space.kscience.visionforge.compose.ComposeVisionRenderer import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.three.compose.ThreeView @@ -21,7 +23,7 @@ import three.objects.Group as ThreeGroup /** * A plugin that handles Three Object3D representation of Visions. */ -public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { +public class ThreePlugin : AbstractPlugin(), ComposeVisionRenderer { override val tag: PluginTag get() = Companion.tag public val solids: Solids by require(Solids) @@ -75,7 +77,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { // disable tracking changes for statics group[token] = object3D } catch (ex: Throwable) { - logger.error(ex) { "Failed to render $child" } + logger.error(ex) { "Failed to render vision with token $token and type ${child::class}" } } } } @@ -115,7 +117,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { val object3D = buildObject3D(child) set(childName, object3D) } catch (ex: Throwable) { - logger.error(ex) { "Failed to render $child" } + logger.error(ex) { "Failed to render vision with name $childName" } } } }.launchIn(context) @@ -185,11 +187,10 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { render(vision) } - override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) { + @Composable + override fun DOMScope.render(client: VisionClient, name: Name, vision: Vision, meta: Meta) { require(vision is Solid) { "Expected Solid but found ${vision::class}" } - renderComposable(element) { - ThreeView(solids, vision, null, Canvas3DOptions.read(meta)) - } + ThreeView(solids, vision, null, Canvas3DOptions.read(meta)) } public companion object : PluginFactory { diff --git a/visionforge-threejs/visionforge-threejs-server/build.gradle.kts b/visionforge-threejs/visionforge-threejs-server/build.gradle.kts index f6c30385..df821866 100644 --- a/visionforge-threejs/visionforge-threejs-server/build.gradle.kts +++ b/visionforge-threejs/visionforge-threejs-server/build.gradle.kts @@ -6,21 +6,33 @@ plugins { val ktorVersion: String by rootProject.extra kscience { - fullStack("js/visionforge-three.js") + fullStack( + bundleName = "js/visionforge-three.js", + browserConfig = { + webpackTask { + cssSupport { + enabled = true + } + scssSupport { + enabled = true + } + } + } + ) commonMain { api(projects.visionforgeSolid) api(projects.visionforgeComposeHtml) } - jvmMain{ + jvmMain { api(projects.visionforgeServer) } - jsMain{ + jsMain { api(projects.visionforgeThreejs) - implementation(npm("file-saver","2.0.5")) + implementation(npm("file-saver", "2.0.5")) implementation(npm("@types/file-saver", "2.0.7")) - compileOnly(npm("webpack-bundle-analyzer","4.5.0")) + compileOnly(npm("webpack-bundle-analyzer", "4.5.0")) } } \ No newline at end of file