Skip to content

feat(theme): Phase 2 pilot — migrate ComboStyle to applyStyleSheet + tokens#3087

Merged
ten9876 merged 1 commit into
mainfrom
auto/theme-phase2-pilot-combostyle
May 25, 2026
Merged

feat(theme): Phase 2 pilot — migrate ComboStyle to applyStyleSheet + tokens#3087
ten9876 merged 1 commit into
mainfrom
auto/theme-phase2-pilot-combostyle

Conversation

@ten9876

@ten9876 ten9876 commented May 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

First real consumer of the RFC #3076 Phase 2 theming infrastructure. Migrates src/gui/ComboStyle.h — the central styling helper for every QComboBox in AetherSDR — from hardcoded hex to canonical token references via `ThemeManager::applyStyleSheet`.

Why ComboStyle as the pilot

  • High leverage: `applyComboStyle()` is called from 20+ sites (AppletPanel, RadioSetupDialog, PhoneCwApplet, RxApplet, StripEqPanel, WaveApplet, SpectrumOverlayMenu, …) — one function migrated themes them all.
  • Small surface: single 54-line header, easy to review and rollback.
  • Covers both code paths: stylesheet template + paint-code QColor literal (the arrow PNG), exercising both `resolve()` and direct `ThemeManager::color()` lookup.

Migration details

Hex → tokens:

Was Now
`#1a2a3a` `{{color.background.1}}`
`#c8d8e8` `{{color.text.primary}}`
`#304050` `{{color.background.2}}`
`#00b4d8` `{{color.accent}}`
`QColor(0x8a, 0xa8, 0xc0)` `ThemeManager::color("color.text.secondary")`

