User Interfaces
This topic discusses the creation of graphical user interfaces in OPENRNDR applications.
The Panel library
The Panel library provides an HTML/CSS like user interface toolkit and is written using OPENRNDR.
Basic Usage
The easiest way to use Panel is to use it as a Program extension. When used as an extension all mouse and keyboard events are automatically handled and drawing of the user interface will take place after your program’s draw() has been invoked.
To create a very simple user interface that consists of just a single button one would do the following:

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.panel.ControlManager
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.layout
import org.openrndr.panel.style.*
import org.openrndr.panel.styleSheet
fun main() = application {
program {
var color = ColorRGBa.GRAY.shade(0.250)
extend(ControlManager()) {
layout {
button {
label = "click me"
// -- listen to the click event
clicked {
color = ColorRGBa(Math.random(), Math.random(), Math.random())
}
}
}
}
extend {
drawer.clear(color)
}
}
}
Style sheets
The Panel library borrows a lot of ideas from HTML/CSS based layout systems, one of those ideas is style sheets.
Style sheets can be used as shown in the following example in which a style sheet is used to color a button pink.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.panel.ControlManager
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.layout
import org.openrndr.panel.style.*
import org.openrndr.panel.styleSheet
fun main() = application {
program {
extend(ControlManager()) {
styleSheet(has type "button") {
background = Color.RGBa(ColorRGBa.PINK)
color = Color.RGBa(ColorRGBa.BLACK)
width = 120.px
}
layout {
button {
label = "click me"
}
}
}
}
}
Selectors
The following example shows how to build and use complex selectors
fun main() = application {
program {
styleSheet(has class_ "control-bar") {
descendant(has type "button") {
width = 100.percent
}
child(has type "slider") {
width = 100.percent
and(has state "hover") {
background = Color.RGBa(ColorRGBa.RED)
}
}
}
}
}
Elements
The Panel library comes with a built-in set of elements with which user interfaces can be composed.
Element
Element is the base class from which all other elements derive. Element can be used directly but it is advised to use Div instead.
Div
The Div represents a rectangular area in which other elements can be placed. The Div element is the main ingredient in the creation of layouts. Divs are best created using the div {} builder.
fun main() = application {
program {
controlManager {
layout {
div("some-class-here", "another-class-here") {
// -- children here
}
}
}
}
}
Button
An ordinary labelled button. The default width of buttons is set to Auto such that the width is determined by the label contents.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.panel.ControlManager
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.layout
import org.openrndr.panel.style.*
import org.openrndr.panel.styleSheet
fun main() = application {
program {
extend(ControlManager()) {
layout {
button {
label = "Click me "
events.clicked.listen {
// -- do something with the clicked event
}
}
}
}
extend {
drawer.clear(ColorRGBa.GRAY.shade(0.250))
}
}
}
Slider
A horizontal labelled slider control.
Properties
label : String- the slider labelprecision : Int- the number of digits behind the point, set to 0 for an integer sliderrange: Range- the slider range, default isRange(0.0, 10.0)value : Double- the slider value
Events
valueChanged- emitted when the slider value has changed

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.panel.ControlManager
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.layout
import org.openrndr.panel.style.*
import org.openrndr.panel.styleSheet
fun main() = application {
program {
extend(ControlManager()) {
layout {
slider {
label = "Slide me"
range = Range(0.0, 1.0)
value = 0.50
precision = 2
events.valueChanged.listen {
println("the new value is ${it.newValue}")
}
}
}
}
}
}
Since the value is clamped to the current range, it is better to set the range before the value to avoid unexpected results.
ColorPickerButton
A button like control that slides out a HSV color picker when clicked
Properties
label : String- the label on the buttonvalue : ColorRGBa- the currently picked color
Events
valueChanged- emitted when a color is picked

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.panel.ControlManager
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.layout
import org.openrndr.panel.style.*
import org.openrndr.panel.styleSheet
fun main() = application {
program {
extend(ControlManager()) {
layout {
colorpickerButton {
label = "Pick a color"
color = ColorRGBa.PINK
events.valueChanged.listen {
println("the new color is ${it.color}")
}
}
}
}
}
}
DropdownButton
A button like control that slides out a list of items when clicked.
Properties
label : String- the label on the buttonvalue : Item- the currently picked item
Events
valueChanged- emitted when an option is picked

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.panel.ControlManager
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.layout
import org.openrndr.panel.style.*
import org.openrndr.panel.styleSheet
fun main() = application {
program {
extend(ControlManager()) {
styleSheet(has id "b1") {
width = 150.px
}
layout {
dropdownButton {
id = "b1"
label = "Option"
item {
label = "Item 1"
events.picked.listen {
println("you picked item 1")
}
}
item {
label = "Item 2"
events.picked.listen {
println("you picked item 2")
}
}
}
}
}
}
}