Move all-things to Compose

This commit is contained in:
Alexander Nozik 2024-05-11 17:56:28 +03:00
parent 381da970bf
commit 24b6856f15
7 changed files with 146 additions and 161 deletions

View File

@ -3,7 +3,6 @@ import space.kscience.gradle.useSPCTeam
plugins { plugins {
id("space.kscience.gradle.project") id("space.kscience.gradle.project")
alias(libs.plugins.versions)
} }
allprojects { allprojects {

View File

@ -35,7 +35,7 @@ public class VirtualLimitSwitch(
public val lockedState: DeviceState<Boolean>, public val lockedState: DeviceState<Boolean>,
) : DeviceBySpec<LimitSwitch>(LimitSwitch, context), LimitSwitch { ) : DeviceBySpec<LimitSwitch>(LimitSwitch, context), LimitSwitch {
init { override suspend fun onStart() {
lockedState.valueFlow.onEach { lockedState.valueFlow.onEach {
propertyChanged(LimitSwitch.locked, it) propertyChanged(LimitSwitch.locked, it)
}.launchIn(this) }.launchIn(this)

View File

@ -1,7 +1,6 @@
plugins { plugins {
kotlin("jvm") kotlin("jvm")
id("org.openjfx.javafxplugin") version "0.0.13" alias(spclibs.plugins.compose)
application
} }
@ -20,28 +19,46 @@ dependencies {
implementation(projects.controlsOpcua) implementation(projects.controlsOpcua)
implementation(spclibs.ktor.client.cio) implementation(spclibs.ktor.client.cio)
implementation(libs.tornadofx)
implementation(libs.plotlykt.server) implementation(libs.plotlykt.server)
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6") // implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
implementation(compose.runtime)
implementation(compose.desktop.currentOs)
implementation(compose.material3)
// implementation("org.pushing-pixels:aurora-window:1.3.0")
// implementation("org.pushing-pixels:aurora-component:1.3.0")
// implementation("org.pushing-pixels:aurora-theming:1.3.0")
implementation(spclibs.logback.classic) implementation(spclibs.logback.classic)
} }
kotlin{ kotlin{
jvmToolchain(11) jvmToolchain(17)
} compilerOptions {
freeCompilerArgs.addAll("-Xjvm-default=all", "-Xopt-in=kotlin.RequiresOptIn")
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + listOf("-Xjvm-default=all", "-Xopt-in=kotlin.RequiresOptIn")
} }
} }
javafx { compose{
version = "17" desktop{
modules("javafx.controls")
}
application{ application{
mainClass.set("space.kscience.controls.demo.DemoControllerViewKt") mainClass = "space.kscience.controls.demo.DemoControllerViewKt"
} }
}
}
//
//
//tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
// kotlinOptions {
// freeCompilerArgs = freeCompilerArgs + listOf("-Xjvm-default=all", "-Xopt-in=kotlin.RequiresOptIn")
// }
//}
//
//javafx {
// version = "17"
// modules("javafx.controls")
//}
//
//application {
// mainClass.set("space.kscience.controls.demo.DemoControllerViewKt")
//}

View File

@ -1,14 +1,19 @@
package space.kscience.controls.demo package space.kscience.controls.demo
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import io.ktor.server.engine.ApplicationEngine import io.ktor.server.engine.ApplicationEngine
import javafx.scene.Parent import kotlinx.coroutines.Job
import javafx.scene.control.Slider
import javafx.scene.layout.Priority
import javafx.stage.Stage
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.eclipse.milo.opcua.sdk.server.OpcUaServer import org.eclipse.milo.opcua.sdk.server.OpcUaServer
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText
@ -17,9 +22,6 @@ import space.kscience.controls.api.GetDescriptionMessage
import space.kscience.controls.api.PropertyChangedMessage import space.kscience.controls.api.PropertyChangedMessage
import space.kscience.controls.client.launchMagixService import space.kscience.controls.client.launchMagixService
import space.kscience.controls.client.magixFormat import space.kscience.controls.client.magixFormat
import space.kscience.controls.demo.DemoDevice.Companion.cosScale
import space.kscience.controls.demo.DemoDevice.Companion.sinScale
import space.kscience.controls.demo.DemoDevice.Companion.timeScale
import space.kscience.controls.manager.DeviceManager import space.kscience.controls.manager.DeviceManager
import space.kscience.controls.manager.install import space.kscience.controls.manager.install
import space.kscience.controls.opcua.server.OpcUaServer import space.kscience.controls.opcua.server.OpcUaServer
@ -35,16 +37,15 @@ import space.kscience.magix.rsocket.rSocketWithWebSockets
import space.kscience.magix.server.RSocketMagixFlowPlugin import space.kscience.magix.server.RSocketMagixFlowPlugin
import space.kscience.magix.server.startMagixServer import space.kscience.magix.server.startMagixServer
import space.kscince.magix.zmq.ZmqMagixFlowPlugin import space.kscince.magix.zmq.ZmqMagixFlowPlugin
import tornadofx.*
import java.awt.Desktop import java.awt.Desktop
import java.net.URI import java.net.URI
class DemoController : Controller(), ContextAware { class DemoController : ContextAware {
var device: DemoDevice? = null var device: DemoDevice? = null
var magixServer: ApplicationEngine? = null var magixServer: ApplicationEngine? = null
var visualizer: ApplicationEngine? = null var visualizer: ApplicationEngine? = null
var opcUaServer: OpcUaServer = OpcUaServer { val opcUaServer: OpcUaServer = OpcUaServer {
setApplicationName(LocalizedText.english("space.kscience.controls.opcua")) setApplicationName(LocalizedText.english("space.kscience.controls.opcua"))
endpoint { endpoint {
@ -60,8 +61,7 @@ class DemoController : Controller(), ContextAware {
private val deviceManager = context.request(DeviceManager) private val deviceManager = context.request(DeviceManager)
fun init() { fun start(): Job = context.launch {
context.launch {
device = deviceManager.install("demo", DemoDevice) device = deviceManager.install("demo", DemoDevice)
//starting magix event loop //starting magix event loop
magixServer = startMagixServer( magixServer = startMagixServer(
@ -90,9 +90,8 @@ class DemoController : Controller(), ContextAware {
listenerEndpoint.send(DeviceManager.magixFormat, GetDescriptionMessage(), "listener", "controls-kt") listenerEndpoint.send(DeviceManager.magixFormat, GetDescriptionMessage(), "listener", "controls-kt")
} }
}
suspend fun shutdown() { fun shutdown(): Job = context.launch {
logger.info { "Shutting down..." } logger.info { "Shutting down..." }
opcUaServer.shutdown() opcUaServer.shutdown()
logger.info { "OpcUa server stopped" } logger.info { "OpcUa server stopped" }
@ -102,92 +101,82 @@ class DemoController : Controller(), ContextAware {
logger.info { "Magix server stopped" } logger.info { "Magix server stopped" }
device?.stop() device?.stop()
logger.info { "Device server stopped" } logger.info { "Device server stopped" }
context.close()
} }
} }
@Composable
fun DemoControls(controller: DemoController) {
var timeScale by remember { mutableStateOf(5000f) }
var xScale by remember { mutableStateOf(1f) }
var yScale by remember { mutableStateOf(1f) }
class DemoControllerView : View(title = " Demo controller remote") { Surface(Modifier.padding(5.dp)) {
private val controller: DemoController by inject() Column {
private var timeScaleSlider: Slider by singleAssign() Row(Modifier.fillMaxWidth()) {
private var xScaleSlider: Slider by singleAssign() Text("Time Scale", modifier = Modifier.align(Alignment.CenterVertically).width(100.dp))
private var yScaleSlider: Slider by singleAssign() TextField(String.format("%.2f", timeScale),{}, enabled = false, modifier = Modifier.align(Alignment.CenterVertically).width(100.dp))
Slider(timeScale, onValueChange = { timeScale = it }, steps = 20, valueRange = 1000f..5000f)
override val root: Parent = vbox {
hbox {
label("Time scale")
pane {
hgrow = Priority.ALWAYS
} }
timeScaleSlider = slider(1000..10000, 5000) { Row(Modifier.fillMaxWidth()) {
isShowTickLabels = true Text("X scale", modifier = Modifier.align(Alignment.CenterVertically).width(100.dp))
isShowTickMarks = true TextField(String.format("%.2f", xScale),{}, enabled = false, modifier = Modifier.align(Alignment.CenterVertically).width(100.dp))
Slider(xScale, onValueChange = { xScale = it }, steps = 20, valueRange = 0.1f..2.0f)
} }
Row(Modifier.fillMaxWidth()) {
Text("Y scale", modifier = Modifier.align(Alignment.CenterVertically).width(100.dp))
TextField(String.format("%.2f", yScale),{}, enabled = false, modifier = Modifier.align(Alignment.CenterVertically).width(100.dp))
Slider(yScale, onValueChange = { yScale = it }, steps = 20, valueRange = 0.1f..2.0f)
} }
hbox { Row(Modifier.fillMaxWidth()) {
label("X scale") Button(
pane { onClick = {
hgrow = Priority.ALWAYS
}
xScaleSlider = slider(0.1..2.0, 1.0) {
isShowTickLabels = true
isShowTickMarks = true
}
}
hbox {
label("Y scale")
pane {
hgrow = Priority.ALWAYS
}
yScaleSlider = slider(0.1..2.0, 1.0) {
isShowTickLabels = true
isShowTickMarks = true
}
}
button("Submit") {
useMaxWidth = true
action {
controller.device?.run { controller.device?.run {
launch { launch {
write(timeScale, timeScaleSlider.value) write(DemoDevice.timeScale, timeScale.toDouble())
write(sinScale, xScaleSlider.value) write(DemoDevice.sinScale, xScale.toDouble())
write(cosScale, yScaleSlider.value) write(DemoDevice.cosScale, yScale.toDouble())
} }
} }
},
Modifier.fillMaxWidth()
) {
Text("Submit")
} }
} }
button("Show plots") { Row(Modifier.fillMaxWidth()) {
useMaxWidth = true Button(
action { onClick = {
controller.visualizer?.run { controller.visualizer?.run {
val host = "localhost"//environment.connectors.first().host val host = "localhost"//environment.connectors.first().host
val port = environment.connectors.first().port val port = environment.connectors.first().port
val uri = URI("http", null, host, port, "/", null, null) val uri = URI("http", null, host, port, "/", null, null)
Desktop.getDesktop().browse(uri) Desktop.getDesktop().browse(uri)
} }
} },
Modifier.fillMaxWidth()
) {
Text("Show plots")
} }
} }
} }
}
class DemoControllerApp : App(DemoControllerView::class) {
private val controller: DemoController by inject()
override fun start(stage: Stage) {
super.start(stage)
controller.init()
} }
override fun stop() {
runBlocking { fun main() = application {
val controller = remember { DemoController().apply { start() } }
Window(
title = "All things control",
onCloseRequest = {
controller.shutdown() controller.shutdown()
} exitApplication()
super.stop() },
state = rememberWindowState(width = 400.dp, height = 300.dp)
) {
MaterialTheme {
DemoControls(controller)
} }
} }
fun main() {
launch<DemoControllerApp>()
} }

View File

@ -1,10 +0,0 @@
package space.kscience.controls.demo
//import com.github.ricky12awesome.jss.encodeToSchema
//import com.github.ricky12awesome.jss.globalJson
//import space.kscience.controls.api.DeviceMessage
//fun main() {
// val schema = globalJson.encodeToSchema(DeviceMessage.serializer(), generateDefinitions = false)
// println(schema)
//}

View File

@ -1,19 +1,11 @@
plugins { plugins {
id("space.kscience.gradle.jvm") id("space.kscience.gradle.jvm")
application alias(spclibs.plugins.compose)
id("org.openjfx.javafxplugin")
} }
//TODO to be moved to a separate project //application{
// mainClass.set("ru.mipt.npm.devices.pimotionmaster.PiMotionMasterAppKt")
javafx { //}
version = "17"
modules = listOf("javafx.controls")
}
application{
mainClass.set("ru.mipt.npm.devices.pimotionmaster.PiMotionMasterAppKt")
}
kotlin{ kotlin{
explicitApi = null explicitApi = null
@ -25,5 +17,4 @@ val dataforgeVersion: String by extra
dependencies { dependencies {
implementation(project(":controls-ports-ktor")) implementation(project(":controls-ports-ktor"))
implementation(projects.controlsMagix) implementation(projects.controlsMagix)
implementation(libs.tornadofx)
} }

View File

@ -18,7 +18,6 @@ pluginManagement {
id("space.kscience.gradle.mpp") version toolsVersion id("space.kscience.gradle.mpp") version toolsVersion
id("space.kscience.gradle.jvm") version toolsVersion id("space.kscience.gradle.jvm") version toolsVersion
id("space.kscience.gradle.js") version toolsVersion id("space.kscience.gradle.js") version toolsVersion
id("org.openjfx.javafxplugin") version "0.0.13"
} }
} }