LWXGL’s element system is the primary way you place visible widgets on screen. Every widget — text labels, buttons, input fields, images, and more — is stored as anDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/DRESsedAlarm184/LWXGL/llms.txt
Use this file to discover all available pages before exploring further.
Element struct in a global vector and referenced by a caller-supplied integer ID. Understanding how that vector works, how IDs are assigned, and how the system cleans up is fundamental to writing correct LWXGL applications.
The Element Struct
Every widget is wrapped in an Element, defined in elements/structs.cc:
elem pointer is cast to the appropriate struct at render time and when the element is deleted. The type field determines which struct elem points to and which renderer function handles it.
Element Types
| Type ID | Name | Struct | Create Function |
|---|---|---|---|
0 | Text | TextElement | CreateText / CreateCopiedText |
1 | Button | ButtonElement | CreateButton |
2 | Input | InputElement | CreateInput |
3 | Rect | RectElement | CreateRect |
4 | Image | ImageElement | CreateImage / CreateTGAImage |
5 | Checkbox | CheckboxElement | CreateCheckbox |
6 | Console | ConsoleElement | CreateConsole |
7 | Ellipse | EllipseElement | CreateEllipse |
The elements Vector
All Element* pointers live in a global std::vector<Element*> elements. This vector is sparse: it may contain NULL entries at positions that have been deleted or never used. The vector grows on demand but never shrinks. The renderer skips NULL entries during every frame.
_allocate_element Behavior
Every Create* function calls the internal _allocate_element(id, type, data, x, y, w, h) helper, which performs two operations before inserting:
- Resize if needed — if
id >= elements.size(), the vector is extended withNULLfills up toid + 1. - Replace if occupied — if
elements[id] != NULL,DeleteElement(id)is called first, freeing the old element’s type-specific data and theElementstruct.
Element is then stored at elements[id] with v = 1 (visible) and anchor = INT_MIN (not anchored).
Because
_allocate_element calls DeleteElement on an occupied slot, creating an element at an existing ID is a safe, complete replacement — not a memory leak.Choosing Element IDs
IDs are arbitrary non-negative integers that you choose at call time. There is no auto-increment; the library never picks an ID for you. A few practical conventions:When
CreateWindow is called with FLAG_CANVAS, ID 0 is reserved for the full-window canvas ImageElement. Reserve a different ID range for your other widgets in that case.DeleteElement
id in full, then sets elements[id] = NULL. The type-specific cleanup varies:
- Text (
0) — frees the text string only if it was duplicated byCreateCopiedText(copied == true) - Button (
1), Input (2), Rect (3), Checkbox (5), Console (6) —deletethe type struct - Image (
4) — destroys theXImage, freesdataandprevpixel buffers, frees the custom font buffer if set, and callsXFreePixmapon the backing pixmap
ElemModifyBounds
-1 for w or h to leave that dimension unchanged.
ElemModifyBounds updates the Element struct directly. For ImageElement types, it does not reallocate the underlying pixmap — use UpdateImage to push new pixel data after resizing.ElemSetVisible
v flag to visible (1 = show, 0 = hide). Hidden elements are skipped by both the renderer and the ElemInside hit test, so they do not receive hover or click events. The element data is preserved; calling ElemSetVisible(id, 1) restores it to the screen unchanged.
ElemInside
1 if the current mouse position is over the element’s bounding box and the element is visible and no modal is open; returns 0 otherwise. The y check accounts for the current scroll offset, so this works correctly in scrollable windows.
For Checkbox elements the hit region is extended rightward to include the label text, mirroring the internal _inside_elem logic.
Anchoring Elements to the Scroll Position
In a scrollable window thebb back-buffer is taller than the visible viewport. Most elements scroll naturally because their y coordinates are in document space. Sometimes, however, you want an element to stay fixed in the viewport (e.g., a toolbar or a status bar at the bottom). That is what anchoring is for.
ElemAnchor
anchor = 0— removes anchoring from the listed elements, restoring each element’syto its saved pre-anchor position.anchor ≠ 0— records each element’s currentyas a viewport offset (stored ine->anchor).
ResolveAnchors
on_every callback) to update every anchored element’s y to bb.scroll + e->anchor. This keeps anchored elements pinned at their viewport offset regardless of the current scroll position.