refactor(slice): centralize LOCKED tune-feedback timer in SliceModel#3017
Merged
Conversation
Move the 500ms LOCKED visual-feedback gate from per-widget timers in VfoWidget and RxApplet to a single QTimer in SliceModel. Both widgets previously tracked the same UX concept (slice tune blocked → show "LOCKED" for 500ms) with independent timers and mirrored bool state. The new API: - tuneBlockedByLock() keeps its one-shot semantics for consumers needing per-event reactions (cancel direct-entry, future status-bar ack — see #2984). - lockedFeedbackActiveChanged(bool) and isLockedFeedbackActive() expose the sustained "is LOCKED overlay active" state. Widgets that render the overlay connect to the signal for repaint and read the flag in their freq-label update path. - setLocked(false) and applyStatus("lock=0") both clear the timer + flag centrally, so widgets no longer need to mirror unlock events. Net change: -83 / +73 across the four files, dropping two timers and two bools in favor of one source of truth. Future consumers (spectrum overlay, hardware LED, multi-flex bridge) can subscribe to one signal. Closes #2983. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
ten9876
added a commit
that referenced
this pull request
May 24, 2026
## Summary Implements #2984. Wires `MainWindow::onSliceAdded()` to the new `SliceModel::lockedFeedbackActiveChanged` signal (from #2983 / #3017) so a 3-second status-bar message fires on the first blocked tune of a sustained sequence: > Slice is locked — unlock to tune. ## Why this is the option-2 path The issue listed two approaches: per-path latches in `nudgeFreq` / `rx.tuneKnob` / HID coalesce, or driving the message off a single SliceModel signal. With #2983 landed, the signal route is one connection, automatic dedup (only fires on the false→true edge), and naturally covers every current and future blocked-tune entry point — no per-call-site latch state. ## Dedup behavior `lockedFeedbackActiveChanged(true)` fires once when the LOCKED feedback gate goes active. The 500 ms timer in SliceModel keeps the gate active across rapid repeated blocked attempts (stuck MIDI knob, held arrow key), so a burst gives **one toast at the start**, not one per event. When the timer expires without another block, the gate clears; the next blocked attempt re-triggers a fresh toast. ## Scope - 1 file, +10 / -0 - No new state in MainWindow - Same message for keyboard / MIDI / HID / wheel / direct-entry / band-shortcut paths — operator knows which input they used; the message just surfaces the lock cause - Matches the existing memory-recall lock toast pattern in MainWindow.cpp ## Test plan - [x] Clean build, 0 warnings - [ ] Manual: lock slice, scroll-wheel tune ⇒ LOCKED overlay shows AND status-bar toast appears - [ ] Manual: lock slice, hold keyboard right-arrow for 2s ⇒ overlay shows continuously, ONE toast at start (not spammed) - [ ] Manual: lock slice, spin MIDI tune knob ⇒ same as above - [ ] Manual: unlock slice, scroll-tune ⇒ no toast (gate didn't activate) Closes #2984. 🤖 Generated with [Claude Code](https://claude.com/claude-code) 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
…ethersdr#3017) ## Summary Implements aethersdr#2983. Moves the 500ms LOCKED visual-feedback gate from per-widget timers in `VfoWidget` and `RxApplet` to a single `QTimer` in `SliceModel`. Before: each widget had its own `m_lockedFrequencyTimer` + `m_showingLockedFrequencyFeedback` bool. Two timers, two state mirrors, same UX concept. After: one timer + one bool on `SliceModel`. New signal `lockedFeedbackActiveChanged(bool)` drives repaint; the existing `tuneBlockedByLock()` keeps its one-shot semantics for per-event side effects (cancel direct-entry, future status-bar ack — see aethersdr#2984). `setLocked(false)` and `applyStatus("lock=0")` both clear feedback centrally. ## Why this is worth doing - One state variable for "is feedback active" — no risk of widgets drifting out of sync. - Future consumers (spectrum-widget VFO marker, hardware controller LED, status bar) connect to one signal, not two. - Simpler clean-up: `setSlice()` no longer needs to manually clear per-widget state when swapping slices. ## Stats - 6 files changed, **+73 / -83** - Drops 2 `QTimer` members + 2 mirrored `bool` flags + 2 `static constexpr` 500ms constants across the widget pair. - Adds 1 `QTimer` + 1 `bool` + 1 `kLockedFeedbackMs` on `SliceModel`. ## Test plan - [x] Clean build (680 targets, 0 warnings) - [x] Full test suite passes (18/18) - [ ] Manual: lock slice via RX applet ⇒ scroll-wheel tune ⇒ both VFO and RX freq label show "LOCKED" together for 500ms, then both clear. - [ ] Manual: lock slice ⇒ keyboard/MIDI tune ⇒ same as above. - [ ] Manual: lock slice ⇒ blocked tune ⇒ unlock immediately ⇒ overlay clears immediately (doesn't sit for the remainder of 500ms). - [ ] Manual: VFO direct-entry open ⇒ blocked tune attempt ⇒ direct-entry cancels, LOCKED shows. Closes aethersdr#2983. 🤖 Generated with [Claude Code](https://claude.com/claude-code) 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
…dr#3020) ## Summary Implements aethersdr#2984. Wires `MainWindow::onSliceAdded()` to the new `SliceModel::lockedFeedbackActiveChanged` signal (from aethersdr#2983 / aethersdr#3017) so a 3-second status-bar message fires on the first blocked tune of a sustained sequence: > Slice is locked — unlock to tune. ## Why this is the option-2 path The issue listed two approaches: per-path latches in `nudgeFreq` / `rx.tuneKnob` / HID coalesce, or driving the message off a single SliceModel signal. With aethersdr#2983 landed, the signal route is one connection, automatic dedup (only fires on the false→true edge), and naturally covers every current and future blocked-tune entry point — no per-call-site latch state. ## Dedup behavior `lockedFeedbackActiveChanged(true)` fires once when the LOCKED feedback gate goes active. The 500 ms timer in SliceModel keeps the gate active across rapid repeated blocked attempts (stuck MIDI knob, held arrow key), so a burst gives **one toast at the start**, not one per event. When the timer expires without another block, the gate clears; the next blocked attempt re-triggers a fresh toast. ## Scope - 1 file, +10 / -0 - No new state in MainWindow - Same message for keyboard / MIDI / HID / wheel / direct-entry / band-shortcut paths — operator knows which input they used; the message just surfaces the lock cause - Matches the existing memory-recall lock toast pattern in MainWindow.cpp ## Test plan - [x] Clean build, 0 warnings - [ ] Manual: lock slice, scroll-wheel tune ⇒ LOCKED overlay shows AND status-bar toast appears - [ ] Manual: lock slice, hold keyboard right-arrow for 2s ⇒ overlay shows continuously, ONE toast at start (not spammed) - [ ] Manual: lock slice, spin MIDI tune knob ⇒ same as above - [ ] Manual: unlock slice, scroll-tune ⇒ no toast (gate didn't activate) Closes aethersdr#2984. 🤖 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
Implements #2983. Moves the 500ms LOCKED visual-feedback gate from per-widget timers in
VfoWidgetandRxAppletto a singleQTimerinSliceModel.Before: each widget had its own
m_lockedFrequencyTimer+m_showingLockedFrequencyFeedbackbool. Two timers, two state mirrors, same UX concept.After: one timer + one bool on
SliceModel. New signallockedFeedbackActiveChanged(bool)drives repaint; the existingtuneBlockedByLock()keeps its one-shot semantics for per-event side effects (cancel direct-entry, future status-bar ack — see #2984).setLocked(false)andapplyStatus("lock=0")both clear feedback centrally.Why this is worth doing
setSlice()no longer needs to manually clear per-widget state when swapping slices.Stats
QTimermembers + 2 mirroredboolflags + 2static constexpr500ms constants across the widget pair.QTimer+ 1bool+ 1kLockedFeedbackMsonSliceModel.Test plan
Closes #2983.
🤖 Generated with Claude Code