numass-framework/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt

149 lines
4.4 KiB
Kotlin
Raw Normal View History

2017-05-26 22:33:56 +03:00
package inr.numass.control
2017-06-08 08:19:08 +03:00
import hep.dataforge.kodex.KMetaBuilder
2017-10-13 10:04:03 +03:00
import hep.dataforge.kodex.fx.plots.PlotContainer
2017-10-11 21:55:48 +03:00
import hep.dataforge.plots.Plot
2017-06-08 08:19:08 +03:00
import hep.dataforge.plots.PlotFrame
import hep.dataforge.plots.jfreechart.JFreeChartFrame
2017-05-26 22:33:56 +03:00
import hep.dataforge.values.Value
import javafx.beans.value.ObservableValue
import javafx.event.EventTarget
2017-05-27 11:50:11 +03:00
import javafx.geometry.Orientation
2017-06-03 21:05:01 +03:00
import javafx.scene.Node
2017-06-08 08:19:08 +03:00
import javafx.scene.layout.BorderPane
2017-05-26 22:33:56 +03:00
import javafx.scene.paint.Color
import javafx.scene.paint.Paint
import javafx.scene.shape.Circle
import javafx.scene.shape.StrokeType
2017-06-04 22:42:47 +03:00
import org.controlsfx.control.ToggleSwitch
2017-05-26 22:33:56 +03:00
import tornadofx.*
2017-06-08 08:19:08 +03:00
import java.util.*
2017-05-26 22:33:56 +03:00
/**
* A pin like indicator fx node
*/
class Indicator(radius: Double = 10.0) : Circle(radius, Color.GRAY) {
private var binding: ObservableValue<*>? = null;
init {
stroke = Color.BLACK;
strokeType = StrokeType.INSIDE;
}
/**
* bind this indicator color to given observable
*/
fun <T> bind(observable: ObservableValue<T>, transform: (T) -> Paint) {
if (binding != null) {
throw RuntimeException("Indicator already bound");
} else {
binding = observable;
2017-05-27 11:50:11 +03:00
fill = transform(observable.value)
observable.addListener { _, _, value ->
fill = transform(value);
}
2017-05-26 22:33:56 +03:00
}
}
/**
* bind indicator to the boolean value using default colours
*/
2017-05-28 16:47:11 +03:00
fun bind(booleanValue: ObservableValue<Boolean?>) {
2017-05-26 22:33:56 +03:00
bind(booleanValue) {
2017-05-28 16:47:11 +03:00
if (it == null) {
Color.GRAY
} else if (it) {
2017-05-26 22:33:56 +03:00
Color.GREEN;
} else {
Color.RED;
}
}
}
fun unbind() {
this.binding = null;
neutralize();
}
/**
* return indicator to the neutral state but do not unbind
*/
fun neutralize() {
fill = Color.GRAY;
}
}
fun EventTarget.indicator(radius: Double = 10.0, op: (Indicator.() -> Unit)? = null) = opcr(this, Indicator(radius), op)
fun Indicator.bind(connection: DeviceViewConnection<*>, state: String, transform: ((Value) -> Paint)? = null) {
tooltip(state)
if (transform != null) {
bind(connection.getStateBinding(state), transform);
} else {
bind(connection.getStateBinding(state)) {
if (it.isNull) {
Color.GRAY
} else if (it.booleanValue()) {
Color.GREEN;
} else {
Color.RED;
}
}
}
2017-05-27 11:50:11 +03:00
}
/**
* State name + indicator
*/
2017-06-03 21:05:01 +03:00
fun EventTarget.deviceStateIndicator(connection: DeviceViewConnection<*>, state: String, showName: Boolean = true, transform: ((Value) -> Paint)? = null) {
2017-05-27 11:50:11 +03:00
if (connection.device.hasState(state)) {
2017-06-03 21:05:01 +03:00
if (showName) {
text("${state.toUpperCase()}: ")
}
2017-05-27 11:50:11 +03:00
indicator {
bind(connection, state, transform);
}
separator(Orientation.VERTICAL)
2017-06-04 22:42:47 +03:00
} else {
throw RuntimeException("Device does not support state $state");
2017-05-27 11:50:11 +03:00
}
2017-05-31 16:53:51 +03:00
}
2017-06-01 16:58:38 +03:00
2017-06-03 21:05:01 +03:00
/**
* A togglebutton + indicator for boolean state
*/
fun Node.deviceStateToggle(connection: DeviceViewConnection<*>, state: String, title: String = state) {
if (connection.device.hasState(state)) {
togglebutton(title) {
isSelected = false
selectedProperty().addListener { observable, oldValue, newValue ->
2017-06-04 22:42:47 +03:00
if (oldValue != newValue) {
connection.device.setState(state, newValue).thenAccept {
2017-06-03 21:05:01 +03:00
isSelected = it.booleanValue()
}
}
}
}
deviceStateIndicator(connection, state, false)
2017-06-04 22:42:47 +03:00
} else {
throw RuntimeException("Device does not support state $state");
2017-06-03 21:05:01 +03:00
}
}
2017-06-04 22:42:47 +03:00
fun EventTarget.switch(text: String = "", op: (ToggleSwitch.() -> Unit)? = null): ToggleSwitch {
val switch = ToggleSwitch(text)
return opcr(this, switch, op)
2017-06-08 08:19:08 +03:00
}
/**
2017-10-19 10:31:11 +03:00
* Add frame
2017-06-08 08:19:08 +03:00
*/
2017-10-11 21:55:48 +03:00
fun BorderPane.plot(plottables: Iterable<Plot> = Collections.emptyList(), metaTransform: (KMetaBuilder.() -> Unit)? = null): PlotFrame {
2017-06-08 08:19:08 +03:00
val meta = KMetaBuilder("plotFrame");
metaTransform?.invoke(meta)
val plot = JFreeChartFrame(meta)
plot.addAll(plottables)
2017-10-13 10:04:03 +03:00
center = PlotContainer(plot).root
2017-06-08 08:19:08 +03:00
return plot;
2017-06-04 22:42:47 +03:00
}