Theming, materials and colour tints
Theme (ui/theme.py) turns a few settings into a
palette of named colour tokens that every widget paints with. There is one instance, returned by theme().
Tokens#
DARK and LIGHT map token names to colours, many of them translucent so the backdrop shows through:
| Token | Used for |
|---|---|
window, sidebar, canvas, card, panel, dialog, layer |
surfaces (translucent) |
*_solid (sidebar_solid, card_solid, …) |
the same surfaces when the material is Solid |
text, text2, text3 |
primary, secondary and tertiary text |
hover, pressed, selected, card_hover |
interaction states |
divider, card_border, input, input_border, focus_ring, shadow, scrim |
lines and effects |
danger, warning, success, sleep |
status colours |
window_tint |
the wash painted over the backdrop |
accent |
the Windows accent colour (or JBrowser blue), adjusted for contrast |
th = theme()
p.fillPath(path, th.surface("card")) # the *_solid variant when the material is Solid
p.setPen(th.c("text2"))
p.setBrush(th.accent_alpha(0.16))
theme().changed fires after every recalculation; widgets repaint on it. Theme.apply() also sets the
application palette and a small style sheet for standard Qt widgets (scroll bars, menus, inputs).
What decides the colours#
refresh() runs at start-up, when the Windows colour scheme changes, and when one of appearance.theme,
appearance.use_accent, appearance.material, appearance.tint changes:
- Dark or light:
appearance.theme(system,dark,light);systemfollows Windows. An incognito space forces dark. - Accent: the Windows accent colour (
appearance.use_accent), lightened on dark or darkened on light when it would lack contrast. - Material:
appearance.material=acrylic(default),mica,mica_altorsolid. With a translucent material,theme().translucentisTrue: the window paints transparent pixels and DWM draws the system backdrop behind them. Solid paints the opaque*_solidtokens instead. - Colour tint and incognito (below).
Colour tints#
New in 1.5.0 TINTS defines ten colours (rose, coral, amber, lime, mint, teal, sky, indigo, violet, slate);
appearance.tint is one of their keys or "none". A tint must stay a tint, never a paint job:
- Over Acrylic or Mica, the tint becomes
window_tint, a wash at 15 % opacity (dark) or 10 % (light) (_WASH_ALPHA), whichRootWidgetpaints over the transparent backdrop.backdrop_wash()returns it. - With Solid, each opaque surface is mixed towards the tint by an amount per token (
_SOLID_MIX: 20 % for the window, 24 % for the sidebar, down to 5 % for cards) withmix(), so text contrast stays intact.
The picker is TintPicker in ui/widgets.py: a keyboard-accessible row of swatches
(arrow keys move, the choice applies live) used by Settings and the welcome's Look page.
Incognito is black#
When the active space is incognito, MainWindow calls theme().set_incognito(True). The theme then forces dark,
ignores the tint, and overlays _INCOGNITO: near-black solid surfaces and a 62 % black wash over the backdrop, so
an incognito window is unmistakable. Switching to a normal space restores the chosen look.
Fonts#
The UI uses Segoe UI (UI_FONT), and the Segoe UI Variable Display family for large text where available. Icons are
Segoe Fluent Icons glyphs (with a Segoe MDL2 Assets fallback), so no image files are needed.
Changing the look#
- New colour: add a token to both
DARKandLIGHT(and a*_solidvariant if it is a surface), then useth.c("token"). - Never hard-code colours in widgets, except fixed brand colours such as space colours.
- Test both themes, all four materials, a tint and an incognito space.