Abstract Lua Graphical User Interface is a Lua library which aims to be a simple and embeddable GUI system.
Tip: If your GUI relies on time and you don't already have some kind of scheduler, elscheduler may interest you.
Principles:
- The library should be a framework, not a full fledged GUI; it must be defined/extended to suit needs.
- It should decouple logic and rendering for clarity and flexibility.
E.g. the logic may stay in Lua and the rendering could be done by something else. - It should be flexible.
E.g. the 2D surface of a widget is not necessarily expressed in pixels of a screen, it could be meters for a VR/3D surface. - It should allow for both stateful and stateless renderers.
E.g. for performance rendering data could be updated only when needed.
Concepts
- GUI: Root widget.
- Widget: Object which may contain other widgets. Defines a 2D surface (axis-aligned rectangle) with an inner content.
- Renderer: Used to render a GUI.
Event
Events are emitted on widgets and are deferred through an event loop.
View
Each widget has a view surface based on its parent's view surface. The view is recomputed when needed and allows to only render visible widgets.
Inner content
Each widget has an inner content which contains its children. The parent widget has zoom and offset properties to scale/offset the display of the inner content.
Note: The inner offset is applied in inner space, not in the parent widget space.
Layout
GUI layouts in general may be simple or complex ways to achieve dynamic
organization of widgets based on some rules. ALGUI widgets have a fixed surface
and there are no internal rules to change that, but widgets can implement
layouts through the updateLayout()
method.
Layouts are updated recursively; when updating its layout, each widget can call
updateLayout()
on its children to request a specific size (if needed) and the
children may update their layouts accordingly. This way, widgets are allowed to
organize their children and set their own size based on their own layout.
Note: Layouts are updated when the widgets' size or content is updated.
Warning: Layouts are built from the shallowest to the deepest widgets; widgets shouldn't base their layout on the parent data.
Warning: Wrongly designed layouts may cause an infinite loop.
Consistency
Some computed data are cached to improve logic performances. A stateful renderer may also build data by listening to GUI events.
To ensure consistency of computed data between the GUI and Renderer, the state of the GUI should not be modified between the end of a tick and the rendering (emitting events is fine).
Warning: By the loose coupling design of the library, it is not recommended to add/remove a widget between different GUIs; this may result in deferred effects or cached data to be incorrectly applied or interpreted.
API
Events
Event handler callback:
-- Event handler.
-- callback(widget, event, ...)
--- widget: event target
--- event: event identifier (any value as key)
--- ...: event arguments
Core events:
Identifier | Target | Arguments | Description |
---|---|---|---|
bind | GUI | widget | When a widget is bound to the GUI. |
unbind | GUI | widget | When a widget is unbound from the GUI. |
position-update | Widget | x, y | |
size-update | Widget | w, h | |
z-update | Widget | z | |
visibility-update | Widget | visibility | When the final visibility, not the visible flag, is updated. |
inner-zoom-update | Widget | zoom | |
inner-offset-update | Widget | x, y | |
transform-update | Widget | ||
view-update | Widget | ||
drawlist-update | Widget |
Ext
Spatial event
A spatial event is propagated by crossing widgets at a specific position from the shallowest to the deepest widget, known as the down phase, then backwards, known as the up phase.
The deepest widget, also known as the target, only receives the up phase event.
Down phase events have the :down
suffix to their identifier.
A unique state is shared among the events to implement a capture behavior by
checking/setting the captured
field flag.
Ext GUI events:
Identifier | Target | Arguments | Description |
---|---|---|---|
pointer-press | Widget | id, x, y, button, n, state | (spatial) |
pointer-release | Widget | id, x, y, button, state | (spatial) |
pointer-click | Widget | id, x, y, button, n, state | (spatial) |
pointer-wheel | Widget | id, x, y, wx, wy, state | (spatial) |
pointer-move | Widget | id, x, y, dx, dy, state | (spatial) |
pointer-enter | Widget | id | |
pointer-leave | Widget | id | |
focus-transition | GUI | old, new | |
focus-update | Widget | focus (flag) | |
key-press | GUI and focused widget | keycode, scancode, repeated | |
key-release | GUI and focused widget | keycode, scancode | |
text-input | GUI and focused widget | text |