fix(smartmtr): render extremes labels + meter selector in GPU flag sprites (rebased #3765)#3771
Merged
Conversation
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>
This was referenced Jun 23, 2026
Contributor
There was a problem hiding this comment.
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 thesetRowOpacitylambda — all gone cleanly. - ✅ The
QGraphicsOpacityEffecton 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_meterMenuOpenstays consistent withm_meterMenuRow's visibility: it's only mutated insetMeterMenuOpen(), the initialhide()inbuildUI()matches thefalsedefault, and both the strip-click toggle and the tab/menu mutual-exclusion path route throughsetMeterMenuOpen(). So thepaintEventunderline gate (m_meterMenuOpen) can't desync.
Notes (non-blocking):
ComboStyle.hQComboBox:disabledis 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.- Row-level
setEnabled()now makes the per-combosetEnabled()calls (VfoWidget.cpp:3343–3349) partly redundant — disabling the parent row already propagates the disabled state (and:disabledstyling) to the child combo. Harmless, and them_showValuesCmbblock is still needed for its item-hiding logic, so no change required; just noting it isn't dead-but-load-bearing. - Trivial: with the three
m_*Fademembers gone, theclass QGraphicsOpacityEffect;forward declaration inVfoWidget.h:23is 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
This was referenced Jun 23, 2026
Closed
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>
This was referenced Jun 25, 2026
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>
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.
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):
drawSmartMtrLabels()gated onm_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.QWidget::render()can't rasterize aQGraphicsEffect. The selector now gates its underline on an explicitm_meterMenuOpenflag (not the hidden row'sisVisible()), and the option rows drop theQGraphicsOpacityEffects in favor ofsetEnabled(false)+:disabledstylesheet dimming (newQComboBox:disabledrule inComboStyle.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
mainafter #3765 was branched. Both target the same blank-rows-in-sprite bug, but:Resolved
syncSmartMtrSettingsStatein favor of #3765's approach and dropped #3760's now-deadsetRowOpacitylambda + them_*Fademembers. Verified: no danglingm_*Fade/kDisabledOpacityreferences; theQGraphicsOpacityEffecton the DSP filter-level row (meant to vanish in sprites) is untouched.Verification
main(437f7469); conflict resolved; commits signed.syncSmartMtrSettingsControlsre-seeds combos, thensyncSmartMtrSettingsStatedisables the rows) and feat(a11y): QAccessibleInterface for VfoWidget + LevelBar (#3754) #3758 (a11y —QAccessibleInterfacereference preserved; a11y linter passes 0 findings).Credit: @dsocha.
🤖 Generated with Claude Code