cleanup(theme): tokenize hardcoded slider sites (Panadapter / Eq / RadioSetup / FlexControl)#3204
Conversation
…dioSetup / FlexControl) Closes the second half of Pat's "both" answer to (a) toggle namespace work (landed as aethersdr#3198) and (b) the hardcoded-hex slider sites called out in aethersdr#3188's Out-of-scope section. The four sites bypassed the color.slider.* namespace entirely with inline `setStyleSheet(...)` calls full of hardcoded hex values, so the v2 per-applet override path couldn't reach them and theme switches required an app restart. Each migrates the colours to {{token}} form and routes through ThemeManager::applyStyleSheet so: - the per-applet override cascade lights up automatically once a relevant scope exists (none of the four currently sits under applet/tx|rx|comp, so the immediate effect at root scope is the canonical Wave-blue / accent-success treatment); - live theme switching (Dark ↔ Light without restart) re-resolves the tokens and repaints, matching the rest of the namespace-aware UI. Site-local slider DIMENSIONS are preserved intentionally — the four sites each chose bespoke handle widths / groove heights for the UX context they live in (Panadapter's tiny 8px handle for the CW bar, EqApplet's 10x16 vertical handle for band-column rhythm, RadioSetup's emphasis-sized 14px handle, FlexControl's 16px bordered ring). Homogenizing them via applyPrimarySliderStyle would have been a more literal interpretation of "drop the local stylesheet" but would have introduced visible regressions across all four sites. Option A (tokenize colours, preserve sizes) achieves Pat's stated goal — sliders honour the theme system — without the visual cost. Per-site notes: - **PanadapterApplet**: pitch min/max sliders in the CW decoder bar. Groove → color.slider.background, handle → color.slider.handle (replaces hardcoded #1a2a3a + #6a8090). Now functional in light theme (was previously stuck rendering dark-theme colours). - **EqApplet**: vertical band sliders, all 8 frequency rows. Groove → color.slider.background, handle → color.slider.foreground (the EQ visual idiom puts the accent colour on the handle itself — there is no sub-page rule, so foreground is the right token). Live theme switching adapts the accent shade between Default Dark (#00b4d8) and Default Light (#0088b0). - **RadioSetupDialog**: kFilterSlider used by the voice/cw/digital filter-sharpness sliders. Groove → color.slider.background, handle → color.slider.handle. Two other sliders in the dialog (lineoutSlider, hpSlider) already inherit from the global QSS set up in aethersdr#3188 — no migration needed there. - **FlexControlDialog**: spin + sensitivity sliders inside the dialog-wide kFlexControlStyle stylesheet. Sliders kept the FlexControl green identity by routing the sub-page fill + handle border to color.accent.success (very close to the prior hardcoded #65d379 — resolves to #4dd87a in dark, #1a8040 in light). Body widget now uses applyStyleSheet so the slider tokens resolve and the dialog body is registered for live re-theme. Out of scope — observed during testing, filed as follow-ups: - **RadioSetupDialog has broader light-theme migration debt** — kLabelStyle / kValueStyle / kGroupStyle / kEditStyle constants still hardcode dark-theme colours (#c8d8e8 labels, #00c8ff values, #304050 borders, #1a2a3a edit fields). Labels render as low-contrast pale text against the light-theme background. Beyond this slider sweep. - **FlexControlDialog has the same broader debt** — the dialog template hardcodes #0b1625 button backgrounds, #31455f borders, #65d379 FlexControl-green accents throughout. The slider rules now adapt to theme; the rest of the dialog stays dark in light theme. Beyond this slider sweep. Verification on Windows 11 (MSVC + Ninja + Qt 6.10.3) on top of aethersdr/AetherSDR main at 4ee99f7: - All 4 sites visually verified in Default Dark. - Live theme switch to Default Light — Panadapter pitch sliders + RadioSetup filter sliders adapt cleanly without restart (groove + handle gray shades flip). EqApplet bands stay accent-coloured in both themes (intentional — handle uses color.slider.foreground which resolves to the active theme's accent blue). FlexControl sliders' green sub-page stays green in both themes (the color.accent.success token IS green in both bundled themes). - theme_manager_test: zero new failures. The 4 pre-existing importThemeFromFile-related failures present on clean main remain (Windows-vs-CI env issue, not introduced here). cc @ten9876 @jensenpat @chibondking Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks Nigel — this is a clean, well-scoped follow-on to #3188 / #3198. Reviewed against AetherSDR conventions and the slider/knob namespace work that landed in #3188.
What works well
- Scope matches the title exactly — four call sites, four files, no incidental drive-bys. The intentional decision to preserve site-local sizes (handle widths / groove heights) and tokenize colours only is the right call; the per-site dimensions carry real UX intent.
- All four tokens used (
color.slider.background,color.slider.handle,color.slider.foreground,color.accent.success) resolve in both bundled themes — verified againstresources/themes/default-dark.json(lines 160-166 for slider namespace, line 44 for accent.success). - Switching
bodyWidget()->setStyleSheet(...)toThemeManager::applyStyleSheet(...)inFlexControlDialog.cpp:990-997is the right shape — registers the body widget for live re-theme without changing its lifetime semantics. - The choice to route FlexControl's green identity through
color.accent.successrather than introducing a newcolor.toggle.success.*token here keeps the slider sweep tightly scoped while still letting a future FlexControl-tribe carve-out retint cleanly. - Honest scope discipline on the call-outs in "Observed during testing" — flagging
RadioSetupDialoglabel/value/group/edit hardcoded colours and the broader FlexControl dialog migration debt as separate follow-ups rather than scope-creeping this PR is the right call.
Conventions check
- RAII / Qt parent ownership: untouched, all slider widgets retain their existing parenting through layout addition.
- No
QSettings/AppSettingsinteraction in scope. - No new error paths at system boundaries —
applyStyleSheetis the established path and handles missing tokens at the resolver level. - No null deref risk;
bodyWidget()is non-null by the timeFlexControlDialogconstructor reaches line 990.
One observation, not a request
The EqApplet handle uses {{color.slider.foreground}} rather than {{color.slider.handle}} — your PR description calls this out explicitly ("the EQ slider's visual idiom puts the accent colour on the handle itself"), and the in-file comment (EqApplet.cpp:79-86) documents the why. Worth noting that if EqApplet ever lands under applet/tx / applet/rx / applet/comp scope, the handle would retint to red/green/amber via the existing scope override — that's likely the intended cascade behaviour and matches the rest of the namespace, just flagging that it's a different cascade target than the other three sites in this PR.
Approving the design direction; no blockers from my read. 🟢
🤖 aethersdr-agent · cost: $9.4588 · model: claude-opus-4-7
Closes the second half of Pat's "both" answer to (a) the toggle namespace work (landed as #3198) and (b) the hardcoded-hex slider sites called out in #3188's Out of scope section.
Background
#3188 tagged four sites as bypassing the
color.slider.*namespace entirely:Each site used inline
setStyleSheet(...)calls full of hardcoded hex values — so the v2 per-applet override path couldn't reach them, and theme switches required an app restart. This PR tokenizes the colours and routes throughThemeManager::applyStyleSheetso:applet/tx|rx|comp, so the immediate effect at root scope is the canonical Wave-blue / accent-success treatment);Approach — Option A (tokenize colours, preserve sizes)
Site-local slider dimensions are preserved intentionally — the four sites each chose bespoke handle widths / groove heights for the UX context they live in (Panadapter's tiny 8px handle for the CW bar, EqApplet's 10×16 vertical handle for band-column rhythm, RadioSetup's emphasis-sized 14px handle, FlexControl's 16px bordered ring).
Homogenizing them via
applyPrimarySliderStylewould have been a more literal interpretation of "drop the local stylesheet" but would have introduced visible regressions across all four sites. Option A (tokenize colours, preserve sizes) achieves Pat's stated goal — sliders honour the theme system — without the visual cost.Per-site notes
PanadapterApplet.cpp#1a2a3agroove →{{color.slider.background}}#6a8090handle →{{color.slider.handle}}EqApplet.cpp#203040groove →{{color.slider.background}}#00b4d8handle →{{color.slider.foreground}}(the EQ idiom puts the accent colour on the handle itself — no sub-page rule)RadioSetupDialog.cpp#1a2a3agroove →{{color.slider.background}}#c8d8e8handle →{{color.slider.handle}}(
lineoutSlider+hpSlideralready inherit from the global QSS — no migration needed)FlexControlDialog.cppkFlexControlStyletemplate#162437groove →{{color.slider.background}}#65d379sub-page →{{color.accent.success}}(preserves FlexControl green identity)#d8e2efhandle →{{color.slider.handle}}#65d379handle border →{{color.accent.success}}Body widget switched to
applyStyleSheetso the tokens resolve + live re-theme registersVerification
Windows 11 (MSVC + Ninja + Qt 6.10.3) on top of
aethersdr/AetherSDRmain at4ee99f78.#0088b0)color.accent.successwhich is green in both bundled themes; gray shades adapt around it)theme_manager_test: zero new failures. The 4 pre-existingimportThemeFromFile-related failures on clean main remain (Windows-vs-CI env issue, not introduced here).Observed during testing — out of scope for this PR
While verifying in Default Light, two broader migration debt items came to light that go beyond this slider sweep:
RadioSetupDialoglight-theme contrast —kLabelStyle(color: #c8d8e8),kValueStyle(color: #00c8ff),kGroupStyle(border#304050, title#8aa8c0), andkEditStyle(background#1a2a3a) all hardcode dark-theme colours. Labels render as low-contrast pale text against the light-theme#f5f5f8background, and edit fields look misplaced. Migrating those constants needs the same{{token}}+applyStyleSheetpattern and touches dozens of call sites across the dialog — a separate follow-up PR.FlexControlDialogwhole-dialog migration debt — the dialog template hardcodes#0b1625button backgrounds,#31455fborders,#65d379FlexControl-green accents throughout. The slider rules now adapt to theme; the rest of the dialog stays dark in light theme. A separate "FlexControl light-theme migration" PR would close this; touching it here would have ballooned the slider-cleanup scope.Both observations were flagged as candidates for the next cleanup sweep that follows this one.
Together with #3198
This PR completes Pat's "both" answer. With #3198 (toggle namespace carve-out) and this PR (slider site cleanup) merged, the four originally-cited problem sites from #3188's Out-of-scope section all become theme-system-aware and the toggle button class joins the slider + knob namespace pattern as a third carved-out widget type.
cc @ten9876 @jensenpat @chibondking
73 Nigel G0JKN
🤖 Generated with Claude Code