29 KiB
GUI Library Documentation
A LÖVE2D-based GUI framework with a dual-dimension layout system, event-driven architecture, theming, transitions, and a rich set of built-in widgets.
Table of Contents
- Setup & Integration
- The Dual-Dimension Layout System
- Core Widget Reference
- Base Object API
- Events & Connections
- Theming
- Color Module
- Transitions & Animation
- Add-on Widgets
- Canvas
- Simulation (Testing)
- Scheduler Probe (Load Monitoring)
- Task Manager
- Tips & Patterns
1. Setup & Integration
Require the library at the top of your project. The library hooks into LÖVE's callbacks automatically.
local gui = require("gui")
function love.update(dt)
gui.update(dt)
end
function love.draw()
gui.draw()
end
That is all that is required. The library installs its own hooks for love.keypressed, love.mousepressed, love.resize, etc., so you do not need to forward those manually.
Creating Additional Processors
The library runs on the multi scheduler. If you need background work to integrate with the GUI update cycle, use gui:newProcessor:
local proc = gui:newProcessor("MyProcessor")
proc:newThread(function() ... end)
2. The Dual-Dimension Layout System
Every object's size and position is described by eight numbers that combine pixel offsets with fractional (0–1) scale values relative to the parent. This is the library's central concept.
setDualDim(x, y, w, h, sx, sy, sw, sh)
| Parameter | Meaning |
|---|---|
x |
Pixel offset from parent's left edge |
y |
Pixel offset from parent's top edge |
w |
Pixel width |
h |
Pixel height |
sx |
Fractional X position (0 = left, 1 = right of parent) |
sy |
Fractional Y position (0 = top, 1 = bottom of parent) |
sw |
Fractional width (0 = 0px, 1 = full parent width) |
sh |
Fractional height (0 = 0px, 1 = full parent height) |
The resolved absolute values are calculated as:
absolute_x = parent.w * sx + x + parent.x
absolute_y = parent.h * sy + y + parent.y
absolute_w = parent.w * sw + w
absolute_h = parent.h * sh + h
Examples
-- Full-screen frame (fills parent completely)
frame:setDualDim(0, 0, 0, 0, 0, 0, 1, 1)
-- Fixed 200×50 button in the top-left corner
btn:setDualDim(10, 10, 200, 50)
-- Centered horizontally, 300px wide, 5% from the top
panel:setDualDim(-150, 0, 300, 0, 0.5, 0.05, 0, 0.4)
-- sx=0.5 puts the left edge at the parent's midpoint;
-- x=-150 shifts it left by half the panel's own width.
-- Right-aligned sidebar, 20% of parent width, full height
sidebar:setDualDim(0, 0, 0, 0, 0.8, 0, 0.2, 1)
-- Anchored to bottom-right corner, fixed 100×30
btn:setDualDim(-110, -40, 100, 30, 1, 1)
Helper: fullFrame()
Sets the object to fill its parent completely (equivalent to setDualDim(0,0,0,0,0,0,1,1)).
frame:fullFrame()
Reading Position
local x, y, w, h = obj:getAbsolutes() -- resolved pixel values
local x, y, w, h, sx, sy, sw, sh = obj:getDualDim() -- raw dual-dim values
Squaring
Setting obj.square = "w" forces h = w (width-driven square). Setting obj.square = "h" forces w = h (height-driven square). Useful for icon buttons and circle elements.
3. Core Widget Reference
All constructors follow the same signature pattern:
parent:newXxx(x, y, w, h, sx, sy, sw, sh)
where parent is either gui (the root) or another object. Children are drawn on top of and clipped by (if clipDescendants is set) their parent.
3.1 Frame
A plain rectangular container. The base building block.
local panel = gui:newFrame(x, y, w, h, sx, sy, sw, sh)
-- Example: a full-screen dark overlay
local overlay = gui:newFrame(0, 0, 0, 0, 0, 0, 1, 1)
overlay.color = {0, 0, 0}
overlay.visibility = 0.6
Virtual Frame — exists in memory and updates but is never drawn. Used to move objects off-screen without destroying them.
local vframe = gui:newVirtualFrame(...)
Visual Frame — a frame that does not participate in mouse hit-testing. Children of a visual frame are also non-interactive.
local display = gui:newVisualFrame(...)
3.2 TextLabel
A non-interactive frame that renders text.
local label = parent:newTextLabel("Hello, World!", x, y, w, h, sx, sy, sw, sh)
Key properties:
| Property | Type | Description |
|---|---|---|
text |
string | The displayed text |
textColor |
color | Text color (default: black) |
font |
Font | LÖVE font object |
align |
constant | gui.ALIGN_LEFT, gui.ALIGN_CENTER, or gui.ALIGN_RIGHT |
textOffsetX/Y |
number | Pixel nudge for text rendering |
textScaleX/Y |
number | Scale multiplier for text |
textVisibility |
number | 0–1 alpha for text only |
Font methods:
label:setFont(16) -- set by size (default font)
label:setFont("fonts/myfont.ttf", 18) -- set by file + size
label:setFont(myLoveFont) -- set by existing font object
label:fitFont(minSize, maxSize) -- auto-fit text to the element's bounds
label:centerFont() -- vertically center text within element
3.3 TextButton
An interactive button with text. Automatically shows a hand cursor on hover.
local btn = parent:newTextButton("Click Me", x, y, w, h, sx, sy, sw, sh)
btn.OnReleased(function(self, x, y, button, istouch)
print("Button clicked!")
end)
Buttons automatically integrate with the theming system inside a newWindow — they receive button colors, hover highlights, and the button font.
3.4 TextBox (Input)
An editable single-line text input field. Gains focus on click and shows a blinking cursor.
local input = parent:newTextBox("placeholder", x, y, w, h, sx, sy, sw, sh)
Key properties:
| Property | Type | Description |
|---|---|---|
text |
string | Current text value |
cur_pos |
number | Cursor position (character index) |
blink |
boolean | Whether cursor blinks (default: true) |
Selection API:
input:HasSelection() -- boolean
input:GetSelection() -- start, stop (always start <= stop)
input:GetSelectedText() -- string
input:ClearSelection()
Events:
input.OnReturn(function(self, text)
print("Submitted:", text)
end)
Built-in hotkeys (active when the textbox has focus):
Ctrl+A— select allCtrl+C— copy selectionCtrl+V— pasteCtrl+X— cut selectionLeft/Right— move cursorBackspace/Delete— delete character
3.5 ImageLabel
Displays an image. Supports PNG, JPG, and GIF.
local img = parent:newImageLabel("path/to/image.png", x, y, w, h, sx, sy, sw, sh)
The image is stretched to fill the element's bounds. GIFs animate automatically.
Changing the image:
img:setImage("path/to/other.png")
img:setImage(loveImageObject)
-- Tile from a spritesheet:
img:setImage("spritesheet.png", srcX, srcY, srcW, srcH)
Flipping:
img:flip() -- flip horizontally
img:flip(true) -- flip vertically
Gradient fill (applies a gradient image to any frame or image element):
panel:applyGradient("vertical", color1, color2, color3)
panel:applyGradient("horizontal", {1,0,0,1}, {0,0,1,1})
Pre-loading images into cache:
gui.cacheImage(gui, "assets/hero.png")
gui.cacheImage(gui, {"assets/a.png", "assets/b.png"})
3.6 ImageButton
An image that responds to click events. Shows a hand cursor on hover.
local btn = parent:newImageButton("icon.png", x, y, w, h, sx, sy, sw, sh)
btn.OnReleased(function(self)
self:setImage("icon_pressed.png")
end)
3.7 Video
Plays a LÖVE-supported video file inside an element.
local vid = parent:newVideo("movie.ogv", x, y, w, h, sx, sy, sw, sh)
Playback control:
vid:play()
vid:pause()
vid:stop() -- pause + rewind
vid:rewind()
vid:seek(t) -- seek to time in seconds
vid:tell() -- returns current time in seconds
vid:getDuration()
vid:setVolume(0.8)
Events:
vid.OnVideoFinished(function(self)
print("Video ended")
end)
4. Base Object API
Every object in the hierarchy inherits the following API.
4.1 Positioning & Sizing
obj:setDualDim(x, y, w, h, sx, sy, sw, sh) -- update position/size; nil preserves current value
obj:getAbsolutes() -- returns resolved x, y, w, h in pixels
obj:getDualDim() -- returns all 8 raw values
obj:move(dx, dy) -- increment pixel offset (fires OnPositionChanged)
obj:size(dx, dy) -- increment pixel size (fires OnSizeChanged)
obj:moveInBounds(dx, dy) -- move but keep within parent bounds
obj:fullFrame() -- shorthand for 100%×100% fill
obj:centerX(true) -- auto-center horizontally within parent
obj:centerY(true) -- auto-center vertically within parent
4.2 Appearance
obj.color = {r, g, b} -- background color (0–1 range)
obj.borderColor = {r, g, b} -- border color
obj.drawBorder = true/false -- show/hide border
obj.visibility = 0.8 -- overall opacity 0–1
obj.rotation = 45 -- rotation in degrees
obj:setRoundness(rx, ry, segments) -- round all corners
obj:setRoundness(rx, ry, seg, "top") -- round top corners only
obj:setRoundness(rx, ry, seg, "bottom") -- round bottom corners only
obj.shader = myShader -- apply a LÖVE shader (image elements only)
obj.clipDescendants = true -- clip child rendering to this element's bounds
4.3 Visibility & Lifecycle
obj.visible = false -- hide (and stop receiving events)
obj.active = false -- deactivate without hiding
obj:isActive() -- true if active and not in the virtual tree
obj:isOffScreen() -- true if fully outside the window
obj:topStack() -- move to top of parent's draw order (drawn last = on top)
obj:bottomStack() -- move to bottom of draw order
obj:destroy() -- remove from tree, disconnect all events, free resources
obj:removeChildren() -- destroy all children but keep the object itself
4.4 Interaction
-- Drag support
obj:enableDragging(gui.MOUSE_PRIMARY) -- enable drag with left mouse button
obj:enableDragging(gui.MOUSE_SECONDARY) -- enable drag with right button
obj:enableDragging(false) -- disable dragging
-- Hierarchy hit-testing: only fires events when not occluded by a sibling
obj:respectHierarchy(true)
-- Tag system (used for identifying objects and filtering events)
obj:tag("myTag") -- set the primary tag (accessible via :getTag())
obj:setTag("category") -- set an arbitrary tag key
obj:hasTag("category") -- boolean
obj:parentHasTag("visual") -- checks the ancestor chain
-- Tree queries
obj:getChildren() -- immediate children table
obj:getAllChildren() -- flat list of all visible descendants
obj:isDescendantOf(other) -- boolean
obj:canPress(mx, my) -- boolean: would a click at mx,my hit this object?
-- Cloning
local copy = obj:clone()
local copy = obj:clone({copyTo = parent, connections = true})
4.5 Shape & Form Factor
By default elements are rectangles. You can change an element's form factor:
-- Circle
obj:makeCircle(x, y, radius, sx, sy, sr, segments)
-- Arc
obj:makeArc(arcType, x, y, radius, sx, sy, sr, angle1, angle2, segments)
-- arcType is a LÖVE arc type string: "open", "closed", or "pie"
The formFactor property can also be set directly:
obj.formFactor = gui.FORM_RECTANGLE -- default
obj.formFactor = gui.FORM_CIRCLE
obj.formFactor = gui.FORM_ARC
5. Events & Connections
The library uses the multi connection system. Connections are called with the syntax:
obj.OnSomeEvent(function(self, ...)
-- handler
end)
Multiple handlers can be attached to a single event. Connections can be combined:
-- OR: fires the handler if either event fires
(obj.OnReleased + obj.OnReleasedOuter)(function() ... end)
-- AND: fires the handler only when both have fired
(conn1 * conn2)(function() ... end)
5.1 Per-Object Events
| Event | Arguments | Description |
|---|---|---|
OnPressed |
self, x, y, dx, dy, istouch |
Mouse pressed inside the element |
OnReleased |
self, x, y, button, istouch, presses |
Mouse released inside the element |
OnReleasedOuter |
same | Released after a press, but outside the element |
OnReleasedOther |
same | Released with no previous press on this element |
OnPressedOuter |
self, x, y, button, istouch, presses |
Pressed outside this element |
OnEnter |
self, x, y |
Mouse moved onto the element |
OnExit |
self, x, y |
Mouse moved off the element |
OnMoved |
self, x, y, dx, dy, istouch |
Mouse moved while over the element |
OnDragStart |
self, dx, dy, x, y, istouch |
Drag began |
OnDragging |
self, dx, dy, x, y, istouch |
Drag in progress |
OnDragEnd |
self, dx, dy, x, y, istouch, presses |
Drag ended |
OnWheelMoved |
x, y |
Scroll wheel moved while cursor is over element |
OnSizeChanged |
self, ... |
Element size changed |
OnPositionChanged |
self, ... |
Element position changed |
OnDestroy |
self |
Element is being destroyed |
OnCreated |
element |
Fires for any descendant created under this element |
OnLoad |
— | Fires once when the element is first set up |
OnUpdate |
self, dt |
Fires every update frame |
Gamepad / joystick events are also available on every object:
obj.OnLeftStickUp / Down / Left / Right
obj.OnRightStickUp / Down / Left / Right
TextLabel / TextButton / TextBox extras:
obj.OnFontUpdated(function(self) end) -- font changed
input.OnReturn(function(self, text) end) -- Enter key pressed in textbox
Video extras:
vid.OnVideoFinished(function(self) end)
5.2 Global Events
All global events live under gui.Events:
gui.Events.OnKeyPressed(function(key, scancode, isrepeat) end)
gui.Events.OnKeyReleased(function(key, scancode) end)
gui.Events.OnTextInputed(function(text) end)
gui.Events.OnMouseMoved(function(x, y, dx, dy, istouch) end)
gui.Events.OnMousePressed(function(x, y, button, istouch, presses) end)
gui.Events.OnMouseReleased(function(x, y, button, istouch, presses) end)
gui.Events.OnWheelMoved(function(x, y) end)
gui.Events.OnResized(function(w, h) end)
gui.Events.OnQuit(function() end)
gui.Events.OnFilesDropped(function(x, y, files) end)
gui.Events.OnFocus(function(focus) end)
gui.Events.OnObjectFocusChanged(function(previous, current) end)
-- Gamepad / joystick
gui.Events.OnGamepadPressed(function(joystick, button) end)
gui.Events.OnGamepadAxis(function(joystick, axis, value) end)
5.3 Hotkeys
Register a hotkey and get back a connection object:
local conn = obj:setHotKey({"lctrl", "s"})
conn(function(ref)
print("Save triggered from", ref)
end)
Multiple key combinations for the same action:
local onSave = gui:setHotKey({"lctrl", "s"}) + gui:setHotKey({"rctrl", "s"})
onSave(function() save() end)
Built-in hotkeys:
| Hotkey | Connection |
|---|---|
| Ctrl+A | gui.HotKeys.OnSelectAll |
| Ctrl+C | gui.HotKeys.OnCopy |
| Ctrl+V | gui.HotKeys.OnPaste |
| Ctrl+X | gui.HotKeys.OnCut |
| Ctrl+Z | gui.HotKeys.OnUndo |
| Ctrl+Y / Ctrl+Shift+Z | gui.HotKeys.OnRedo |
| Ctrl+T | Toggle Task Manager |
6. Theming
The theme module generates consistent color palettes for use with newWindow and other themed widgets.
local theme = require("gui.core.theme")
Creating a Theme
From explicit colors:
local t = theme:new(primaryColor, primaryText, buttonText, buttonNormal, primaryFont, buttonFont)
-- Using hex strings (most convenient):
local t = theme:new("#2d6a9f", "#f0f0f0", "#ffffff")
From a table (preferred for full control):
local t = theme:new({
primary = "#124559",
primaryDark = "#01161E",
primaryText = "#AEC3B0",
buttonNormal = "#1e6f8a",
buttonHighlight = "#2a9bbf",
buttonText = "#ffffff",
textFont = myFont,
buttonTextFont = myBoldFont,
-- Any extra keys are kept and accessible on the theme object
})
Random harmonious theme:
local t = theme:random() -- any brightness
local t = theme:random(nil, "dark") -- dark palette
local t = theme:random(nil, "light") -- light palette
local t = theme:random(12345) -- reproducible from a seed
print(t:getSeed()) -- retrieve the seed
print(t:dump()) -- export as hex string
Theme Properties
| Property | Description |
|---|---|
colorPrimary |
Main background color |
colorPrimaryDark |
Darker variant (headers, accents) |
colorPrimaryText |
Text on primary backgrounds |
colorButtonNormal |
Button resting color |
colorButtonHighlight |
Button hover color |
colorButtonText |
Text on buttons |
fontPrimary |
Font for labels |
fontButton |
Font for buttons |
Applying a Theme to a Window
Pass the theme as the last argument to newWindow — the window will automatically style all child buttons and labels that are created inside it:
local win = gui:newWindow(x, y, w, h, "Title", draggable, myTheme)
7. Color Module
The color module handles color creation, conversion, and manipulation. All colors in the library are {r, g, b} or {r, g, b, a} tables with values in the 0–1 range.
local color = require("gui.core.color")
Creating Colors
-- Hex string
color.new("#ff5500")
color.new("#ff550088") -- with alpha
-- CSS-style strings
color.new("rgb(255,85,0)")
color.new("rgba(255,85,0,0.5)")
color.new("hsl(20,100,50)")
color.new("hsla(20,100,50,0.8)")
-- Raw 0–1 floats
color.new(1, 0.33, 0)
-- HSL (hue 0–360, sat 0–100, light 0–100)
color.new(color.hsl(200, 60, 40))
-- HSV (hue 0–360, sat 0–1, val 0–1)
color.new(color.hsv(200, 0.6, 0.8))
Manipulation
color.lighten(c, amount) -- amount is 0–1 factor
color.darken(c, amount)
color.saturate(c, amount)
color.desaturate(c, amount)
color.invert(c)
color.lerp(c1, c2, t) -- blend; t is 0–1
color.mix(c1, c2, t) -- alias for lerp
Queries
color.isLight(c) -- boolean
color.getAverageLightness(c) -- 0–1 float
color.rgbToHex(c) -- returns hex string without "#"
Arithmetic
Color objects support +, -, *, /, %, ^, and unary - operators, applied component-wise.
Named Colors
color.white
color.black
color.red
color.green
color.blue
color.highlighter_blue
-- (and more — check core_color.lua for the full list)
8. Transitions & Animation
The transitions module provides smooth interpolated animations for numeric values.
local transition = require("gui.elements.transitions")
Built-in Transitions
Currently transition.glide is provided — a linear glide from a start value to a stop value.
Using a Transition
A transition factory is created by calling transition.glide(start, stop, duration). This returns a factory function that, when called, starts the animation and returns a handle.
-- Animate a panel sliding in from the left
local slideIn = transition.glide(-200, 0, 0.3) -- from -200 to 0 in 0.3 seconds
local t = slideIn() -- start the animation
t.OnStep(function(position)
panel:setDualDim(position)
end)
t.OnStop(function()
print("Animation complete")
end)
Overriding Values at Runtime
The factory function accepts optional overrides:
local t = slideIn(newStart, newStop, newDuration)
Stopping Early
t.Kill()
Custom Transitions
local myTransition = transition:newTransition(function(t, start, stop, time)
-- t.fps is the target FPS for this transition
local steps = t.fps * time
local piece = time / steps
t.running = true
for i = 0, steps do
if not t.kill then
thread.sleep(piece)
-- push the current interpolated value as a status update
thread.pushStatus(start + i * ((stop - start) / steps))
end
end
t.running = false
t.kill = false
end)
Changing FPS
transition.glide:SetFPS(30) -- lower for performance-sensitive animations
9. Add-on Widgets
These widgets live in gui/addons and extend the core library.
9.1 Window
A resizable, draggable floating window with a title bar and a close button.
require("gui.addons") -- loads addons
local win = gui:newWindow(x, y, width, height, "Window Title", draggable, theme)
The returned object is the inner content frame (inside the title bar). Add children directly to win.
API:
win:setTitle("New Title")
win:close() -- moves the window to the virtual tree (hides it)
win:open() -- brings the window back to the main tree
win:setTheme(theme) -- re-apply a different theme
win:getTheme() -- returns current theme
win.OnClose(function(self)
-- fires when the X button is pressed
end)
Minimum dimensions: 200px wide, 100px tall (enforced by resize handles).
Children auto-styled: Any TYPE_BUTTON or TYPE_TEXT created inside the window automatically receives the theme's colors and fonts via the OnCreated event.
9.2 ScrollFrame
A viewport with automatic vertical and horizontal scrollbars. Returns the content frame — add children to that.
require("gui.addons")
local content = gui:newScrollFrame(x, y, w, h, sx, sy, sw, sh)
-- Add children to `content`:
local row = content:newFrame(0, rowY, 0, 30, 0, 0, 1)
Scrolling API (on the content frame):
content:scrollTo(scrollY, scrollX) -- jump to absolute scroll position
content:scrollBy(deltaY, deltaX) -- scroll by a relative amount
content:scrollToTop()
content:scrollToBottom()
content:setScrollSpeed(speed) -- default is 40 pixels per wheel tick
content:getScrollPos() -- returns scrollX, scrollY
content:getMaxScroll() -- returns maxScrollX, maxScrollY
content:setContentSize(width, height) -- explicitly set the content dimensions
The scrollbars appear automatically when the content overflows the viewport and hide when it does not.
9.3 Slide-in Menu
A panel that slides in from the left, right, or top with an animated transition.
local transition = require("gui.elements.transitions")
local menu = gui:newMenu(title, size, position, trans)
-- title : string label (required)
-- size : fractional width/height (e.g. 0.25 for 25% of screen)
-- position : gui.ALIGN_LEFT (default), gui.ALIGN_RIGHT, or gui.ALIGN_CENTER
-- trans : transition factory (default: transition.glide)
API:
menu:Open(true) -- slide open
menu:Open(false) -- slide closed
menu:isOpen() -- boolean
Example:
local sidebar = gui:newMenu("Navigation", 0.2, gui.ALIGN_LEFT)
-- Add content to the menu frame
local navBtn = sidebar:newTextButton("Home", 10, 60, 180, 40)
-- Wire toggle
toggleBtn.OnReleased(function()
sidebar:Open(not sidebar:isOpen())
end)
9.4 Video Player
A pre-built media player widget with play/pause toggle and a seek bar.
require("gui.addons")
gui:newVideoPlayer(source, x, y, w, h, sx, sy, sw, sh)
The player creates its own themed window containing the video, a play/pause button, and a progress bar.
10. Canvas
The canvas module creates full-screen root frames.
local newCanvas = require("gui.core.canvas")
local visual = newCanvas("visual") -- visual frame: non-interactive, for backgrounds/effects
local regular = newCanvas() -- regular interactive frame
Swapping child trees between canvases:
visual:swap(frameA, frameB)
-- Exchanges the children of frameA and frameB, re-parenting correctly.
-- Useful for scene transitions.
11. Simulation (Testing)
The simulate module lets you programmatically fire mouse events, useful for automated testing or scripted UI demos.
local simulate = require("gui.core.simulate")
Methods
-- Immediate (synchronous) mouse press and release
simulate:Press(button, x, y, istouch)
simulate:Release(button, x, y, istouch)
-- Async click (press then release after one scheduler tick)
simulate.Click(obj, button, x, y, istouch)
-- Animated mouse movement
simulate.Move(obj, dx, dy, x, y, istouch)
When called on an object (obj:Press()), the position defaults to the object's center. When called on simulate directly, x and y default to the current mouse position.
Example:
-- Programmatically click a button
simulate.Click(myButton)
-- Simulate a drag from one point to another
simulate.Move(nil, 100, 0, startX, startY) -- move 100px to the right
12. Scheduler Probe (Load Monitoring)
Measures scheduler responsiveness using tick-slip detection. Gives a 0–100% load estimate without blocking.
local probe = require("gui.core.probe")
probe:install(multi)
Options:
probe:install(multi, {
interval = 0.05, -- probe fires every N seconds (default: 0.05)
alpha = 0.15, -- EMA smoothing factor 0–1 (default: 0.15, lower = smoother)
maxLag = 0.5, -- seconds of lag that equals 100% load (default: 0.5)
})
Reading load:
-- Both are non-blocking — safe to call every frame
local load, lagMs = multi:getLoad()
-- load : integer 0–100
-- lagMs : smoothed scheduler lag in milliseconds
local lagMs, lagRatio = multi:getSchedulerLag()
The probe is automatically installed when gui:showTaskManager() is called.
13. Task Manager
A built-in debug overlay showing all active scheduler tasks, their state, uptime, and priority.
require("gui.addons")
gui:showTaskManager()
Default hotkey: Ctrl+T toggles it open/closed.
The task manager window provides:
- A list of all processors, threads, and tasks with live state
- Pause/Resume buttons for individual tasks
- Kill buttons to terminate tasks
- Clickable priority column to cycle a task's scheduler priority
- An Error Log tab that captures all thread errors in real-time
- A load bar showing current scheduler utilization
14. Tips & Patterns
Aspect Ratio Locking
-- Lock the root to a 16:9 canvas; letterbox on resize
gui:setAspectSize(1920, 1080)
gui.aspect_ratio = true
Clipping Children
local container = gui:newFrame(x, y, w, h)
container.clipDescendants = true -- children are scissored to container bounds
Tag-Based Queries
-- Mark a group of elements and query by tag
for _, child in ipairs(parent:getAllChildren()) do
if child:hasTag("card") then
child.color = selectedColor
end
end
Using gui.apply for Bulk Property Setting
gui.apply sets properties on multiple objects at once. It understands connection names (C_ prefix), invoke-style functions (I_ prefix), and plain properties.
gui.apply({
color = {0.2, 0.2, 0.2},
drawBorder = false,
I_enableDragging = {gui.MOUSE_PRIMARY},
OnReleased = function(self) print("clicked", self:getTag()) end,
}, btn1, btn2, btn3)
Stacking Order
Objects are drawn in the order they appear in their parent's children table. The last child is drawn on top.
obj:topStack() -- draw on top of siblings
obj:bottomStack() -- draw below all siblings
Responsive Layouts
Combine fractional scale with negative pixel offsets for padding:
-- A frame inset 10px on all sides within its parent
inner:setDualDim(10, 10, -20, -20, 0, 0, 1, 1)
Intersection Testing
local ix, iy, iw, ih = obj:intersecpt(x, y, w, h)
-- Returns the overlapping rectangle, or 0,0,0,0 if no overlap
Programmatic Focus
local focused = gui:getObjectFocus() -- the currently focused object
OnUpdate (per-frame callback)
obj:OnUpdate(function(self, dt)
-- runs every frame while the object exists
self.rotation = self.rotation + 90 * dt
end)