fix(smartmtr): disable identity opacity effect so option rows don't render blank#3760
Conversation
…ender blank A fully-enabled SmartMTR option row keeps a QGraphicsOpacityEffect at opacity 1.0 (identity). When multiple VFO flags are GPU-composited (#3695), an identity opacity effect can render the row's contents blank. Disable the effect entirely while it is at full strength (a disabled effect is a no-op, so the row paints directly) and keep it installed only while it is actually dimming the row. Extracted as the net-new fix from #3757; the remainder of that PR re-implemented SmartMTR hardening already landed in #3751/#3752/#3753. Part of #3750. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Accessibility check findingsThis PR touches
See Findings are warnings only — the build is not blocked. |
There was a problem hiding this comment.
Reviewed the diff and surrounding code in src/gui/VfoWidget.cpp. This is a clean, focused fix and it looks good. ✅
What it does, and why it's correct:
- The three
QGraphicsOpacityEffects are parented to their rows and installed at construction (VfoWidget.cpp:1021-1064), so they're enabled with default opacity1.0out of the gate — exactly the identity-effect-renders-blank condition under the #3695 GPU compositing path. - The new
setRowOpacitylambda resolves that bysetEnabled(!fullStrength): at full strength the effect is disabled (a no-op, so the row paints directly), and it's only kept active while actually dimming to0.45. That's the right shape for the bug. - The null guard is preserved, the
setOpacity→setEnabledordering avoids any visible flash on the dimmed transition, and togglingsetEnableddoesn't affect geometry/layout, so the existing relayout logic is unaffected.
Conventions: No AppSettings/QSettings surface here; effects remain parented (RAII intact); the no-capture lambda referencing the constexpr kDisabledOpacity is fine. Nicely de-duplicates the three near-identical blocks into one helper.
CI is fully green (build, macOS, Windows, CodeQL, Qt a11y static analysis). The only thing left is the unchecked box in your test plan — visual confirmation on a real radio with multiple flags up. Worth getting that on-hardware check before merge since the failure mode is render-only and not exercised by the build, but the code reasoning is sound.
Thanks for extracting this into a focused change, @ten9876 — the provenance note about dropping the already-landed #3751/#3752/#3753 churn is appreciated and made review easy.
🤖 aethersdr-agent · cost: $1.3340 · model: claude-opus-4-8
There was a problem hiding this comment.
Reviewed the diff against the surrounding code in VfoWidget.cpp. This looks good — clean, focused, and correct.
What's right
- The
setRowOpacitylambda folds the three near-identical blocks into one helper with a single null guard each, and thesetEnabled(!fullStrength)semantics are correct: a disabledQGraphicsOpacityEffectis a no-op, so a full-strength row paints directly instead of round-tripping through the identity-opacity composite path that was rendering blank. Keeping the effect installed-but-disabled (rather than uninstalling) is the right call — it stays cheap to re-enable when dimming kicks back in. - These three effects (
m_extremesSpeedFade/m_showValuesFade/m_txMeterFade) are created andsetGraphicsEffect'd once atVfoWidget.cpp:1021-1064and touched nowhere else, so toggling their enabled state here has no other consumers to surprise. Initial state is also handled, sincesyncSmartMtrSettingsState()runs the same path that disables a default-enabled/1.0 effect. kDisabledOpacityisconstexpr, so using it inside the empty-capture lambda is fine (value read, not odr-used). Scope is exactly the one file the title claims; noQSettings/RAII/error-handling concerns at any system boundary here.
One non-blocking note
- The blank-row mechanism is a visual GPU-compositing interaction (#3695), and the test plan's "verified on a real radio" box is unchecked. The code change is sound regardless, but it'd be worth confirming on-hardware that a full-strength row actually renders before this is treated as fully validated — the failure mode is exactly the kind that only shows under real QRhi composition.
Thanks for the focused extraction from #3757, @ten9876 — narrowing it to just the net-new fix makes this easy to reason about.
🤖 aethersdr-agent · cost: $1.4617 · model: claude-opus-4-8
…rites (rebased #3765) (#3771) Closes #3762. **Rebased + conflict-resolved version of #3765** by @dsocha (original authorship preserved on all three commits). Opened from a maintainer branch because the original is on a fork; #3765 should be closed in favor of this. ## What it fixes (unchanged from #3765) Two GPU-flag-sprite rendering bugs in the SmartMTR meter view (#3723): 1. **Extremes value labels never drew (#3762)** — `drawSmartMtrLabels()` gated on `m_smartMtrWidget->isVisible()`, false in GPU-sprite mode. Now gates on `!size().isEmpty()` (the same condition the sprite is drawn under), so labels track the markers in both GPU and software paths. 2. **Meter selector vanished from the sprite** — `QWidget::render()` can't rasterize a `QGraphicsEffect`. The selector now gates its underline on an explicit `m_meterMenuOpen` flag (not the hidden row's `isVisible()`), and the option rows drop the `QGraphicsOpacityEffect`s in favor of `setEnabled(false)` + `:disabled` stylesheet dimming (new `QComboBox:disabled` rule in `ComboStyle.h`), so they stay visible **and** dimmed in the sprite. ## Rebase / conflict resolution (the reason this is a new branch) The original #3765 conflicted with **#3760** ("disable identity opacity effect…"), which merged into `main` after #3765 was branched. Both target the same blank-rows-in-sprite bug, but: - **#3760** only neutralized the effect at *identity* (opacity 1.0) — i.e. for *enabled* rows. A *disabled* row still carried an active 0.45 effect, so it would **still render blank** in a sprite. - **#3765** removes the effects entirely, so both enabled and disabled rows render. **#3765 ⊇ #3760.** Resolved `syncSmartMtrSettingsState` in favor of #3765's approach and **dropped #3760's now-dead `setRowOpacity` lambda + the `m_*Fade` members**. Verified: no dangling `m_*Fade`/`kDisabledOpacity` references; the `QGraphicsOpacityEffect` on the DSP filter-level row (meant to vanish in sprites) is untouched. ## Verification - Rebased onto `main` (`437f7469`); conflict resolved; commits signed. - Composes with the merged #3752 (M3 `syncSmartMtrSettingsControls` re-seeds combos, then `syncSmartMtrSettingsState` disables the rows) and #3758 (a11y — `QAccessibleInterface` reference preserved; a11y linter passes 0 findings). - Original hardware test (macOS / FlexRadio 6000) per #3765. Credit: @dsocha. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Dariusz Socha <dariusz.socha.pl@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Disables the identity
QGraphicsOpacityEffecton fully-enabled SmartMTR option rows so they don't render blank when multiple VFO flags are GPU-composited.A fully-enabled option row keeps its
QGraphicsOpacityEffectat opacity1.0(identity). With the GPU-composited slice flags from #3695, an identity opacity effect can render the row's contents blank. The fix disables the effect entirely while it is at full strength (a disabledQGraphicsOpacityEffectis a no-op, so the row paints directly) and keeps it installed only while it is actually dimming the row.Provenance
This is the net-new fix extracted from #3757. The remainder of that PR re-implemented SmartMTR
#3750hardening that already landed via #3751 (H1), #3752 (M1–M4), and #3753 (L1–L3); #3757 is being closed in favor of this focused change to avoid re-churning already-merged code. Part of #3750.Test plan
cmake --build build --target AetherSDR)🤖 Generated with Claude Code