ui.um offers an immediate GUI library suitable both for simple game menus and more complex applications. See the tutorial for example usage.

struct BoxStyle

type BoxStyle* = struct {
	img: image::Image
	outer, inner: rect::Rect
	scale: th::fu
	color: uint32
}

BoxStyle describes how a box within the GUI is styled. In this case box can be anything, ranging from a button to a container. By default the box is drawn using the image.Image.drawNinepatch method. However if the image is invalid, a rectangle with color color is drawn.

interface Font

type Font* = interface {
	draw(text: str, pos: th::Vf2, color: uint32, scale: th::fu = 1.0)
	measure(test: str): th::Vf2
}

This interface is used by all elements that draw text. A font.Font implements this interface.

struct PixelFont

type PixelFont* = struct { }

This struct implement the Font interface using the canvas.um pixel font.

struct Style

type Style* = struct {
	// current font
	ft: Font
	// font scale
	ftScale: th::fu
	// text color
	ftColor: uint32

	// Positive box - i. e. unpressed button
	posBox: BoxStyle
	// Negative box - i. e. pressed button, text box
	negBox: BoxStyle
	// Used to draw containers
	containerBox: BoxStyle
}

Style is used as a global state for styling the GUI.

interface Container

type Container* = interface {
	// This adds a rectangle to the container, and returns the rectangle
	// which was actually added (the container can modify the rectangle).
	// See individual containers for further documentation.
	pushRect(r: rect::Rect): rect::Rect
	getDims(): rect::Rect
}

Containers are used to layout elements or other containers.

struct Gui

