Add tracking of orx-gui sidebar hide, collapse and scroll state
This commit is contained in:
@@ -18,14 +18,35 @@ import org.openrndr.panel.style.*
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.reflect.KMutableProperty1
|
import kotlin.reflect.KMutableProperty1
|
||||||
|
|
||||||
|
/** Dear contributor, just in case you are here looking to add a new parameter type.
|
||||||
|
There is a 6-step incantation to add a new parameter type
|
||||||
|
0) Add your parameter type to orx-parameters, follow the instructions provided there.
|
||||||
|
|
||||||
|
1) Setup a control style, very likely analogous to the styles already in place.
|
||||||
|
2) Add control creation code.
|
||||||
|
3) Add value serialization code, may need to update ParameterValue too.
|
||||||
|
4) Add value deserialization code.
|
||||||
|
5) Add value randomization code.
|
||||||
|
6) Add control update code.
|
||||||
|
|
||||||
|
You can use your editor's search functionality to jump to "1)", "2)".
|
||||||
|
*/
|
||||||
private data class LabeledObject(val label: String, val obj: Any)
|
private data class LabeledObject(val label: String, val obj: Any)
|
||||||
|
|
||||||
private class CompartmentState(var collapsed: Boolean = false, val parameterValues: MutableMap<String, Any> = mutableMapOf())
|
private class CompartmentState(var collapsed: Boolean = false, val parameterValues: MutableMap<String, Any> = mutableMapOf())
|
||||||
|
private class SidebarState(var hidden: Boolean = false, var collapsed: Boolean = false, var scrollTop: Double = 0.0)
|
||||||
private class TrackedObjectBinding(
|
private class TrackedObjectBinding(
|
||||||
val parameters: List<Parameter>,
|
val parameters: List<Parameter>,
|
||||||
val parameterControls: MutableMap<Parameter, Element> = mutableMapOf()
|
val parameterControls: MutableMap<Parameter, Element> = mutableMapOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
private val persistentCompartmentStates = mutableMapOf<Long, MutableMap<String, CompartmentState>>()
|
private val persistentCompartmentStates = mutableMapOf<Long, MutableMap<String, CompartmentState>>()
|
||||||
|
private val persistentSidebarStates = mutableMapOf<Long, SidebarState>()
|
||||||
|
|
||||||
|
private fun sidebarState(): SidebarState = persistentSidebarStates.getOrPut(Driver.instance.contextID) {
|
||||||
|
SidebarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun <T : Any> getPersistedOrDefault(compartmentLabel: String, property: KMutableProperty1<Any, T>, obj: Any): T? {
|
private fun <T : Any> getPersistedOrDefault(compartmentLabel: String, property: KMutableProperty1<Any, T>, obj: Any): T? {
|
||||||
val state = persistentCompartmentStates[Driver.instance.contextID]!![compartmentLabel]
|
val state = persistentCompartmentStates[Driver.instance.contextID]!![compartmentLabel]
|
||||||
@@ -60,6 +81,7 @@ class GUI : Extension {
|
|||||||
if (it.key == KEY_F11) {
|
if (it.key == KEY_F11) {
|
||||||
enabled = !enabled
|
enabled = !enabled
|
||||||
panel.enabled = enabled
|
panel.enabled = enabled
|
||||||
|
sidebarState().hidden = !enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +120,7 @@ class GUI : Extension {
|
|||||||
this.background = Color.RGBa(ColorRGBa.GRAY.copy(a = 0.99))
|
this.background = Color.RGBa(ColorRGBa.GRAY.copy(a = 0.99))
|
||||||
this.overflow = Overflow.Scroll
|
this.overflow = Overflow.Scroll
|
||||||
|
|
||||||
|
/* 1) setup control style */
|
||||||
descendant(has type "colorpicker-button") {
|
descendant(has type "colorpicker-button") {
|
||||||
this.width = 175.px
|
this.width = 175.px
|
||||||
}
|
}
|
||||||
@@ -123,7 +146,7 @@ class GUI : Extension {
|
|||||||
layout {
|
layout {
|
||||||
div("container") {
|
div("container") {
|
||||||
id = "container"
|
id = "container"
|
||||||
div("toolbar") {
|
val header = div("toolbar") {
|
||||||
button {
|
button {
|
||||||
label = "Randomize"
|
label = "Randomize"
|
||||||
clicked {
|
clicked {
|
||||||
@@ -148,8 +171,9 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div("sidebar") {
|
val sidebar = div("sidebar") {
|
||||||
id = "sidebar"
|
id = "sidebar"
|
||||||
|
scrollTop = sidebarState().scrollTop
|
||||||
for ((labeledObject, binding) in trackedObjects) {
|
for ((labeledObject, binding) in trackedObjects) {
|
||||||
val (label, _) = labeledObject
|
val (label, _) = labeledObject
|
||||||
|
|
||||||
@@ -169,21 +193,52 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header.mouse.pressed.subscribe {
|
header.mouse.pressed.subscribe {
|
||||||
|
it.cancelPropagation()
|
||||||
|
}
|
||||||
|
header.mouse.clicked.subscribe {
|
||||||
if (collapseClass in collapsible.classes) {
|
if (collapseClass in collapsible.classes) {
|
||||||
collapseState.collapsed = false
|
|
||||||
collapsible.classes.remove(collapseClass)
|
collapsible.classes.remove(collapseClass)
|
||||||
|
collapseState.collapsed = false
|
||||||
} else {
|
} else {
|
||||||
collapseState.collapsed = true
|
|
||||||
collapsible.classes.add(collapseClass)
|
collapsible.classes.add(collapseClass)
|
||||||
|
collapseState.collapsed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
header.mouse.pressed.subscribe {
|
||||||
|
it.cancelPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
header.mouse.clicked.subscribe {
|
||||||
|
val collapsed = ElementClass("collapsed")
|
||||||
|
if (collapsed in sidebar.classes) {
|
||||||
|
sidebar.classes.remove(collapsed)
|
||||||
|
sidebarState().collapsed = false
|
||||||
|
} else {
|
||||||
|
sidebar.classes.add(collapsed)
|
||||||
|
sidebarState().collapsed = true
|
||||||
|
}
|
||||||
|
it.cancelPropagation()
|
||||||
|
}
|
||||||
|
sidebar.mouse.scrolled.subscribe {
|
||||||
|
sidebarState().scrollTop = sidebar.scrollTop
|
||||||
|
}
|
||||||
|
if (sidebarState().collapsed) {
|
||||||
|
sidebar.classes.add(ElementClass("collapsed"))
|
||||||
|
}
|
||||||
|
sidebar.scrollTop = sidebarState().scrollTop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.enabled = enabled
|
if (sidebarState().hidden) {
|
||||||
|
enabled = false
|
||||||
|
panel.enabled = false
|
||||||
|
} else {
|
||||||
|
enabled = true
|
||||||
|
panel.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
program.extend(panel)
|
program.extend(panel)
|
||||||
}
|
}
|
||||||
@@ -192,6 +247,8 @@ class GUI : Extension {
|
|||||||
val obj = compartment.obj
|
val obj = compartment.obj
|
||||||
|
|
||||||
return when (parameter.parameterType) {
|
return when (parameter.parameterType) {
|
||||||
|
|
||||||
|
/* 2) control creation. create control, set label, set range, setup event-handler, load values */
|
||||||
ParameterType.Int -> {
|
ParameterType.Int -> {
|
||||||
slider {
|
slider {
|
||||||
label = parameter.label
|
label = parameter.label
|
||||||
@@ -221,7 +278,6 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterType.Action -> {
|
ParameterType.Action -> {
|
||||||
button {
|
button {
|
||||||
label = parameter.label
|
label = parameter.label
|
||||||
@@ -232,7 +288,6 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterType.Boolean -> {
|
ParameterType.Boolean -> {
|
||||||
slider {
|
slider {
|
||||||
label = parameter.label
|
label = parameter.label
|
||||||
@@ -246,7 +301,6 @@ class GUI : Extension {
|
|||||||
value = if ((parameter.property as KMutableProperty1<Any, Boolean>).get(obj)) 1.0 else 0.0
|
value = if ((parameter.property as KMutableProperty1<Any, Boolean>).get(obj)) 1.0 else 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterType.Text -> {
|
ParameterType.Text -> {
|
||||||
textfield {
|
textfield {
|
||||||
label = parameter.label
|
label = parameter.label
|
||||||
@@ -259,7 +313,6 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterType.Color -> {
|
ParameterType.Color -> {
|
||||||
colorpickerButton {
|
colorpickerButton {
|
||||||
label = parameter.label
|
label = parameter.label
|
||||||
@@ -310,6 +363,7 @@ class GUI : Extension {
|
|||||||
trackedObjects.entries.associate { (lo, b) ->
|
trackedObjects.entries.associate { (lo, b) ->
|
||||||
Pair(lo.label, b.parameterControls.keys.associate { k ->
|
Pair(lo.label, b.parameterControls.keys.associate { k ->
|
||||||
Pair(k.property?.name ?: k.function?.name ?: error("no name"), when (k.parameterType) {
|
Pair(k.property?.name ?: k.function?.name ?: error("no name"), when (k.parameterType) {
|
||||||
|
/* 3) setup serializers */
|
||||||
ParameterType.Double -> ParameterValue(doubleValue = k.property.qget(lo.obj) as Double)
|
ParameterType.Double -> ParameterValue(doubleValue = k.property.qget(lo.obj) as Double)
|
||||||
ParameterType.Int -> ParameterValue(intValue = k.property.qget(lo.obj) as Int)
|
ParameterType.Int -> ParameterValue(intValue = k.property.qget(lo.obj) as Int)
|
||||||
ParameterType.Action -> ParameterValue()
|
ParameterType.Action -> ParameterValue()
|
||||||
@@ -337,6 +391,7 @@ class GUI : Extension {
|
|||||||
ps.forEach { (parameterName, parameterValue) ->
|
ps.forEach { (parameterName, parameterValue) ->
|
||||||
binding.parameters.find { it.property?.name == parameterName }?.let { parameter ->
|
binding.parameters.find { it.property?.name == parameterName }?.let { parameter ->
|
||||||
when (parameter.parameterType) {
|
when (parameter.parameterType) {
|
||||||
|
/* 4) Set up deserializers */
|
||||||
ParameterType.Double -> parameterValue.doubleValue?.let {
|
ParameterType.Double -> parameterValue.doubleValue?.let {
|
||||||
parameter.property.qset(lo.obj, it)
|
parameter.property.qset(lo.obj, it)
|
||||||
}
|
}
|
||||||
@@ -365,6 +420,7 @@ class GUI : Extension {
|
|||||||
|
|
||||||
private fun updateControl(labeledObject: LabeledObject, parameter: Parameter, control: Element) {
|
private fun updateControl(labeledObject: LabeledObject, parameter: Parameter, control: Element) {
|
||||||
when (parameter.parameterType) {
|
when (parameter.parameterType) {
|
||||||
|
/* 5) Update control from property value */
|
||||||
ParameterType.Double -> {
|
ParameterType.Double -> {
|
||||||
(control as Slider).value = (parameter.property as KMutableProperty1<Any, Double>).get(labeledObject.obj)
|
(control as Slider).value = (parameter.property as KMutableProperty1<Any, Double>).get(labeledObject.obj)
|
||||||
}
|
}
|
||||||
@@ -391,6 +447,7 @@ class GUI : Extension {
|
|||||||
// -- only randomize visible parameters
|
// -- only randomize visible parameters
|
||||||
for (parameter in binding.parameterControls.keys) {
|
for (parameter in binding.parameterControls.keys) {
|
||||||
when (parameter.parameterType) {
|
when (parameter.parameterType) {
|
||||||
|
/* 6) Set up value randomizers */
|
||||||
ParameterType.Double -> {
|
ParameterType.Double -> {
|
||||||
val min = parameter.doubleRange!!.start
|
val min = parameter.doubleRange!!.start
|
||||||
val max = parameter.doubleRange!!.endInclusive
|
val max = parameter.doubleRange!!.endInclusive
|
||||||
|
|||||||
Reference in New Issue
Block a user