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.
New in 1.5.2 The active card's outline follows the tint too. card_outline(alpha) returns the tint washed 30 %
towards white on dark (12 % on light, _OUTLINE_WASH) at 90 % opacity, or grey (_OUTLINE_GREY) with No colour
and in incognito spaces. WebCard draws it 2 px wide around the active card, and at 60 % (and 14 % as the header
fill) for cards selected together. Earlier versions used the accent blue.
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.