type Gui* = struct {
	// user context passed to layout functions
	ctx: any

	// the index of the current selection. TODO implement properly
	selection: int
	// true, if the layout is being evaluated, not drawn
	isEval: bool
	// contains more unexported fields

This is the main struct of any UI. Styles and containers are in a stack.

fn mk

fn mk*(r: rect::Rect, s: Style): Gui

Creates a new gui spanning r, with style s.

type LayoutFn

type LayoutFn* = fn(gui: ^Gui)

The layout function calls different element or container methods to create the user interface itself. It is called in the eval and draw.

fn BoxStyle.draw

fn (this: ^BoxStyle) draw*(r: rect::Rect) {

Draws a rectangle using a BoxStyle

fn Gui.pushStyle

fn (this: ^Gui) pushStyle*(s: Style) {

Pushes a style onto the style stack.

fn Gui.popStyle

fn (this: ^Gui) popStyle*() {

Pops a style from the style stack.

fn Gui.getStyle

fn (this: ^Gui) getStyle*(): ^Style {

Returns a pointer to the style atop the style stack.

fn Gui.getContainer

fn (this: ^Gui) getContainer*(): Container {

Returns the container atop the container stack.

fn Gui.pushRect

fn (this: ^Gui) pushRect*(r: rect::Rect): rect::Rect {

Shortcut to this.getContainer().pushRect(r)

fn Gui.getDims

fn (this: ^Gui) getDims*(): rect::Rect {

Shortcut to this.getContainer().getDims(r)

fn Gui.dupStyle

fn (this: ^Gui) dupStyle*() {

Duplicates the current style.

fn Gui.pushContainer

fn (this: ^Gui) pushContainer*(c: Container) {

Pushes a container onto the container stack.

fn Gui.popContainer

fn (this: ^Gui) popContainer*() {

Pops a container from the container stack.

fn Gui.eval

fn (this: ^Gui) eval*(layout: LayoutFn) {

Runs the evaluation phase on layout.

fn Gui.draw

fn (this: ^Gui) draw*(layout: LayoutFn) {

Runs the draw phase on layout.

enum BoxGrow

type BoxGrow* = enum {
	dimension
	subdiv
	span
	pxSpan
}

The different types of "growing" the box can do.

enum BoxDirection

type BoxDir* = enum {
	down
	right
	up
	left
}

Direction in which the box will grow.

struct BoxConfig

type BoxConfig* = struct {
	// dimension to grow by if `BoxGrowDimension` is used
	dimension: th::fu
	// number of subdivisions if `BoxGrowSubdivisions` is used
	subdivisions: uint
	// the grow type
	growType: BoxGrow
	// the grow direction
	dir: BoxDir
	// Specifies the values used with BoxGrowSpan nad BoxGrowPxSpan.
	// If BoxGrowSpan is used, 1 equals the size of the box divided by the sum
	// of all spans.
	// If BoxGrowPxSpan is used, 1 equals one pixel.
	span: []th::fu
	// rect passed to the current container
	rect: rect::Rect
	// padding inserted after each element
	padding: th::fu
}

Configuration of the Box container.

struct Box

type Box* = struct {
	grow: th::fu
	spanCursor: int
	dm: rect::Rect
	cfg: BoxConfig
}

Box is the main layout. It puts the elements next to each other, according to the config.

If the dimensions of the rect passed to pushRect are non zero, they will be kept. Position is always forced.

fn Gui.box

fn (gui: ^Gui) box*(cfg: BoxConfig = {
	dimension: 30,
	growType: BoxGrow.dimension,
	dir: BoxDir.down }) {

Adds the Box container to the gui.

struct StackConfig

type StackConfig* = struct {
	rect: rect::Rect
	padding: th::fu
}

Configuration for the Stack container.

struct Stack

type Stack* = struct {
	dm: rect::Rect
	cfg: StackConfig
}

The stack container puts elements on top of each other. If a property of the rect passed to pushRect is zero, it will be changed to an equivalent property of the containers' dimensions (minus the padding), else it will stay the same. This means stack can be used either to put multiple elements/containers on top of each other, or for absolutely positioned elements.

fn Gui.stack

fn (gui: ^Gui) stack*(cfg: StackConfig = {}) {

Adds the Stack container to the gui.

struct ScrollAreaConfig

type ScrollAreaConfig* = struct {
	rect: rect::Rect
	// scroll speed. Default is 1
	speed: real32
	// if true, scrolling will be horizontal
	horizontal: bool
}

Configuration for the scroll area.

struct ScrollArea

type ScrollArea* = struct {
	dm: rect::Rect
	cfg: ScrollAreaConfig
	scroll: ^real32
	maxScroll: real32
}

Scroll area is a container which allows the user to scroll. It acts as a stack container, but all the elements are shifted by the scroll.

fn Gui.scrollArea

fn (gui: ^Gui) scrollArea*(scroll: ^real32, maxScroll: real32, cfg: ScrollAreaConfig = {}) {

Pushes a scroll area. scroll is both input and output value. Both scroll and maxScroll are in pixels.

struct ButtonConfig

type ButtonConfig* = struct {
	rect: rect::Rect
}

Configuration for the button.

fn Gui.button

fn (gui: ^Gui) button*(cfg: ButtonConfig = {}): bool {

Adds a button to the gui. The button acts like a Stack container, but it is drawn using the pos/nexBox styles and handles clicks. If the button is pressed and the gui is in the eval phase, the return value will be true.

struct LabelConfig

type LabelConfig* = struct {
	// centers the label along the X axis, enables `stretchX`
	centerX: bool
	// centers the label along the Y axis, enables `stretchY`
	centerY: bool
	// if false, the rect passed to `pushRect` will have the width of
	// the text, else it will be 0
	stretchX: bool
	// if false, the rect passed to `pushRect` will have the height of
	// the text, else it will be 0
	stretchY: bool
	// forces the rectangle the label will use
	rect: rect::Rect
}

fn Gui.label

fn (gui: ^Gui) label*(text: str, cfg: LabelConfig = {

Draws a label using the current font style.

fn Gui.qbutton

fn (gui: ^Gui) qbutton*(text: str, cfg: ButtonConfig = {}): bool {

Adds a button with a label to gui.

struct TextBoxConfig

type TextBoxConfig* = struct {
	// force the rect of the text box
	rect: rect::Rect
}

struct TextBox

type TextBox* = struct {
	// index of the cursor
	cursor: int
	// contains other unexported rules...

fn TextBox.clear

fn (this: ^TextBox) clear*() {

Clears the textbox

fn TextBox.getBuf()

fn (this: ^TextBox) getBuf*(): str {

Get the content of the textbox.

fn TextBox.setBuf()

fn (this: ^TextBox) setBuf*(s: str) {

Get the content of the textbox.

fn Gui.textBox

fn (gui: ^Gui) textBox*(tb: ^TextBox, cfg: TextBoxConfig = {}) {

Adds a single line textbox to the gui. TODO:

  • right-to-left unicode is not supported.
  • no selection
  • multiline
  • copy paste (now implemented but in a limited way due to the lack of selection)
  • common input shortcuts
  • ctrl+delete / ctrl+backspace (delete word)

struct ImageConfig

type ImageConfig* = struct {
	stretchX, stretchY: bool
	centerX, centerY: bool
	color: uint32
	scale: th::Vf2
	rect: rect::Rect
}

Configuration for the images element. Behaves similarly to labels.

fn Gui.image

fn (gui: ^Gui) image*(i: image::Image, cfg: ImageConfig = {
	stretchX: true,
	stretchY: true,
	color: th::white,
	scale: { 1, 1 } }) {

Draws an image.

fn getDefaultStyle

fn getDefaultStyle*(): Style {

Returns the default tophat ui style.

fn mk

fn mk*(r: rect::Rect, s: Style): Gui {

Creates a GUI instance.