Settings > Video > Appearance gains Custom: <name> entries and Customize..., a theme editor that starts
from Dark or Light and edits eleven semantic colours (home background, window, inputs, text, muted,
accent, warning, error, success, hardcore, card), the rounding and the spacing, with a live preview and a
warning list when a text pair falls below 4.5:1 (3:1 on a hovered control). Save, Duplicate, Delete,
Export... and Import... (a validated file: bad colours, out-of-range numbers and files that are not themes
are refused with a message; unknown keys are ignored, missing colours fall back to the base).
- theme_custom.{h,cpp}: the Custom theme, the palette derived from it, the file format
(<data>/themes/<name>.ini, atomic writes, 64 KiB limit, names sanitised to a safe file name) and the Store.
A secondary copy of the app (#902) reads the folder and cannot change it.
- theme_style.cpp: the Dear ImGui colours derived from the few the theme has; rounding and spacing at the
UI scale (identical to ScaleAllSizes at the defaults). Fonts are never touched, so a font setting composes.
- ui.theme = custom:<name>; a missing theme file falls back to System. --theme custom:NAME for one run.
- theme_unit: choice and listeners, file round trip, import validation, the store, warnings, derived style.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Theme = System (default) / Dark / Light, saved as ui.theme and reset with the Video group.
System uses SDL_GetSystemTheme() and re-applies live on SDL_EVENT_SYSTEM_THEME_CHANGED.
- theme.{h,cpp}: the choice, the scheme in force, a palette per scheme (warning, error, success,
muted text, card, home background, ...) and one overlay palette for what sits on the game picture.
theme::isDark() and theme::addListener() let other code (a Windows title bar) follow the theme.
- theme_style.{h,cpp}: the Dear ImGui style colours for both schemes. Only Colors[] are touched,
so DPI scaling and rounding survive a switch. The light style keeps the dark one's blue accent.
- ~85 hard-coded colours on 66 lines routed through the palette (library tiles, cards, badges,
stars, BIOS tiles, state boxes, achievements, netplay, cheats, remap, shaders, welcome screen).
Kept as they were: the black letterbox behind a game and the white image tints.
- In-game overlays (controls sheet, OSD, toasts, trackers, frame rate) stay dark-translucent in both
themes, with a little more opacity so they hold 4.5:1 over a white game frame; the frame rate
gets a backing chip. Dark theme: TextDisabled and the muted text lightened to clear 4.5:1.
- --theme system|dark|light for one run (not saved).
- theme_unit: selection logic, the theme-changed event, and WCAG contrast of the palette, the applied
style and the overlays (white and black frames).
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>