From 5b664267a803771f316643a21130c6f750ea45f3 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Thu, 3 Mar 2022 21:52:51 +0100 Subject: [PATCH] [orx-gui] doubleBind default true, add side canvas, add defaultStyles argument --- .../src/demo/kotlin/DemoSideCanvas01.kt | 48 ++++ orx-jvm/orx-gui/src/main/kotlin/Gui.kt | 255 ++++++++++-------- 2 files changed, 189 insertions(+), 114 deletions(-) create mode 100644 orx-jvm/orx-gui/src/demo/kotlin/DemoSideCanvas01.kt diff --git a/orx-jvm/orx-gui/src/demo/kotlin/DemoSideCanvas01.kt b/orx-jvm/orx-gui/src/demo/kotlin/DemoSideCanvas01.kt new file mode 100644 index 00000000..ec9d4254 --- /dev/null +++ b/orx-jvm/orx-gui/src/demo/kotlin/DemoSideCanvas01.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/orx-jvm/orx-gui/src/main/kotlin/Gui.kt b/orx-jvm/orx-gui/src/main/kotlin/Gui.kt index 200bb529..2ddbb5f0 100644 --- a/orx-jvm/orx-gui/src/main/kotlin/Gui.kt +++ b/orx-jvm/orx-gui/src/main/kotlin/Gui.kt @@ -71,7 +71,7 @@ private fun setAndPersist(compartmentLabel: String, property: KMutable private val logger = KotlinLogging.logger { } @Suppress("unused", "UNCHECKED_CAST") -class GUI : Extension { +class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List = defaultStyles()) : Extension { private var onChangeListener: ((name: String, value: Any?) -> Unit)? = null override var enabled = true @@ -91,10 +91,12 @@ class GUI : Extension { } var compartmentsCollapsedByDefault = true - var doubleBind = false + var doubleBind = true var defaultSaveFolder = "gui-parameters" var persistState = true + var enableSideCanvas = false + var canvas : Canvas? = null private var panel: ControlManager? = null // 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") { this.display = Display.FLEX this.flexDirection = FlexDirection.Column @@ -164,10 +181,10 @@ class GUI : Extension { this.flexDirection = FlexDirection.Column this.height = 5.px 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") { - 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.display = Display.FLEX 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") { @@ -195,7 +212,7 @@ class GUI : Extension { this.paddingRight = 10.px this.marginRight = 2.px 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 // @@ -248,135 +265,145 @@ class GUI : Extension { styleSheet(has type "dropdown-button") { this.width = 175.px } - - layout { - div("container") { - id = "container" - @Suppress("UNUSED_VARIABLE") val header = div("toolbar") { - randomizeButton = button { - label = "Randomize" - clicked { - randomize(strength = if (shiftDown) .75 else .05) + div("fullscreen") { + div("container") { + id = "container" + @Suppress("UNUSED_VARIABLE") val header = div("toolbar") { + randomizeButton = button { + label = "Randomize" + clicked { + randomize(strength = if (shiftDown) .75 else .05) + } } - } - button { - label = "Load" - clicked { - openFileDialog(supportedExtensions = listOf("json"), contextID = "gui.parameters") { - loadParameters(it) + button { + label = "Load" + clicked { + openFileDialog(supportedExtensions = listOf("json"), contextID = "gui.parameters") { + 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 { - label = "Save" - clicked { - val defaultPath = getDefaultPathForContext(contextID = "gui.parameters") + val collapseBorder = div("collapse-border") { - if (defaultPath == null) { - val local = File(".") - val parameters = File(local, defaultSaveFolder) - if (parameters.exists() && parameters.isDirectory) { - setDefaultPathForContext(contextID = "gui.parameters", file = parameters) + } + + val collapsibles = mutableSetOf
() + 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 (parameters.mkdirs()) { - setDefaultPathForContext(contextID = "gui.parameters", file = parameters) + + if (collapseClass in collapsible.classes) { + collapsible.classes.remove(collapseClass) + collapseState.collapsed = false } 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") { - - } - - val collapsibles = mutableSetOf
() - 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 - } - } - } + if (enableSideCanvas) { + canvas = canvas("full-canvas") { } } - 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 - program.extend(panel ?: error("no panel")) }