Skip to content

fix(smartmtr): render extremes labels + meter selector in GPU flag sprites (rebased #3765)#3771

Merged
ten9876 merged 3 commits into
mainfrom
smartmtr/3765-rebased
Jun 23, 2026
Merged

fix(smartmtr): render extremes labels + meter selector in GPU flag sprites (rebased #3765)#3771
ten9876 merged 3 commits into
mainfrom
smartmtr/3765-rebased

Conversation

@ten9876

@ten9876 ten9876 commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

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 (bug(smartmtr): extremes value numbers fade out before their markers #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 spriteQWidget::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 QGraphicsOpacityEffects 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:

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

Credit: @dsocha.

🤖 Generated with Claude Code

dsocha and others added 3 commits June 23, 2026 05:48
The min/max value numbers (Show values = Extremes) appeared only
intermittently, or not at all, while their triangle markers stayed
visible. drawSmartMtrLabels() gated on m_smartMtrWidget->isVisible(),
but in the default GPU flag mode the flag QWidget is hidden
(setVisible(false)) and drawn as a grabbed sprite — so the in-meter
markers ride along in the sprite while isVisible() is false, which
skipped these separately-overlay-drawn labels entirely (they only
showed on the brief "live"/hover frames where the flag is a real
widget). Gate on the meter having a real size instead — the same
condition the flag sprite itself is drawn under — so the labels track
the markers in both GPU and software flag modes, at the same opacity.

Fixes #3762.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the cursor leaves a flag it's rasterized into a static GPU sprite via
QWidget::render(), which can't draw widgets carrying a QGraphicsEffect.
The meter-view selector dimmed its option rows with QGraphicsOpacityEffect
and the underline gated on the (now-hidden) row's isVisible(), so the
selector's combos and underline vanished from the sprite — unlike tab
underlines / filter buttons, which stay. The selector should stay too.

Make the selector render-compatible:
- underline gates on an explicit m_meterMenuOpen flag, not isVisible();
- option rows drop the opacity effects and dim via :disabled stylesheet
  rules (QComboBox:disabled in the shared combo template, QLabel:disabled
  on the option labels), disabling each row as a unit;
- so the combos + labels stay visible AND keep their disabled dimming in
  the sprite.

Effect-based controls that are meant to disappear (e.g. the DSP
filter-level slider) keep their QGraphicsOpacityEffect and are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The comment above the option-row pointers still described the removed
QGraphicsOpacityEffect members and claimed the combo stylesheet has no
:disabled variant — both untrue after the render-compatible rework (the
:disabled rule was added in this branch). Delete it; the accurate comment
on the m_*Row pointers remains. Review nit on #3765.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ten9876 ten9876 requested a review from a team as a code owner June 23, 2026 12:53
@ten9876 ten9876 merged commit 3d8ba5a into main Jun 23, 2026
6 checks passed
@ten9876 ten9876 deleted the smartmtr/3765-rebased branch June 23, 2026 13:34

@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.

Reviewed the rebased diff against main (437f746). The fix is sound and the conflict resolution against #3760 is done correctly. Thanks for carefully preserving @dsocha's authorship and documenting the rebase rationale.

Verified the rebase claims:

  • ✅ No dangling references to the dropped m_extremesSpeedFade/m_showValuesFade/m_txMeterFade, kDisabledOpacity, or the setRowOpacity lambda — all gone cleanly.
  • ✅ The QGraphicsOpacityEffect on the DSP filter-level row (m_dspLevelRow, VfoWidget.cpp:1723) is untouched, so the "meant to vanish in the sprite" control still behaves as before. The <QGraphicsOpacityEffect> include is correctly retained for it.
  • m_meterMenuOpen stays consistent with m_meterMenuRow's visibility: it's only mutated in setMeterMenuOpen(), the initial hide() in buildUI() matches the false default, and both the strip-click toggle and the tab/menu mutual-exclusion path route through setMeterMenuOpen(). So the paintEvent underline gate (m_meterMenuOpen) can't desync.

Notes (non-blocking):

  1. ComboStyle.h QComboBox:disabled is app-wide, as you flagged. This is a real (good) behavior change beyond SmartMTR scope: disabled combos elsewhere previously rendered as if enabled and will now correctly grey out. It reads as a latent-bug fix, but worth a maintainer eyeball on any other disabled combo in the app that may have leaned on the old look.
  2. Row-level setEnabled() now makes the per-combo setEnabled() calls (VfoWidget.cpp:3343–3349) partly redundant — disabling the parent row already propagates the disabled state (and :disabled styling) to the child combo. Harmless, and the m_showValuesCmb block is still needed for its item-hiding logic, so no change required; just noting it isn't dead-but-load-bearing.
  3. Trivial: with the three m_*Fade members gone, the class QGraphicsOpacityEffect; forward declaration in VfoWidget.h:23 is now unused in the header (the effect is only constructed in the .cpp). Could drop it, but it's cosmetic.

The behavioral upgrade where disabled rows are now truly non-interactive (vs. the old opacity-effect-only dimming, which left the combos clickable) is an improvement, not a regression. Nice work — LGTM.


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

ten9876 added a commit that referenced this pull request Jun 23, 2026
#3765 was closed unmerged in favor of #3771 (its rebased form), which has now
landed. Update the v26.6.4 SmartMTR ref so the changelog points at the PR that
is actually in the history.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ten9876 added a commit that referenced this pull request Jun 23, 2026
…#3772)

Release-prep for **v26.6.4**. Docs/metadata only — no code changes.

## CHANGELOG
New `## [v26.6.4]` entry built from the **80 commits** since v26.6.3, in
the house style (headline + New features / CAT-rigctld parity / Fixes &
hardening / Internal / Governance / Packaging). Headlines: KiwiSDR
public-receiver browser, SmartMTR meter view, agent automation/test
bridge, GPU-composite slice flags + multi-GPU selector, accessibility
pass, CAT/rigctld parity, Constitution v2.0.0. `[Unreleased]` preserved
above it.

## Version bump → 26.6.4
`CMakeLists.txt`, `README.md`, `AGENTS.md` (kept in sync), plus a new
`<release version="26.6.4">` in the AppStream metainfo.

## Doc refresh
- **README**: KiwiSDR highlight added; SmartMTR +
multi-GPU/GPU-composite folded into existing highlights.
- **ROADMAP**: retargeted to post-v26.6.4; dropped already-shipped items
wrongly listed in-flight/queued (H1 Phase 2, L1–L4, RigctlPty);
"Recently shipped" refreshed with the v26.6.4 set; added Flathub +
KiwiSDR-followup forward items.
- **AGENTS**: KiwiSDR subsystem pointer added (the one new subsystem
with no mention); constitution principle numbering verified intact
post-v2.0.0.

## Notes
- Release date stamped **2026-06-23** in CHANGELOG + metainfo — adjust
if tagged on another day.
- Provenance language kept out of the release-facing docs
(CHANGELOG/README/ROADMAP) intentionally; the internal clean-room
practice stays documented in CONSTITUTION/AGENTS/CONTRIBUTING.
- The CHANGELOG SmartMTR line lists #3765 — land #3771 (its rebased
form) before tagging so that ref is accurate.

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
ten9876 added a commit that referenced this pull request Jun 23, 2026
… truth (#3773) (#3775)

## Summary

Closes #3773. Consistency follow-up to #3771.

#3771 introduced `m_meterMenuOpen` as the explicit open-state for the
SmartMTR meter selector and switched the `paintEvent` underline onto it
(the child `m_meterMenuRow->isVisible()` reads false while the flag is
hidden and rasterized into a GPU sprite). This retires the two remaining
`m_meterMenuRow->isVisible()` reads of the same logical open-state:

- [VfoWidget.cpp:525](src/gui/VfoWidget.cpp#L525) — meter-strip
click-to-toggle → `setMeterMenuOpen(!m_meterMenuOpen)`
- [VfoWidget.cpp:2514](src/gui/VfoWidget.cpp#L2514) —
open-a-tab-closes-the-selector → `if (m_meterMenuOpen)`

Both are live-flag interaction paths, so `isVisible()` was accurate
there and there is **no behavior change** — this just makes
`m_meterMenuOpen` the single source of truth so the two reads can't ever
disagree with the flag the way `paintEvent` did.

The null-guard dropped at the tab path is safe: `setMeterMenuOpen()`
early-returns on a null `m_meterMenuRow`, and `m_meterMenuOpen` is only
set true *after* that guard, so a true value implies the row exists.

## Test plan

- [x] Local build passes (`cmake --build build --target AetherSDR`)
- [ ] Existing tests pass (CI)
- [ ] Manual: meter-strip click toggles the selector; opening a tab
still closes it; underline unaffected

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

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
ten9876 added a commit that referenced this pull request Jun 26, 2026
…ve (#3777) (#3806)

## Summary

**Strategy B** of the GPU-flag reversion plan (attached to #3777) — the
**full excision** that #3803 (the one-line default-flip) was the
reversible precursor to. VFO slice flags are now **unconditionally live
child widgets**; the off-screen-sprite + live-on-hover machinery is
removed entirely, fixing the #3777 idle-flag blur and the Diversity-mode
RX-antenna regression at the source.

**Net −582 lines** across `SpectrumWidget.{cpp,h}` and
`VfoWidget.{cpp,h}`.

## Relationship to #3803
These are **alternatives — merge one, not both.** #3803 flips the
default but keeps the sprite path behind `AETHER_GPU_FLAGS=1`
(reversible, for measurement). This PR deletes the machinery (no env
opt-in remains). Recommended sequence: validate live-flag behavior + the
4-panadapter re-profile via #3803 first; if the group commits to it,
merge **this** as the clean removal and close #3803.

## Removed (all sprite-path)
- SpectrumWidget: `m_gpuFlagMode` + the env gate, `m_flagRefreshTimer` +
lambda, `grabFlagSprites`/`releaseFlagSprite`,
`setLiveFlag`/`updateLiveFlag`,
`updateFlagRefreshTimer`/`attachFlagTimerWindowWatcher` +
`m_flagTimerFilteredWindow`, `FlagSprite` +
`m_flagSprites`/`m_flagDrawOrder`/`m_flagQuadVbo`/`m_flagSampler`/`kMaxFlagSprites`,
the `renderGpuFrame` sprite draw-order/texture/quad blocks, and the QRhi
flag-resource init/teardown.
- VfoWidget: `setButtonsOccluded` +
`m_occludeRestore`/`m_buttonsOccluded`.

## Kept intact (verified)
- **`repositionVfoFlags()`** — the *shared* positioner that calls
`updatePosition()` on every flag; only its trailing GPU-mode hide-block
was removed. Still called each frame from `renderGpuFrame`, so live
flags position correctly. This was the key correctness invariant.
- The whole **GPU panadapter** path (`AETHER_GPU_SPECTRUM`:
FFT/waterfall/overlay) — untouched.
- The **SmartMTR** render-mode-agnostic fixes from #3771/#3773/#3775.
- `event()`/`eventFilter()` non-flag logic (`setMouseTracking`, Mac QRhi
teardown in `prepareForTopLevelChange`) preserved.

## Trade-off (unchanged from #3803)
Re-introduces the #3617 main-thread composite cost #3695 removed
(**~0.82 vs 0.45 cores, +0.37 ≈ +45% main-thread**). Separate from and
likely additive to #3797.

## Test plan
- [x] Builds clean (`cmake --build build --target AetherSDR`); zero
dangling references to removed symbols
- [ ] Idle VFO-flag text crisp; no hover-pop (Windows)
- [ ] Diversity-mode RX-antenna selection works
- [ ] Flags position/move correctly with 1, 2, and N panadapters;
split-partner side-locking intact (repositionVfoFlags path)
- [ ] Dragging a flag: no audio crackle / re-raster crash (#3695's
original concern)
- [ ] 4-panadapter main-thread CPU re-profile (the decision gate)
- [ ] a11y linter clean; SmartMTR meter renders correctly

Refs #3777, #3617. Supersedes #3803. Plan: see the #3777 comment.

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

Co-authored-by: Claude Opus 4.8 <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.

bug(smartmtr): extremes value numbers fade out before their markers

2 participants