Back to Projects
TUIX v0.3Beta

Last Updated: 2026-05-20

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:

ConstantValueWidget Type
builders.PROGRESSBARb"ProgressBarBuilder"Animated progress bar
builders.CHOICEb"ChoiceBuilder"Selection menu
builders.INPUTb"InputBuilder"Text entry field
builders.CANVASb"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_mod

This 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

  1. Create: objects.create_object() → allocates object, buffer, and registers subcycle handler
  2. Configure: call widget-specific set functions (set_options, set_value, set_placeholder, etc.)
  3. Render: engine.main_loop() resolves geometry, calls build_content, composites, renders
  4. Input: handled automatically in the v0.3 frame loop for built-in builders
  5. Query: check is_confirmed/is_submitted, get_selected/get_text/get_result
  6. Reset (optional): widget-specific reset() to reuse without recreating
  7. 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.

Focus Routing (v0.3)v0.3 supports scene-level focus routing. When multiple interactive widgets are present, use scenes.set_focus(scene_name, uid) to select which widget should handle keyboard input. Use scenes.set_previous_focus(scene_name) to restore the previous target.