Themes & scale

A theme is data, not code

Every widget draws through a Theme — it never hardcodes a colour or a metric. A theme is data: one renderer (DataTheme) draws every widget from a ThemeData of fonts, metrics, a style mode, and a palette. Swap the data and the whole interface re-skins, live, with no widget code changed.

auto flat  = ui::makeFlatTheme(font.get());                 // built-in dark palette
auto irix  = ui::makeThemeFromFile(device, "irix.theme", scale);   // loaded from disk
view->setTheme(irix.get());                                  // re-skins immediately

Plain-text .theme files

A theme can live in a plain-text file of dotted key = value lines (with # comments and #RRGGBB[AA] colours), so designing a look is editing a file, not recompiling:

style.mode   = bevel          # bevel (Motif/IRIX) · rounded (flat) · square
font         = Helvetica
font.px      = 12
color.panel  = #2b2f2b
color.accent = #4772b3
color.text   = #e8ece8

The same widget tree renders as a flat dark theme, a retro beveled one, or a pixel-art skin purely by which ThemeData it is handed. The style mode changes how chrome is drawn (beveled vs rounded vs square); the palette and metrics fill in the rest.

Semantic colours

The palette is semantic, not a grab-bag: panel, accent, text, selectionText, rowHover, outline, gridLine, and so on. Widgets ask for the role they mean (t.selectionTextColor()), which is why a theme with a light accent still renders readable selected text — a class of bug that hardcoded white text would cause. Node-graph colours (nodeHeader, wire, socket) are part of the same data, so a node editor re-skins with everything else.

One scale factor

uiScale is a single number that scales every metric and font size together — the desktop "UI scale" setting. Metrics return base × uiScale; font sizes round to points × uiScale; and because the FontBook rasterizes at the requested size rather than scaling a bitmap, text stays crisp at any scale. ⌘= / ⌘− live-scale the whole UI in the Editor.

The upshot: look and density are configuration, owned by a file a designer can edit, not constants buried in widget code — which is exactly the separation the example apps lean on (Prism Pixel ships the pixel theme; the Editor defaults to a Blender-inspired dark one).