[orx-gui] doubleBind default true, add side canvas, add defaultStyles argument
This commit is contained in:
48
orx-jvm/orx-gui/src/demo/kotlin/DemoSideCanvas01.kt
Normal file
48
orx-jvm/orx-gui/src/demo/kotlin/DemoSideCanvas01.kt
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.gui.GUI
|
||||||
|
import org.openrndr.extra.parameters.*
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import org.openrndr.panel.elements.draw
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple demonstration of a GUI for drawing some circles
|
||||||
|
*/
|
||||||
|
fun main() = application {
|
||||||
|
configure {
|
||||||
|
width = 800
|
||||||
|
height = 800
|
||||||
|
windowResizable = true
|
||||||
|
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
val gui = GUI(baseColor = ColorRGBa.GRAY.shade(0.25))
|
||||||
|
gui.compartmentsCollapsedByDefault = false
|
||||||
|
gui.enableSideCanvas = true
|
||||||
|
|
||||||
|
|
||||||
|
val settings = @Description("Settings") object {
|
||||||
|
@DoubleParameter("radius", 0.0, 100.0)
|
||||||
|
var radius = 50.0
|
||||||
|
|
||||||
|
@Vector2Parameter("position", 0.0, 1.0)
|
||||||
|
var position = Vector2(0.6, 0.5)
|
||||||
|
|
||||||
|
@ColorParameter("color")
|
||||||
|
var color = ColorRGBa.PINK
|
||||||
|
|
||||||
|
@DoubleListParameter("radii", 5.0, 30.0)
|
||||||
|
var radii = mutableListOf(5.0, 6.0, 8.0, 14.0, 20.0, 30.0)
|
||||||
|
}
|
||||||
|
gui.add(settings)
|
||||||
|
extend(gui)
|
||||||
|
|
||||||
|
gui.canvas?.draw {
|
||||||
|
val width = drawer.width
|
||||||
|
val height = drawer.height
|
||||||
|
drawer.fill = settings.color
|
||||||
|
drawer.circle(width/2.0, height/2.0, 100.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,7 +71,7 @@ private fun <T : Any> setAndPersist(compartmentLabel: String, property: KMutable
|
|||||||
private val logger = KotlinLogging.logger { }
|
private val logger = KotlinLogging.logger { }
|
||||||
|
|
||||||
@Suppress("unused", "UNCHECKED_CAST")
|
@Suppress("unused", "UNCHECKED_CAST")
|
||||||
class GUI : Extension {
|
class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<StyleSheet> = defaultStyles()) : Extension {
|
||||||
private var onChangeListener: ((name: String, value: Any?) -> Unit)? = null
|
private var onChangeListener: ((name: String, value: Any?) -> Unit)? = null
|
||||||
override var enabled = true
|
override var enabled = true
|
||||||
|
|
||||||
@@ -91,10 +91,12 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var compartmentsCollapsedByDefault = true
|
var compartmentsCollapsedByDefault = true
|
||||||
var doubleBind = false
|
var doubleBind = true
|
||||||
var defaultSaveFolder = "gui-parameters"
|
var defaultSaveFolder = "gui-parameters"
|
||||||
var persistState = true
|
var persistState = true
|
||||||
|
var enableSideCanvas = false
|
||||||
|
|
||||||
|
var canvas : Canvas? = null
|
||||||
private var panel: ControlManager? = null
|
private var panel: ControlManager? = null
|
||||||
|
|
||||||
// Randomize button
|
// Randomize button
|
||||||
@@ -151,7 +153,22 @@ class GUI : Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panel = program.controlManager {
|
panel = program.controlManager(defaultStyles = defaultStyles) {
|
||||||
|
styleSheet(has class_ "fullscreen") {
|
||||||
|
this.width = 100.percent
|
||||||
|
this.height = 100.percent
|
||||||
|
this.flexDirection = FlexDirection.Row
|
||||||
|
this.display = Display.FLEX
|
||||||
|
}
|
||||||
|
styleSheet(has class_ "full-canvas") {
|
||||||
|
this.background = Color.RGBa(ColorRGBa.RED)
|
||||||
|
|
||||||
|
this.flexShrink = FlexGrow.Ratio(1.0)
|
||||||
|
this.flexGrow = FlexGrow.Ratio(1.0)
|
||||||
|
this.height = 100.percent
|
||||||
|
this.width = 100.px
|
||||||
|
}
|
||||||
|
|
||||||
styleSheet(has class_ "container") {
|
styleSheet(has class_ "container") {
|
||||||
this.display = Display.FLEX
|
this.display = Display.FLEX
|
||||||
this.flexDirection = FlexDirection.Column
|
this.flexDirection = FlexDirection.Column
|
||||||
@@ -164,10 +181,10 @@ class GUI : Extension {
|
|||||||
this.flexDirection = FlexDirection.Column
|
this.flexDirection = FlexDirection.Column
|
||||||
this.height = 5.px
|
this.height = 5.px
|
||||||
this.width = 100.percent
|
this.width = 100.percent
|
||||||
this.background = Color.RGBa(ColorRGBa.GRAY.shade(0.9))
|
this.background = Color.RGBa(baseColor.shade(0.9))
|
||||||
|
|
||||||
and(has state "hover") {
|
and(has state "hover") {
|
||||||
this.background = Color.RGBa(ColorRGBa.GRAY.shade(1.1))
|
this.background = Color.RGBa(baseColor.shade(1.1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +193,7 @@ class GUI : Extension {
|
|||||||
this.width = 100.percent
|
this.width = 100.percent
|
||||||
this.display = Display.FLEX
|
this.display = Display.FLEX
|
||||||
this.flexDirection = FlexDirection.Row
|
this.flexDirection = FlexDirection.Row
|
||||||
this.background = Color.RGBa(ColorRGBa.GRAY.copy(a = 0.99))
|
this.background = Color.RGBa(baseColor.copy(a = 0.99))
|
||||||
}
|
}
|
||||||
|
|
||||||
styleSheet(has class_ "collapsed") {
|
styleSheet(has class_ "collapsed") {
|
||||||
@@ -195,7 +212,7 @@ class GUI : Extension {
|
|||||||
this.paddingRight = 10.px
|
this.paddingRight = 10.px
|
||||||
this.marginRight = 2.px
|
this.marginRight = 2.px
|
||||||
this.height = 100.percent
|
this.height = 100.percent
|
||||||
this.background = Color.RGBa(ColorRGBa.GRAY.copy(a = 0.99))
|
this.background = Color.RGBa(baseColor.copy(a = 0.99))
|
||||||
this.overflow = Overflow.Scroll
|
this.overflow = Overflow.Scroll
|
||||||
|
|
||||||
//<editor-fold desc="1) setup control style">
|
//<editor-fold desc="1) setup control style">
|
||||||
@@ -248,135 +265,145 @@ class GUI : Extension {
|
|||||||
styleSheet(has type "dropdown-button") {
|
styleSheet(has type "dropdown-button") {
|
||||||
this.width = 175.px
|
this.width = 175.px
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
layout {
|
layout {
|
||||||
div("container") {
|
div("fullscreen") {
|
||||||
id = "container"
|
div("container") {
|
||||||
@Suppress("UNUSED_VARIABLE") val header = div("toolbar") {
|
id = "container"
|
||||||
randomizeButton = button {
|
@Suppress("UNUSED_VARIABLE") val header = div("toolbar") {
|
||||||
label = "Randomize"
|
randomizeButton = button {
|
||||||
clicked {
|
label = "Randomize"
|
||||||
randomize(strength = if (shiftDown) .75 else .05)
|
clicked {
|
||||||
|
randomize(strength = if (shiftDown) .75 else .05)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
button {
|
||||||
button {
|
label = "Load"
|
||||||
label = "Load"
|
clicked {
|
||||||
clicked {
|
openFileDialog(supportedExtensions = listOf("json"), contextID = "gui.parameters") {
|
||||||
openFileDialog(supportedExtensions = listOf("json"), contextID = "gui.parameters") {
|
loadParameters(it)
|
||||||
loadParameters(it)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
label = "Save"
|
||||||
|
clicked {
|
||||||
|
val defaultPath = getDefaultPathForContext(contextID = "gui.parameters")
|
||||||
|
|
||||||
|
if (defaultPath == null) {
|
||||||
|
val local = File(".")
|
||||||
|
val parameters = File(local, defaultSaveFolder)
|
||||||
|
if (parameters.exists() && parameters.isDirectory) {
|
||||||
|
setDefaultPathForContext(contextID = "gui.parameters", file = parameters)
|
||||||
|
} else {
|
||||||
|
if (parameters.mkdirs()) {
|
||||||
|
setDefaultPathForContext(
|
||||||
|
contextID = "gui.parameters",
|
||||||
|
file = parameters
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logger.warn { "Could not create directory ${parameters.absolutePath}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveFileDialog(
|
||||||
|
suggestedFilename = "parameters.json",
|
||||||
|
contextID = "gui.parameters",
|
||||||
|
supportedExtensions = listOf("json")
|
||||||
|
) {
|
||||||
|
saveParameters(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button {
|
val collapseBorder = div("collapse-border") {
|
||||||
label = "Save"
|
|
||||||
clicked {
|
|
||||||
val defaultPath = getDefaultPathForContext(contextID = "gui.parameters")
|
|
||||||
|
|
||||||
if (defaultPath == null) {
|
}
|
||||||
val local = File(".")
|
|
||||||
val parameters = File(local, defaultSaveFolder)
|
val collapsibles = mutableSetOf<Div>()
|
||||||
if (parameters.exists() && parameters.isDirectory) {
|
val sidebar = div("sidebar") {
|
||||||
setDefaultPathForContext(contextID = "gui.parameters", file = parameters)
|
id = "sidebar"
|
||||||
|
scrollTop = sidebarState().scrollTop
|
||||||
|
for ((labeledObject, binding) in trackedObjects) {
|
||||||
|
val (label, _) = labeledObject
|
||||||
|
|
||||||
|
val h3Header = h3 { label }
|
||||||
|
val collapsible = div("compartment") {
|
||||||
|
for (parameter in binding.parameters) {
|
||||||
|
val element = addControl(labeledObject, parameter)
|
||||||
|
binding.parameterControls[parameter] = element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collapsibles.add(collapsible)
|
||||||
|
val collapseClass = ElementClass("collapsed")
|
||||||
|
|
||||||
|
/* this is guaranteed to be in the dictionary after insertion through add() */
|
||||||
|
val collapseState = persistentCompartmentStates[Driver.instance.contextID]!![label]!!
|
||||||
|
if (collapseState.collapsed) {
|
||||||
|
collapsible.classes.add(collapseClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
h3Header.mouse.pressed.listen {
|
||||||
|
it.cancelPropagation()
|
||||||
|
}
|
||||||
|
h3Header.mouse.clicked.listen { me ->
|
||||||
|
|
||||||
|
if (KeyModifier.CTRL in me.modifiers) {
|
||||||
|
collapsible.classes.remove(collapseClass)
|
||||||
|
persistentCompartmentStates[Driver.instance.contextID]!!.forEach {
|
||||||
|
it.value.collapsed = true
|
||||||
|
}
|
||||||
|
collapseState.collapsed = false
|
||||||
|
|
||||||
|
(collapsibles - collapsible).forEach {
|
||||||
|
it.classes.add(collapseClass)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (parameters.mkdirs()) {
|
|
||||||
setDefaultPathForContext(contextID = "gui.parameters", file = parameters)
|
if (collapseClass in collapsible.classes) {
|
||||||
|
collapsible.classes.remove(collapseClass)
|
||||||
|
collapseState.collapsed = false
|
||||||
} else {
|
} else {
|
||||||
logger.warn { "Could not create directory ${parameters.absolutePath}" }
|
collapsible.classes.add(collapseClass)
|
||||||
|
collapseState.collapsed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveFileDialog(suggestedFilename = "parameters.json", contextID = "gui.parameters", supportedExtensions = listOf("json")) {
|
|
||||||
saveParameters(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
collapseBorder.mouse.pressed.listen {
|
||||||
|
it.cancelPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
collapseBorder.mouse.clicked.listen {
|
||||||
|
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.listen {
|
||||||
|
sidebarState().scrollTop = sidebar.scrollTop
|
||||||
|
}
|
||||||
|
if (sidebarState().collapsed) {
|
||||||
|
sidebar.classes.add(ElementClass("collapsed"))
|
||||||
|
}
|
||||||
|
sidebar.scrollTop = sidebarState().scrollTop
|
||||||
}
|
}
|
||||||
val collapseBorder = div("collapse-border") {
|
if (enableSideCanvas) {
|
||||||
|
canvas = canvas("full-canvas") {
|
||||||
}
|
|
||||||
|
|
||||||
val collapsibles = mutableSetOf<Div>()
|
|
||||||
val sidebar = div("sidebar") {
|
|
||||||
id = "sidebar"
|
|
||||||
scrollTop = sidebarState().scrollTop
|
|
||||||
for ((labeledObject, binding) in trackedObjects) {
|
|
||||||
val (label, _) = labeledObject
|
|
||||||
|
|
||||||
val h3Header = h3 { label }
|
|
||||||
val collapsible = div("compartment") {
|
|
||||||
for (parameter in binding.parameters) {
|
|
||||||
val element = addControl(labeledObject, parameter)
|
|
||||||
binding.parameterControls[parameter] = element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collapsibles.add(collapsible)
|
|
||||||
val collapseClass = ElementClass("collapsed")
|
|
||||||
|
|
||||||
/* this is guaranteed to be in the dictionary after insertion through add() */
|
|
||||||
val collapseState = persistentCompartmentStates[Driver.instance.contextID]!![label]!!
|
|
||||||
if (collapseState.collapsed) {
|
|
||||||
collapsible.classes.add(collapseClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
h3Header.mouse.pressed.listen {
|
|
||||||
it.cancelPropagation()
|
|
||||||
}
|
|
||||||
h3Header.mouse.clicked.listen { me ->
|
|
||||||
|
|
||||||
if (KeyModifier.CTRL in me.modifiers) {
|
|
||||||
collapsible.classes.remove(collapseClass)
|
|
||||||
persistentCompartmentStates[Driver.instance.contextID]!!.forEach {
|
|
||||||
it.value.collapsed = true
|
|
||||||
}
|
|
||||||
collapseState.collapsed = false
|
|
||||||
|
|
||||||
(collapsibles - collapsible).forEach {
|
|
||||||
it.classes.add(collapseClass)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (collapseClass in collapsible.classes) {
|
|
||||||
collapsible.classes.remove(collapseClass)
|
|
||||||
collapseState.collapsed = false
|
|
||||||
} else {
|
|
||||||
collapsible.classes.add(collapseClass)
|
|
||||||
collapseState.collapsed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collapseBorder.mouse.pressed.listen {
|
|
||||||
it.cancelPropagation()
|
|
||||||
}
|
|
||||||
|
|
||||||
collapseBorder.mouse.clicked.listen {
|
|
||||||
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.listen {
|
|
||||||
sidebarState().scrollTop = sidebar.scrollTop
|
|
||||||
}
|
|
||||||
if (sidebarState().collapsed) {
|
|
||||||
sidebar.classes.add(ElementClass("collapsed"))
|
|
||||||
}
|
|
||||||
sidebar.scrollTop = sidebarState().scrollTop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = !sidebarState().hidden
|
visible = !sidebarState().hidden
|
||||||
|
|
||||||
|
|
||||||
program.extend(panel ?: error("no panel"))
|
program.extend(panel ?: error("no panel"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user