refactor(gui): consolidate 8 divergent primary-slider styles into one Theme.h helper#3118
Merged
Conversation
… Theme.h helper
Pre-consolidation the codebase had eight near-duplicate QSlider stylesheet
constants across the applet family, each with subtle differences:
TxApplet / PhoneApplet / PhoneCwApplet / RxApplet cyan handle, no fill
WaveApplet sub-page + bordered handle
AetherDspWidget / DspParamPopup hover-cyan, distinct groove
VfoWidget plain light, third groove bg
SpectrumOverlayMenu two more local variants
StripFinalOutputPanel / StripWaveformPanel themed amber sub-page
PanadapterApplet (CW sens) partially themed cyan
Operator-visible drift: same slider widget, different look in three
adjacent applets. Maintainability drift: a Phase 4 light-theme tweak to
"slider handle colour" would have to touch nine separate stylesheet
literals.
This commit picks the canonical look:
Sub-page fill (Wave-style value indicator) +
Plain light handle (Vfo-style, no border, no hover)
…and exposes it through one helper:
Theme::primarySliderStyleTemplate(accentToken = "color.accent")
Theme::applyPrimarySliderStyle(slider, accentToken = "color.accent")
applyPrimarySliderStyle() routes through ThemeManager::applyStyleSheet()
so the slider gets:
* Token-resolved {{color.background.1}} groove
* {{color.accent}} (or caller-supplied token) sub-page fill
* {{color.text.primary}} handle
* Free live re-theme on theme change via the reverse-map
* Both horizontal and vertical orientation rules
Variant tokens — the two transmit-adjacent Strip panels pass
"color.accent.warning" for the amber sub-page that signals TX state.
Same shape, different colour token; no per-call-site stylesheet needed.
## Files migrated (13)
Theme.h + helpers, updated default QSlider
rules in appStylesheetTemplate()
TxApplet / PhoneApplet / collapse kSliderStyle const,
PhoneCwApplet / RxApplet swap setStyleSheet → applyPrimarySliderStyle
WaveApplet / DspParamPopup /
VfoWidget / AetherDspWidget /
SpectrumOverlayMenu /
PanadapterApplet (CW sens)
StripFinalOutputPanel / same migration; amber variant via
StripWaveformPanel accentToken parameter
Two slider sites left intentionally untouched:
* PanadapterApplet Lo/Hi range sliders — deliberate visual
de-emphasis for secondary range controls; tiny gray handle is
a load-bearing visual cue, not drift.
* MeterSlider — already its own widget for VU/level meters with
its own canonical style (handled in #3106).
## Build verified clean
AetherSDR (615 ninja steps) + all 320 targets including every test.
73, Jeremy KK7GWY & Claude (AI dev partner)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…der borders Two follow-ups to #3118 from Jeremy's smoke test: 1. **Pan / balance sliders now fill from the centre outward.** The L↔R pan in RxApplet and the L↔R balance in VfoWidget both use CenterMarkSlider, whose neutral position is the midpoint of the range. The default stylesheet sub-page rule paints (0 → handle), which reads visually wrong on a centre-anchored control — a value slightly left of centre lit up the whole left half of the groove. CenterMarkSlider::paintEvent now over-paints the unwanted half of the sub-page with the groove colour (effectively erasing it) and adds the (centre → handle) accent fill when the handle sits left of centre. Clipping excludes the handle pixel disc so the overpaint never bleeds into it. The fill resolves through ThemeManager so it tracks theme switches for free, same as every other primary slider in the codebase. 2. **All remaining `QSlider` border styling is now explicitly suppressed.** The pre-consolidation SpectrumOverlayMenu had `QSlider { border: none; }` in its local kSliderStyle to kill the platform-style 1-px border that shows up on some themes. Dropping that line during the #3118 sweep re-introduced visible borders on the FFT AVG / FPS / Line / Fill / Floor / NB Blank / Black Level / Wtrfall Gain / Wtrfall Rate / BG Opacity sliders in the Spectrum Overlay Display tab. Theme::primarySliderStyleTemplate() and the QSlider section of appStylesheetTemplate() both now include `border: none;` on the QSlider element itself + on every subcontrol (groove / sub-page / add-page / handle) so the rule wins regardless of which platform style is providing the default. The CenterMarkSlider class is currently duplicated between RxApplet.cpp and VfoWidget.cpp; both copies got the identical fix. Consolidating into a single shared header is reasonable cleanup but orthogonal to the fix — keeping it for a follow-up. 73, Jeremy KK7GWY & Claude (AI dev partner) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
G6PWY-Chris
pushed a commit
to G6PWY-Chris/AetherSDR
that referenced
this pull request
Jun 22, 2026
… Theme.h helper (aethersdr#3118) ## Summary Pre-consolidation the codebase had **eight near-duplicate \`QSlider\` stylesheet constants** scattered across the applet family. Same slider widget, different look in three adjacent applets: | Style | Files | Distinctive properties | |---|---|---| | A — Cyan handle | TxApplet, PhoneApplet, PhoneCwApplet, RxApplet | groove \`#203040\`, handle 10×10 \`#00b4d8\`, no fill | | B — Sub-page + bordered | WaveApplet | sub-page cyan, handle 12×12 light + cyan border | | C — Hover-cyan | AetherDspWidget, DspParamPopup | groove \`#304050\`, handle 12×12 light, hover→cyan | | D — Plain light | VfoWidget | groove \`#1a2a3a\`, handle 12×12 light, no hover | | E — Themed cyan | PanadapterApplet (CW sens) | already token-based but cyan-handle look | | F — Themed amber | StripFinalOutputPanel, StripWaveformPanel | sub-page amber for TX state | | G — Tiny gray | PanadapterApplet (Lo/Hi range) | tiny gray handle — **kept** as deliberate de-emphasis | | H — Plain light variant | SpectrumOverlayMenu | yet another local variant | ## The canonical look (per Jeremy's design call) > Sub-page fill from Wave-style value indicator + Plain light handle from Vfo-style. \`\`\` groove: 4px, {{color.background.1}}, radius 2px sub-page: {{color.accent}} (or caller-supplied token), radius 2px handle: 12×12, {{color.text.primary}}, radius 6px — no border, no hover \`\`\` ## API Two helpers added to [Theme.h](src/gui/Theme.h): \`\`\`cpp namespace Theme { QString primarySliderStyleTemplate(const QString& accentToken = \"color.accent\"); void applyPrimarySliderStyle(QWidget* slider, const QString& accentToken = \"color.accent\"); } \`\`\` \`applyPrimarySliderStyle()\` routes through \`ThemeManager::applyStyleSheet()\` so each slider gets: - Token-resolved colours - **Free live re-theme** on theme change via the reverse-map - Both horizontal and vertical orientation rules Variant tokens — the two transmit-adjacent Strip panels pass \`color.accent.warning\` for the amber sub-page that signals TX state. Same shape, different colour token; no per-call-site stylesheet needed. ## Files migrated (13) - \`Theme.h\` — new helpers + updated default \`QSlider\` rules in \`appStylesheetTemplate()\` - \`TxApplet\` / \`PhoneApplet\` / \`PhoneCwApplet\` / \`RxApplet\` — Style A → canonical - \`WaveApplet\` — Style B → canonical (handle simplified) - \`AetherDspWidget\` / \`DspParamPopup\` — Style C → canonical (hover state dropped) - \`VfoWidget\` — Style D → canonical (now also has the sub-page indicator) - \`PanadapterApplet\` (CW sens slider only) — Style E → canonical - \`SpectrumOverlayMenu\` — both local Style H variants → canonical - \`StripFinalOutputPanel\` / \`StripWaveformPanel\` — Style F → canonical with \`color.accent.warning\` amber ## Intentionally untouched (2) - **\`PanadapterApplet\` Lo/Hi range sliders** — Style G is a deliberate visual de-emphasis for secondary range controls; the tiny gray handle is a load-bearing visual cue, not drift. - **\`MeterSlider\`** — already its own widget for VU/level meters with its own canonical style (aethersdr#3106). ## Net code reduction | | | |---|---| | Lines added | 108 | | Lines removed | 134 | | Net | **-26 lines** | | kSliderStyle constants deleted | 8 | | QSlider rules extracted out of dialog/widget mega-stylesheets | 3 | ## Build verified clean - [x] AetherSDR builds clean (615 ninja steps, no errors) - [x] All 320 targets including every test target ## Phase 4 readiness When the default-light theme ships, slider colours adapt automatically — every site reads through the same three tokens (\`color.background.1\`, \`color.accent\`/\`color.accent.warning\`, \`color.text.primary\`). No follow-up sweep needed. ## Test plan - [ ] CI: build / check-paths / check-windows / CodeQL - [ ] Visual smoke: confirm the TX Controls, Wave, RX, Phone, CW, Vfo, AetherDSP, Quindar editor, and Test Tone dialog all render the same canonical slider; confirm StripFinalOutput + StripWaveform sliders render with amber sub-page fill (TX-state visual) 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Pre-consolidation the codebase had eight near-duplicate `QSlider` stylesheet constants scattered across the applet family. Same slider widget, different look in three adjacent applets:
The canonical look (per Jeremy's design call)
```
groove: 4px, {{color.background.1}}, radius 2px
sub-page: {{color.accent}} (or caller-supplied token), radius 2px
handle: 12×12, {{color.text.primary}}, radius 6px — no border, no hover
```
API
Two helpers added to Theme.h:
```cpp
namespace Theme {
QString primarySliderStyleTemplate(const QString& accentToken = "color.accent");
void applyPrimarySliderStyle(QWidget* slider,
const QString& accentToken = "color.accent");
}
```
`applyPrimarySliderStyle()` routes through `ThemeManager::applyStyleSheet()` so each slider gets:
Variant tokens — the two transmit-adjacent Strip panels pass `color.accent.warning` for the amber sub-page that signals TX state. Same shape, different colour token; no per-call-site stylesheet needed.
Files migrated (13)
Intentionally untouched (2)
Net code reduction
Build verified clean
Phase 4 readiness
When the default-light theme ships, slider colours adapt automatically — every site reads through the same three tokens (`color.background.1`, `color.accent`/`color.accent.warning`, `color.text.primary`). No follow-up sweep needed.
Test plan
73, Jeremy KK7GWY & Claude (AI dev partner)
🤖 Generated with Claude Code