Widgets
Widgets are the interactive elements rendered to the terminal. Each widget is an instance of a builder type, lives in a scene, and has a unique integer UID.
Builder System
Widget types are defined by builders — a polymorphic pattern implemented in C. Each builder provides five callbacks: create_state (allocate per-widget state), destroy_state (free state), handler_func (per-frame update logic), build_content (render state to pixel buffer), and on_resize (optional geometry notification).
TUIX ships four built-in builders, registered by calling builders.register_standard(). The builder constants are byte strings used when creating widgets:
| Constant | Value | Widget Type |
|---|---|---|
| builders.PROGRESSBAR | b"ProgressBarBuilder" | Animated progress bar |
| builders.CHOICE | b"ChoiceBuilder" | Selection menu |
| builders.INPUT | b"InputBuilder" | Text entry field |
| builders.CANVAS | b"CanvasBuilder" | Free-draw surface |
Creating a Widget
uid = objects.create_object(
builders.CHOICE, # builder name (bytes)
b"main", # scene name (bytes)
0.4, # width_mod: fraction of terminal width
0.5, # height_mod: fraction of terminal height
0.25, # margin_top_mod: fraction from top
0.3 # margin_left_mod: fraction from left
)All six parameters are required. The four float modifiers (width_mod, height_mod, margin_top_mod, margin_left_mod) are proportional values between 0.0 and 1.0, multiplied by the terminal dimensions each frame.
Proportional Geometry
Widget dimensions are not fixed pixel counts. They are fractions of the terminal size, resolved every frame by the geometry resolver:
buffer.width = terminal_width × object.width_mod
buffer.height = terminal_height × object.height_mod
buffer.margin_left = terminal_width × object.margin_left_mod
buffer.margin_top = terminal_height × object.margin_top_modThis means widgets automatically resize when the terminal is resized. A widget with width_mod=0.5 always occupies half the terminal width.
Accessing Widget Objects
To call widget-specific functions (set options, feed input, etc.), you need the TuixObject pointer. Retrieve it through the buffer:
buf = buffers.get_buffer_by_uid(uid)
obj = buf.contents.obj.contents
# Now use widget-specific functions
objects.tuix_choice_set_options(obj, [b"A", b"B", b"C"])Widget Lifecycle
- Create: objects.create_object() → allocates object, buffer, and registers subcycle handler
- Configure: call widget-specific set functions (set_options, set_value, set_placeholder, etc.)
- Render: engine.main_loop() resolves geometry, calls build_content, composites, renders
- Input: handled automatically in the v0.3 frame loop for built-in builders
- Query: check is_confirmed/is_submitted, get_selected/get_text/get_result
- Reset (optional): widget-specific reset() to reuse without recreating
- Destroy: buffers.free_buffer(scene, uid) to free the buffer and state
Internal Frame Handlers
Each widget has an internal handler callback that runs every frame. It controls state updates, redraw signaling, and input processing behavior for the builder. These control objects are internal implementation details in v0.3.