Skip to content

feat(smeter): config context menu + needle pivot cover with backlight glow#3859

Merged
ten9876 merged 3 commits into
mainfrom
feat/smeter-config-context-menu
Jun 27, 2026
Merged

feat(smeter): config context menu + needle pivot cover with backlight glow#3859
ten9876 merged 3 commits into
mainfrom
feat/smeter-config-context-menu

Conversation

@ten9876

@ten9876 ten9876 commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two VU/S-meter changes:

  1. Config → right-click context menu. Moves all of the applet's inline config controls (TX Select + RX Select combos, Peak Hold button, Decay combo, RST) into a right-click context menu on the gauge, so the applet body is just the meter.
  2. Needle pivot cover + backlight glow. Masks the needle's origin behind a moulded half-disc with a warm, diffuse backlight glow, like a classic analog VU meter.

Config context menu

Right-click the S-meter → a QMenu with five labelled sections:

  • TX Select — Power / SWR / Level / Compression (exclusive)
  • RX Select — S-Meter / S-Meter Peak (exclusive)
  • Peak Hold — Enabled (toggle)
  • Decay speed — Fast / Medium / Slow (exclusive)
  • Reset Peak Hold — action

Exclusive groups use QActionGroup. Section headers are disabled QWidgetAction + styled QLabel rows, because QMenu::addSection()'s text doesn't render under the app's menu styling (only its separator shows) — see #3858 for the bridge follow-up.

No behavior change: the menu reads/writes the same AppSettings keys (SMeter_TxSelect, SMeter_RxSelect, PeakHoldEnabled, PeakDecayRate) and calls the same SMeterWidget methods; startup restores saved state directly onto the gauge. Removed the now-unused m_txSelect/m_rxSelect members.

Pivot cover + glow

  • A filled half-disc at the bottom-centre (near-black moulding + subtle glossy rim) hides where the needle pivots; the needle appears to emerge from under it.
  • A warm radial backlight glow behind the cover — the cover masks the bright centre, leaving a soft, diffuse amber halo spilling out from behind the moulding. Drawn behind the needle so the needle stays crisp.

Test plan

  • Builds clean (cmake --build build --target AetherSDR)
  • Bridge-verified: inline controls removed, gauge intact, no crash
  • FLEX-8600: right-click menu (with section headers) works and selections persist; pivot cover + glow look correct

Note

UX change (controls → context menu) + visual change (pivot cover/glow); both at maintainer direction.

🤖 Generated with Claude Code

ten9876 and others added 2 commits June 26, 2026 21:24
The S-meter applet carried two rows of inline controls (TX Select + RX Select
combos; Peak Hold button + Decay combo + RST), which crowded the compact VU
applet. Move all of them into a right-click context menu on the gauge so the
applet body is just the meter.

The menu has five labelled sections — TX Select (Power/SWR/Level/Compression),
RX Select (S-Meter/S-Meter Peak), Peak Hold (Enabled toggle), Decay speed
(Fast/Medium/Slow), and Reset Peak Hold — built on customContextMenuRequested.
Exclusive groups use QActionGroup. Section headers are disabled QWidgetAction +
styled QLabel rows, because QMenu::addSection() text doesn't render under the
app's menu styling (only its separator shows).

No behavior change: the menu reads/writes the same AppSettings keys
(SMeter_TxSelect, SMeter_RxSelect, PeakHoldEnabled, PeakDecayRate) and calls the
same SMeterWidget methods; startup restores saved state directly onto the gauge.
The now-unused m_txSelect/m_rxSelect members are removed.

Verified via the automation bridge: inline controls gone, gauge intact, no
crash. Right-click menu (incl. section headers) confirmed visually.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…glow

Hide the VU needle's origin behind a filled half-disc at the bottom-centre of
the gauge (a near-black moulding with a subtle glossy rim), like the pivot bump
on a classic analog VU meter, so the needle appears to emerge from under it.

Add a warm radial backlight glow behind the cover — the cover masks the bright
centre, leaving a soft, diffuse amber halo spilling out from behind the
moulding, as if a lamp sits behind the mask.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ten9876 ten9876 requested a review from a team as a code owner June 27, 2026 04:47
…bsystem

The pivot moulding, its rim, and the backlight glow were hardcoded. Move them
to theme tokens so they follow the active theme and are customizable:

- color.meter.pivot.fill — moulding
- color.meter.pivot.rim  — glossy rim
- color.meter.pivot.glow — warm backlight (paint applies the gradient alphas)

Registered in the ThemeManager paint-code defaults and both bundled themes
(default-dark / default-light, the latter tuned for a light face). SMeterWidget
reads them via ThemeManager::color(); dark-theme values are unchanged, so the
render is identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work — this is a clean, well-scoped change and both halves look correct. CI is green across the board (build, CodeQL, Qt Accessibility static analysis, macOS/Windows). Thanks for the thorough PR description and the #3858 cross-reference explaining the addSection() workaround.

What I checked

Conventions — ✅ Uses AppSettings (not QSettings) throughout; reads/writes the same four keys the inline controls used, so persisted state migrates transparently. The startup-restore block correctly qBounds the saved indices before indexing kTxMeterItems/kRxMeterItems, which is actually more robust than the old if (idx < count) guards.

Memory/ownership — ✅ No leaks. QMenu menu is stack-allocated; the QActionGroups and QWidgetActions are parented to &menu, and each header QLabel is owned by its QWidgetAction via setDefaultWidget. Everything tears down when the menu falls out of scope after exec().

Paint code — ✅ cx/h/w are all in scope (defined at the top of paintEvent), the radial-gradient stops are monotonic (0 → edge → mid → 1), and the cover is drawn after the needle so the needle reads as emerging from under the moulding. Good call seeding color.meter.pivot.{fill,rim,glow} in seedBuiltinDefaults() so a missing theme file degrades gracefully rather than painting transparent.

Removed members — ✅ m_txSelect/m_rxSelect removal is consistent: header decls and every .cpp reference go together in the same diff, no danglers.

Minor (optional, non-blocking)

  • The pivot glow/cover re-fetches three theme tokens and rebuilds the QRadialGradient on every paintEvent. It's negligible next to the existing tick/gradient work in this paint path, so only worth caching the QColors as members if you happen to touch this again — not worth a revision on its own.

Looks good to merge from my side. 👍


🤖 aethersdr-agent · cost: $2.6484 · model: claude-opus-4-8

@ten9876 ten9876 merged commit 7914c8b into main Jun 27, 2026
6 checks passed
@ten9876 ten9876 deleted the feat/smeter-config-context-menu branch June 27, 2026 06:21
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