Routing: `applyComboStyle` now calls `ThemeManager::applyStyleSheet` instead of `combo->setStyleSheet`. Combos get free live re-theme on theme change via the widget-tracked reverse-map (PR #3085).

Arrow PNG cache: filename now includes the resolved `text.secondary` hex so each theme variation gets its own cached arrow (`/tmp/aethersdr_combo_arrow_.png`).

SpectrumOverlayMenu.cpp: two direct calls to `comboStyleSheet()` (the underlying-now-removed helper) converted to `applyComboStyle()`.

Tradeoff documented inline

`applyComboStyle` installs two connections on `themeChanged`:

  1. The reverse-map's automatic re-apply (from feat(theme): Phase 2 widget→tokens reverse-map + live re-theme on change #3085)
  2. An explicit refresh lambda that regenerates the arrow URL

The double-apply is wasteful but small. The arrow URL has to be computed at apply time (it's a filesystem path that depends on the resolved colour), not a `{{token}}` placeholder. Phase 5 could introduce a "computed token" mechanism if combos become a hot path.

QPointer guards the lambda against widget destruction between the connection and the next theme change.

Verified locally

  • Linux build clean (all 20+ call sites still resolve)
  • AetherSDR binary launches without crash (offscreen QPA, 3s smoke test)
  • No visible diff expected today — resolved colours match the previous hardcoded values exactly

Stacking note

This PR is based on `auto/theme-phase2-widget-map` (PR #3085) because it consumes `ThemeManager::applyStyleSheet` which only exists there. When #3085 merges, this rebases cleanly to a single-commit diff against main.

Test plan

73, Jeremy KK7GWY & Claude (AI dev partner)

🤖 Generated with Claude Code

@ten9876 ten9876 requested a review from a team as a code owner May 24, 2026 23:55
Base automatically changed from auto/theme-phase2-widget-map to main May 25, 2026 00:05
@ten9876 ten9876 requested a review from a team as a code owner May 25, 2026 00:05
…tokens

First real consumer of the RFC #3076 Phase 2 theming infrastructure.
ComboStyle.h is the central styling helper for every QComboBox in
AetherSDR — applyComboStyle() is called from 20+ sites (AppletPanel,
RadioSetupDialog, PhoneCwApplet, RxApplet, StripEqPanel, WaveApplet,
SpectrumOverlayMenu, etc.).

What changed:
  - Hardcoded hex (#1a2a3a, #c8d8e8, #304050, #00b4d8) replaced with
    canonical token references: {{color.background.1}},
    {{color.text.primary}}, {{color.background.2}}, {{color.accent}}.
  - QColor(0x8a, 0xa8, 0xc0) in the arrow PNG replaced with
    ThemeManager::color("color.text.secondary").
  - applyComboStyle() now routes through ThemeManager::applyStyleSheet
    so every combo gets free live re-theme on theme change (registered
    in the widget-tracked reverse-map for the Phase 5 inspector).
  - SpectrumOverlayMenu.cpp's two direct calls to comboStyleSheet()
    converted to applyComboStyle() — the underlying helper is gone.
  - Arrow PNG cache key now includes the resolved text.secondary hex
    so each theme variation gets its own cached arrow without stomping.

Tradeoff documented inline: applyComboStyle installs TWO connections
on themeChanged — the reverse-map's automatic re-apply, plus an
explicit refresh to regenerate the arrow URL (since the URL is
computed at apply time, not a {{token}} placeholder).  The double-
apply is wasteful but small; Phase 5 could introduce a "computed
token" mechanism if combos become a hot path.  QPointer guards
against widget destruction between the connection and the next
themeChanged.

Verified locally: Linux build clean (all 20+ call sites still resolve),
binary launches without crash.  No visible diff expected today —
the resolved colours match the previous hardcoded values exactly.

Visible payoff arrives when the user switches themes: every combo
re-themes simultaneously without any per-call-site plumbing.  Phase
4's Default Light theme will demonstrate this end-to-end.

Stacked on top of #3085 (applyStyleSheet infrastructure) — when
that lands the pilot rebases cleanly to a single-commit diff against
main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ten9876 ten9876 force-pushed the auto/theme-phase2-pilot-combostyle branch from 2c034f1 to ced96f1 Compare May 25, 2026 00:06
@ten9876 ten9876 merged commit 8d4cc53 into main May 25, 2026
8 checks passed
@ten9876 ten9876 deleted the auto/theme-phase2-pilot-combostyle branch May 25, 2026 00:31
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
…tokens (aethersdr#3087)

## Summary

First real consumer of the RFC aethersdr#3076 Phase 2 theming infrastructure.
Migrates [src/gui/ComboStyle.h](src/gui/ComboStyle.h) — the central
styling helper for every QComboBox in AetherSDR — from hardcoded hex to
canonical token references via \`ThemeManager::applyStyleSheet\`.

## Why ComboStyle as the pilot

- **High leverage:** \`applyComboStyle()\` is called from 20+ sites
(AppletPanel, RadioSetupDialog, PhoneCwApplet, RxApplet, StripEqPanel,
WaveApplet, SpectrumOverlayMenu, …) — one function migrated themes them
all.
- **Small surface:** single 54-line header, easy to review and rollback.
- **Covers both code paths:** stylesheet template + paint-code QColor
literal (the arrow PNG), exercising both \`resolve()\` and direct
\`ThemeManager::color()\` lookup.

## Migration details

**Hex → tokens:**
| Was | Now |
|---|---|
| \`#1a2a3a\` | \`{{color.background.1}}\` |
| \`#c8d8e8\` | \`{{color.text.primary}}\` |
| \`#304050\` | \`{{color.background.2}}\` |
| \`#00b4d8\` | \`{{color.accent}}\` |
| \`QColor(0x8a, 0xa8, 0xc0)\` |
\`ThemeManager::color(\"color.text.secondary\")\` |

**Routing:** \`applyComboStyle\` now calls
\`ThemeManager::applyStyleSheet\` instead of \`combo->setStyleSheet\`.
Combos get free live re-theme on theme change via the widget-tracked
reverse-map (PR aethersdr#3085).

**Arrow PNG cache:** filename now includes the resolved
\`text.secondary\` hex so each theme variation gets its own cached arrow
(\`/tmp/aethersdr_combo_arrow_<hex>.png\`).

**SpectrumOverlayMenu.cpp:** two direct calls to \`comboStyleSheet()\`
(the underlying-now-removed helper) converted to \`applyComboStyle()\`.

## Tradeoff documented inline

\`applyComboStyle\` installs **two** connections on \`themeChanged\`:
1. The reverse-map's automatic re-apply (from aethersdr#3085)
2. An explicit refresh lambda that regenerates the arrow URL

The double-apply is wasteful but small. The arrow URL has to be computed
at apply time (it's a filesystem path that depends on the resolved
colour), not a \`{{token}}\` placeholder. Phase 5 could introduce a
"computed token" mechanism if combos become a hot path.

QPointer guards the lambda against widget destruction between the
connection and the next theme change.

## Verified locally

- [x] Linux build clean (all 20+ call sites still resolve)
- [x] AetherSDR binary launches without crash (offscreen QPA, 3s smoke
test)
- [x] No visible diff expected today — resolved colours match the
previous hardcoded values exactly

## Stacking note

This PR is based on \`auto/theme-phase2-widget-map\` (PR aethersdr#3085) because
it consumes \`ThemeManager::applyStyleSheet\` which only exists there.
When aethersdr#3085 merges, this rebases cleanly to a single-commit diff against
main.

## Test plan

- [ ] CI green on the dependent aethersdr#3085 first
- [ ] CI green here after rebase
- [ ] Visual smoke: launch app, open Radio Setup dialog, confirm every
combo box (profile picker, RCA/ACC, mic source dropdowns) renders
identically to v26.5.3
- [ ] After Phase 4 Light theme lands: confirm theme switch repaints
every combo simultaneously without a restart

73, Jeremy KK7GWY & Claude (AI dev partner)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant