widgets

tape
@profile(t2);
import ui from "ui";
import widgets from "widgets";

var volume: i64 = 50;
fn on_save() { }
fn on_volume(v: i64) { volume = v; }

component Settings {
    view {
        ui.Column {
            widgets.Label { text: "Volume"; fg: #FFFFFF; }
            widgets.Slider { min_val: 0; max_val: 100; value: 50; on_change: on_volume; }
            widgets.Button { label: "Save"; bg: #368CE2; on_click: on_save; }
        }
    }
}

Every widget also takes width, height and grow, its size in a ui.Column or ui.Row (Column and Row). With grow: 0 a widget takes its own size: a Label its text’s, a Button its label’s, a Checkbox its box and label, a TextInput its text’s (at least 80 pixels), an Image its picture’s, a Slider 120 x 20 and a ProgressBar 120 x 8.

Every prop has a default: leave a color at its zero value (#00000000), or a size at 0, and the widget paints it with the active theme, which theme.set can switch while the program runs. To set props for many widgets at once, write a #style rule.

WidgetPropsEvents
Labeltext: string, fg, size (default: the theme’s, 14)
Buttonlabel: string, bg (set: a colored button in that color), fg, border, text_size; states hovered, active, disabledon_click()
TextInputvalue: string, placeholder: string, bg, fg, border_color, text_size; states hovered, focusedon_change(value: []const u8), on_submit(value: []const u8)
Checkboxchecked: bool, label: string, text_color, check_color, text_size; states hovered, activeon_toggle(new_checked: bool)
Slidermin_val, max_val, value, bg, track_color, thumb_color; states hovered, activeon_change(new_value: i64)
ProgressBarvalue, max_value (default 100), bg, fill_color
Panelbg, border
Scrollabledirection: ScrollDir, content_w, content_h
Imagesrc: *gfx.Surface (from image), bg

The look of a state

Each color prop of a widget with states has a variant per state, named <state>_<prop>: the color while that state is on. Left at zero, the theme’s look for that state is used.

WidgetState props
Buttonhovered_bg, hovered_fg, hovered_border, active_bg, active_fg, active_border (the ring while pressed), disabled_bg, disabled_fg, disabled_border
TextInputhovered_bg, hovered_fg, hovered_border_color, focused_bg, focused_fg, focused_border_color
Checkboxhovered_text_color, hovered_check_color, active_text_color, active_check_color
Sliderhovered_bg, hovered_track_color, hovered_thumb_color, active_bg, active_track_color, active_thumb_color
tape
widgets.Button { label: "Delete"; bg: #B03030; hovered_bg: #C04040; active_bg: #902020; }

With transition: 150 (milliseconds) a widget fades to a state’s colors instead of switching, along transition_ease (widget transitions).

When two states are on, the stronger one shows: disabled over active (pressed) over hovered, and focused over hovered. In a #style rule the same is written :hovered { bg: #C04040; }.

  • A Button fires on_click when pressed and released inside it.
  • A TextInput takes focus when clicked; it edits with the arrow keys, Home, End, Backspace and Delete (Shift selects), fires on_change after each edit and on_submit on Return. The text it hands over is valid during the handler: copy it ("{value}") to keep it.
  • Its value prop is the text to show. Bound to a var whose generated setter on_change calls, the field is controlled: widgets.TextInput { value: query; on_change: set_query; } keeps query and the field in step. When value changes from outside (code assigns query), the field adopts the new text and keeps the caret, clamped to the new length. Inside the component, text() is the text being edited.
  • Checkbox and Slider report what the user asked for and leave the value to you: store it and pass it back as the prop.

Test a form without a window with ui.headless.

Last modified: