gui Macro

In owlkettle, graphical user interfaces are described using the gui macro. It provides a domain-specific language for specifying widget trees.

You can set fields on each widget in the widget tree. Fields may either be set in the argument list of a widget...

let widget = gui:
  Label(text = "Hello, world!", xAlign = 0.0)

...or in the body of the widget:

let widget = gui:
  Label:
    text = "Hello, world!"
    xAlign = 0.0

Each widget may also have a series of events. Events are triggered when the user interacts with the widget.

let widget = gui:
  Button:
    proc clicked() =
      app.counter += 1

Control Flow

You can use if, when and case statements to conditionally show and hide different widgets.

let widget = gui:
  case app.shownPage:
    of PageWelcome:
      Label:
        text = "Welcome!"
    of PageUser:
      UserPage()

if, when and case can also be used on fields:

let widget = gui:
  Label:
    if app.condition:
      text = "Hello"
    else:
      text = "World"

for statements can be used to generate lists of widgets.

let widget = gui:
  ListBox:
    for item in app.items:
      Label(text = item)

Adders

Adders specify how a widget is added to its parent. For example, the HeaderBar.addLeft adder places the given widget on the left side of the header bar, while the addRight adder places it on the right. Adders are specified using pragma expressions (e.g. {.add, expand: false.}). Which adders are available at any place in the widget tree depends on the parent widget. If no adder is specified, the add adder is used by default.

Each adder may receive a series of properties. For example, you can use the expand property of the Box.add adder to specify whether the given child widget should expand to fill up remaining space in the box.

let widget = gui:
  Box:
    Label {.expand: false.}:
      text = "no expand"
    Label {.expand: true.}:
      text = "expand"

insert Statement

The gui macro returns a Widget object. The insert statement inserts a Widget object previously returned by another gui macro into the current widget tree. It is commonly used to implement container widgets.

let childWidget = gui:
  Label(text = "Inserted widget")

let widget = gui:
  Box:
    insert(childWidget)

You can also specify an adder and set properties for the inserted widget.

let childWidget = gui:
  Label(text = "Inserted widget")

let widget = gui:
  Box:
    insert(childWidget) {.expand: false.}