The widget set
The retained widget tree
A widget is a node in a retained tree with two-phase layout: measure (how big do I want to be, given an available width) then arrange (here is your final rect). A WidgetView hosts the tree inside a region, lays it out, draws it, and routes events with a capture slot for modal drags and a focus slot for typing.
struct Widget {
virtual Size measure(const Theme&, float availW) = 0;
virtual void arrange(const Theme&, Rect);
virtual void draw(gpu::Canvas&, const Theme&) = 0;
virtual bool handle(const Event&) { return false; }
};
The control set
The toolkit ships a full control set, each drawn through the theme (no hardcoded colours) and acting on synthesized intent:
- Buttons & inputs:
Button,IconButton,Checkbox,Toggle,IconToggle,Slider,NumberField(drag-to-scrub or click-to-type),TextField,SearchField,Stepper. - Choosers:
Dropdown,RadioGroup,SegmentedControl,ColorSwatch(opens a colour picker). - Chrome:
Title,Separator,StatusBar,ProgressBar,Toolbar,TabBar,MenuBar. - Overlays:
MenuPopup(with cascading submenus, shortcut hints, option boxes), context menus,DialogPopup(modal),ColorPickerPopup. - Rich: lists, trees and tables, an editable text editor, and curve/ramp editors.
Construction without ceremony
Widgets are built through the Build.h factories so a tree is one readable expression: containers take their children directly, leaves configure up front, and the factories handle ownership and conversion so the call site stays clean:
auto panel = column(
title("Transform"),
field("Position", numberField(0.0f)),
field("Visible", checkbox(true)),
row(flex(button("Cancel"), 1), flex(button("Apply"), 2)));
flex(child, weight) weights a row child; cfg(widget, fn) tweaks any extra knob in place. This parsimony is the toolkit's house style: the common case is short, and the easy way is the safe way.
Acting on intent
Momentary controls fire on a clean Click (press + release with no drag), so pressing a button and dragging away cancels it, the desktop-correct behaviour. Drags begin on the first Drag event past the threshold (a NumberField scrub, a list reorder). Because the event-value model synthesizes this uniformly, every widget agrees on what a click is. Hover, active and focused states are tracked per widget and drawn through the theme, so the whole set restyles at once when the theme changes.
A NumberField scrub reads the modifier chord the way a desktop slider does: Shift engages fine precision (the per-pixel step shrinks, smoothly and jump-free, even when you press Shift mid-drag), Ctrl snaps the value to a discrete increment, and Alt-click resets the field to its declared default — so dragging in a precise number is practical, not just an approximation.