diff --git a/orx-gui/src/main/kotlin/Gui.kt b/orx-gui/src/main/kotlin/Gui.kt
index 3ecda134..fdbdb0ba 100644
--- a/orx-gui/src/main/kotlin/Gui.kt
+++ b/orx-gui/src/main/kotlin/Gui.kt
@@ -155,8 +155,7 @@ class GUI : Extension {
this.background = Color.RGBa(ColorRGBa.GRAY.copy(a = 0.99))
this.overflow = Overflow.Scroll
-
- /* 1) setup control style */
+ //
descendant(has type "colorpicker-button") {
this.width = 175.px
}
@@ -181,6 +180,12 @@ class GUI : Extension {
this.width = 175.px
this.height = 175.px
}
+
+ descendant(has type "sequence-editor") {
+ this.width = 175.px
+ this.height = 100.px
+ }
+ //
}
styleSheet(has class_ "randomize-strong") {
@@ -254,7 +259,7 @@ class GUI : Extension {
header.mouse.pressed.subscribe {
it.cancelPropagation()
}
- header.mouse.clicked.subscribe {
+ {
if (KeyModifier.CTRL in it.modifiers) {
collapsible.classes.remove(collapseClass)
@@ -279,7 +284,7 @@ class GUI : Extension {
}
}
}
- collapseBorder.mouse.pressed.subscribe {
+ {
it.cancelPropagation()
}
@@ -294,7 +299,7 @@ class GUI : Extension {
}
it.cancelPropagation()
}
- sidebar.mouse.scrolled.subscribe {
+ {
sidebarState().scrollTop = sidebar.scrollTop
}
if (sidebarState().collapsed) {
@@ -316,18 +321,19 @@ class GUI : Extension {
program.extend(panel)
}
+ /* 2) control creation. create control, set label, set range, setup event-handler, load values */
+ //
private fun Div.addControl(compartment: LabeledObject, parameter: Parameter): Element {
val obj = compartment.obj
return when (parameter.parameterType) {
- /* 2) control creation. create control, set label, set range, setup event-handler, load values */
ParameterType.Int -> {
slider {
label = parameter.label
range = Range(parameter.intRange!!.first.toDouble(), parameter.intRange!!.last.toDouble())
precision = 0
- events.valueChanged.subscribe {
+ {
setAndPersist(compartment.label, parameter.property as KMutableProperty1, obj, it.newValue.toInt())
(parameter.property as KMutableProperty1).set(obj, value.toInt())
onChangeListener?.invoke(parameter.property!!.name, it.newValue)
@@ -343,7 +349,7 @@ class GUI : Extension {
label = parameter.label
range = Range(parameter.doubleRange!!.start, parameter.doubleRange!!.endInclusive)
precision = parameter.precision!!
- events.valueChanged.subscribe {
+ {
setAndPersist(compartment.label, parameter.property as KMutableProperty1, obj, it.newValue)
onChangeListener?.invoke(parameter.property!!.name, it.newValue)
}
@@ -358,7 +364,7 @@ class GUI : Extension {
ParameterType.Action -> {
button {
label = parameter.label
- events.clicked.subscribe {
+ {
/* the `obj` we pass in here is the receiver */
parameter.function!!.call(obj)
onChangeListener?.invoke(parameter.function!!.name, null)
@@ -368,7 +374,7 @@ class GUI : Extension {
ParameterType.Boolean -> {
toggle {
label = parameter.label
- events.valueChanged.subscribe {
+ {
value = it.newValue
setAndPersist(compartment.label, parameter.property as KMutableProperty1, obj, it.newValue)
onChangeListener?.invoke(parameter.property!!.name, it.newValue)
@@ -382,7 +388,7 @@ class GUI : Extension {
ParameterType.Text -> {
textfield {
label = parameter.label
- events.valueChanged.subscribe {
+ {
setAndPersist(compartment.label, parameter.property as KMutableProperty1, obj, it.newValue)
onChangeListener?.invoke(parameter.property!!.name, it.newValue)
}
@@ -394,7 +400,7 @@ class GUI : Extension {
ParameterType.Color -> {
colorpickerButton {
label = parameter.label
- events.valueChanged.subscribe {
+ {
setAndPersist(
compartment.label,
parameter.property as KMutableProperty1,
@@ -423,7 +429,7 @@ class GUI : Extension {
showVector = parameter.showVector!!
invertY = parameter.invertY!!
- events.valueChanged.subscribe {
+ {
setAndPersist(
compartment.label,
parameter.property as KMutableProperty1,
@@ -434,8 +440,37 @@ class GUI : Extension {
}
}
}
+
+ ParameterType.DoubleList -> {
+ sequenceEditor {
+ range = parameter.doubleRange!!
+ label = parameter.label
+ minimumSequenceLength = parameter.sizeRange!!.start
+ maximumSequenceLength = parameter.sizeRange!!.endInclusive
+ precision = parameter.precision!!
+
+ events.valueChanged.listen {
+ setAndPersist(
+ compartment.label,
+ parameter.property as KMutableProperty1>,
+ obj,
+ it.newValue.toMutableList()
+ )
+ onChangeListener?.invoke(parameter.property!!.name, it.newValue)
+ }
+ getPersistedOrDefault(
+ compartment.label,
+ parameter.property as KMutableProperty1>,
+ obj
+ )?.let {
+ value = it
+ }
+ }
+ }
+
}
}
+ //
private val trackedObjects = mutableMapOf()
@@ -452,6 +487,7 @@ class GUI : Extension {
var booleanValue: Boolean? = null,
var colorValue: ColorRGBa? = null,
var vectorValue: Vector2? = null,
+ var doubleListValue: MutableList? = null,
var textValue: String? = null)
@@ -472,6 +508,7 @@ class GUI : Extension {
ParameterType.Text -> ParameterValue(textValue = k.property.qget(lo.obj) as String)
ParameterType.Boolean -> ParameterValue(booleanValue = k.property.qget(lo.obj) as Boolean)
ParameterType.XY -> ParameterValue(vectorValue = k.property.qget(lo.obj) as Vector2)
+ ParameterType.DoubleList -> ParameterValue(doubleListValue = k.property.qget(lo.obj) as MutableList)
})
})
}
@@ -509,6 +546,9 @@ class GUI : Extension {
ParameterType.XY -> parameterValue.vectorValue?.let {
parameter.property.qset(lo.obj, it)
}
+ ParameterType.DoubleList -> parameterValue.doubleListValue?.let {
+ parameter.property.qset(lo.obj, it)
+ }
ParameterType.Boolean -> parameterValue.booleanValue?.let {
parameter.property.qset(lo.obj, it)
}
@@ -538,11 +578,12 @@ class GUI : Extension {
ParameterType.Color -> {
(control as ColorpickerButton).color = (parameter.property as KMutableProperty1).get(labeledObject.obj)
}
-
ParameterType.XY -> {
(control as XYPad).value = (parameter.property as KMutableProperty1).get(labeledObject.obj)
}
-
+ ParameterType.DoubleList -> {
+ (control as SequenceEditor).value = (parameter.property as KMutableProperty1>).get(labeledObject.obj)
+ }
ParameterType.Boolean -> {
(control as Toggle).value = (parameter.property as KMutableProperty1).get(labeledObject.obj)
}
diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt
index db998aaf..6711e8ea 100644
--- a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt
+++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt
@@ -5,9 +5,17 @@ import org.openrndr.KeyModifier
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.Drawer
import org.openrndr.draw.LineCap
+import org.openrndr.draw.isolated
import org.openrndr.events.Event
import org.openrndr.math.Vector2
+import org.openrndr.math.map
+import org.openrndr.panel.style.Color
+import org.openrndr.panel.style.color
+import org.openrndr.panel.style.effectiveColor
import org.openrndr.panel.tools.Tooltip
+import org.openrndr.shape.Rectangle
+import org.openrndr.text.Cursor
+import org.openrndr.text.Writer
import kotlin.math.abs
import kotlin.math.round
import kotlin.math.roundToInt
@@ -15,13 +23,17 @@ import kotlin.math.roundToInt
class SequenceEditor : Element(ElementType("sequence-editor")) {
var value = mutableListOf(0.0)
+ var label = "sequence"
var precision = 2
var maximumSequenceLength = 16
var minimumSequenceLength = 1
+ var range: ClosedRange = -1.0..1.0
private var selectedIndex: Int? = null
private var tooltip: Tooltip? = null
+ private val footerHeight = 20.0
+
class ValueChangedEvent(val source: SequenceEditor,
val oldValue: List,
val newValue: List)
@@ -35,7 +47,7 @@ class SequenceEditor : Element(ElementType("sequence-editor")) {
init {
fun query(position: Vector2): Vector2 {
val x = (position.x - layout.screenX) / layout.screenWidth
- val y = 1.0 - ((position.y - layout.screenY) / (layout.screenHeight * 0.5))
+ val y = 1.0 - ((position.y - layout.screenY) / ((layout.screenHeight - footerHeight) * 0.5))
return Vector2(x, y)
}
@@ -68,7 +80,7 @@ class SequenceEditor : Element(ElementType("sequence-editor")) {
if (value.size < maximumSequenceLength) {
val q = query(it.position)
val oldValue = value.map { it }
- value.add(index.toInt(), q.y)
+ value.add(index.toInt(), q.y.map(-1.0, 1.0, range.start, range.endInclusive))
events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value))
}
}
@@ -108,7 +120,7 @@ class SequenceEditor : Element(ElementType("sequence-editor")) {
val readIndex = index.roundToInt() - 1
if (readIndex >= 0 && readIndex < value.size) {
val value = String.format("%.0${precision}f", value[readIndex])
- tooltip = Tooltip(this@SequenceEditor, it.position - Vector2(layout.screenX, layout.screenY), "index: ${index.roundToInt()}, $value")
+ tooltip = Tooltip(this@SequenceEditor, it.position - Vector2(layout.screenX, layout.screenY), "$value")
requestRedraw()
}
}
@@ -121,7 +133,7 @@ class SequenceEditor : Element(ElementType("sequence-editor")) {
val writeIndex = index - 1
if (writeIndex >= 0 && writeIndex < value.size) {
val oldValue = value.map { it }
- value[writeIndex] = q.y.coerceIn(-1.0, 1.0)
+ value[writeIndex] = q.y.coerceIn(-1.0, 1.0).map(-1.0, 1.0, range.start, range.endInclusive)
events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value))
}
requestRedraw()
@@ -130,21 +142,47 @@ class SequenceEditor : Element(ElementType("sequence-editor")) {
}
override fun draw(drawer: Drawer) {
- drawer.stroke = (ColorRGBa.BLACK.opacify(0.25))
- drawer.strokeWeight = (1.0)
- drawer.lineSegment(0.0, layout.screenHeight / 2.0, layout.screenWidth, layout.screenHeight / 2.0)
+ val controlArea = Rectangle(0.0, 0.0, layout.screenWidth, layout.screenHeight - footerHeight)
+
+ drawer.stroke = computedStyle.effectiveColor?.opacify(0.25)
+ drawer.strokeWeight = (1.0)
+
+
+ val zeroHeight = 0.0.map(range.start, range.endInclusive, -1.0, 1.0).coerceIn(-1.0, 1.0) * controlArea.height / -2.0
+ drawer.lineSegment(0.0, controlArea.height / 2.0 + zeroHeight, layout.screenWidth, controlArea.height / 2.0 + zeroHeight)
+
+ drawer.strokeWeight = 7.0
+ drawer.fill = computedStyle.effectiveColor
- drawer.strokeWeight = 1.0
- drawer.stroke = ColorRGBa.WHITE
for (i in value.indices) {
val dx = layout.screenWidth / (value.size + 1)
- val height = -value[i] * layout.screenHeight / 2.0
+ val height = -value[i].map(range.start, range.endInclusive, -1.0, 1.0).coerceIn(-1.0, 1.0) * controlArea.height / 2.0
val x = dx * (i + 1)
drawer.lineCap = LineCap.ROUND
- drawer.lineSegment(x, layout.screenHeight / 2.0, x, layout.screenHeight / 2.0 + height)
- drawer.circle(x, layout.screenHeight / 2.0 + height, 5.0)
+ drawer.stroke = computedStyle.effectiveColor
+ drawer.lineSegment(x, controlArea.height / 2.0 + zeroHeight, x, controlArea.height / 2.0 + height)
+
+ drawer.stroke = computedStyle.effectiveColor?.shade(1.1)
+ drawer.fill = ColorRGBa.PINK
+ drawer.circle(x, controlArea.height / 2.0 + height, 7.0)
}
+
+ drawer.isolated {
+ drawer.translate(0.0, controlArea.height)
+ drawer.fill = computedStyle.effectiveColor
+ (root() as? Body)?.controlManager?.fontManager?.let {
+ val font = it.font(computedStyle)
+ val writer = Writer(drawer)
+ drawer.fontMap = (font)
+ drawer.fill = computedStyle.effectiveColor
+ writer.cursor = Cursor(0.0, 4.0)
+ writer.box = Rectangle(0.0, 4.0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)
+ writer.newLine()
+ writer.text(label)
+ }
+ }
+
tooltip?.draw(drawer)
}
}
diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt
index 629b5ec1..b7ea7f7b 100644
--- a/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt
+++ b/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt
@@ -105,6 +105,10 @@ fun defaultStyles(
marginBottom = 15.px
marginLeft = 5.px
marginRight = 5.px
+ color = controlTextColor
+ and(has state "active") {
+ color = controlActiveColor
+ }
},
styleSheet(has type "colorpicker") {
@@ -116,6 +120,8 @@ fun defaultStyles(
marginRight = 5.px
},
+
+
styleSheet(has type "xy-pad") {
display = Display.BLOCK
background = Color.RGBa(ColorRGBa.GRAY)
diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt
index 9c5ec6b9..d33b6b3c 100644
--- a/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt
+++ b/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt
@@ -37,7 +37,8 @@ class Tooltip(val parent: Element, val position: Vector2, val message: String) {
drawer.translate(position)
drawer.translate(10.0, 0.0)
- drawer.stroke = null
+ drawer.strokeWeight = 0.5
+ drawer.stroke = ColorRGBa.WHITE.opacify(0.25)
drawer.fill = ColorRGBa.GRAY
drawer.rectangle(0.0, 0.0, maxX + 20.0, maxY)
drawer.fill = ColorRGBa.BLACK