sclass JTargetAndActualSlider extends MetaWithChangeListeners is Swingable { new TargetAndActual data; settableWithVar bool sliderEnabled = true; settableWithVar double min; settableWithVar double max = 100; settableWithVar int decimalsToShow = 1; settableWithVar int widthOfNumbers = 50; transient JColorBar bar; transient JSlider slider; transient JLabel lblActual, lblTarget; *() {} *(TargetAndActual *data) {} double value() { ret unnull(data.value()); } double target() { ret unnull(data.target()); } cachedVisualize { bar = swing(-> new JColorBar().max(max)); slider = jLiveValueSlider_double_bothWays(min, max, data.varTarget()); lblActual = jlabel(); lblTarget = jlabel(); data.varActual().onChangeAndNow(-> { bar.setValue(value()); lblActual?.setText(renderValue(value()); }); data.varTarget().onChangeAndNow(-> slider.setValue(target()); lblTarget.setValue(target()); }); varSliderEnabled().onChangeAndNow(-> setEnabled(slider, sliderEnabled)); ret vstackWithSpacing( centerAndEastWithMargin(bar, jMinWidth(widthOfNumbers, lblActual)), centerAndEastWithMargin(slider, jMinWidth(widthOfNumbers, lblTarget))); } swappable S renderValue(double value) { ret formatDoubleX(value, decimalsToShow); } }