gui.lua
Documentation on using the GUI library written for OpenComputers
Overview
The GUI library comes in 2 parts, the Window Manager (wm
) and the Display Rendering Interface (dri
). A small undocumented util library beans
is also provided.
The library itself is very lightweight and small (~500 lines). Three fundamental structures that make up the GUI (all under the wm
library): the widget, the page and the window.
The widget: Everything displayed on the screen is a widget. Windows are widgets and even the screen is a widget.
The page: A page describes the tab index of widgets. By pressing TAB, the user can bring different widgets into focus. The page describes which widgets can be focused and in what order.
The window: A window is an abstraction for a group of widgets. The
wm
will redirect events to the currently active window.
Objects are implemented through closures (are objects and closures the same thing?). I merely am following in the footsteps of the venerable master Qc Na and his student Anton.
Window Manager API (WM)
Type hints will be provided when necessary (in colon notation). If no type hints are present, use common sense. Non-standard Lua types (i.e., Label
) are assumed to be objects (Lua tables with specific structures). All objects are documented in the subsections below.
wm.createEventObject(): EventHandler
An EventHandler object defines 2 methods (
add
andremove
) plus the metatable__call
event. See more in Examples.add(this: EventHandler, evt: string, fn)
remove(this: EventHandler, evt: string, fn)
this(evt: string, ...)
Calling the object will invoke the appropriate handlerMultiple callbacks can be assigned to one event
wm.makeWidget(vt: Table): Widget
Creates a new widget. An optional virtual function table can be passed as
vt
vt
can be nil or a table with any combination of these keys:Function pointers:
draw
,focus
,blur
,layer
,bounds
wm.makeBox(width, height, fgcolor, bgcolor): Box
wm.makeLabel(blurred, focused, checkedBlurred, checkedFocused): Label
Creates a new label with the specified states in the parameters
Each parameter can be nil or a table with any combination of these keys:
text
,fg
,bg
Labels are checkable and focusable
wm.makeCombo(w, h): Combo
By using the arrow keys (up and down), the user can change which child item of the combo group is checked. Only direct child layers of the combo group will be affected
When a selection is changed, the target child item is focused and checked
The height is inadequate, a vertical scrollbar will appear
wm.makeInput(width: number, blurred, focused, cursor): Input
Creates a single-line user input field of a fixed
width
Each state parameter (
blurred
,focused
andcursor
) can be nil or a table with any combination of these keys:fg
,bg
The user can use arrow keys (left and right) to move the cursor
Backspace will remove the character preceding the cursor
Home and end will move the cursor to the beginning and end of the text respectively
Any other non-control character will be inserted in the space specified by the cursor
wm.makeManager(vt): Manager
Creates the "root window" object
wm.makeWindow(name, vt): Window
Creates a window object with a given unique name
wm.makePage(): Page
Creates a blank page. Pages must be manually bound to windows. See the
Page
object documentation for more details
wm.run(ctx: Manager)
Paints and begins the event loop for a given manager
WM Object Documentation
Inherits from Window
this.refresh()
Since managers are "root windows," this function redraws the entire screen
WM Widgets Documentation
Some methods will automatically mark the region defined by bounds
dirty for you.
These are: draw
, focus
, blur
and move
Widget virtual table functions:
preDraw: function(x, y)
draw: function(x, y)
postDraw: function(x, y)
blur: function()
bounds: function(x, y)
focus: function()
layer: function(f, x, y)
Widget methods:
this.x(): number
andthis.y(): number
Returns the x and y coordinates of the control relative to the parent
this.screenX(): number
andthis.screenY(): number
Returns the x and y screen coordinates of the control
this.move(x, y)
Sets coordinate of control relative to the parent
this.draw(x, y): r: boolean, x1, y1
Draws the control relative to some point (i.e., the drawer is the parent)
The first return value specifies whether or not a region mask should be popped (see the DRI documentation). The second and third values specify offsets for children to be drawn at. If any are nil default values of false and 0 will be assigned appropriately.
this.focus()
this.blur()
this.visible(): boolean
this.focused(): boolean
this.layer(f: Widget, x, y)
Adds a child widget to the parent at the specified relative coordinates
Order of addition dictates paint order
this.update()
Dummy method - child classes override to update control state
this.bounds(): Table { x1, x2, y1, y2 }
The boundary of the current widget
this.bodyBounds(): Table
The boundary of the main body of the widget (defaults to
bounds()
)
this.layers: Table
Propertythis.handlers: EventHandler
Propertythis.disableNoFlash
Property
Display Rendering Interface (DRI)
DRI allows us to only render areas that need to be rendered. It also allows child widgets to only be rendered within a region defined by the parent. This reduces flickering and enables double buffering-like behaviour.
dri.set(x, y, t)
Will draw some text to the screen only if x, y satisfies all of:
inside a dirty region as defined under
dri.regions
outside the regions defined under
dri.negate
inside the uppermost mask of
dri.masks
stack
dri.pushMask(x: Table { x1, x2, y1, y2 }, t: boolean)
The parameter
t
(true if should negate) is rarely used and should be ignored
dri.popMask()
dri.setColors(fg, bg)
dri.markDirty(x: Table { x1, x2, y1, y2 })
Appends the dirty area in
dri.buffer
dri.regions
,dri.negate
,dri.buffer
anddri.masks
are all tables
Usage
The DRI is quite complex and there are some nuances that you need to be aware of.
Examples
Hello, World!
A minimal example with a fullscreen window and a single label would look like this:
Note that windows will not have any decorations drawn by default. Windows by default have no drawing routines. They mainly provide event redirection and such boring (but important) features. However, nothing is stopping you from adding routines!
Pages Upon Pages of Fun!
Pages allow users to focus elements in the order they are added to the page. The boilerplate code has been omitted for brevity. Running this example and pressing tab allows you to cycle through the 3 buttons. Note the order they appear (see line 13).
Last updated