fix(applet-panel): TXDSP drag silently failed due to ID mismatch (#1836)#3044
Conversation
Symptom: dragging the TXDSP (VUDU) tile's title bar to reorder it in the applet panel did nothing. No crash, no error, no log message. Root cause: TXDSP is a composite tile — the AppletEntry registered in m_appletOrder has id="TXDSP" (the persistence key used by Applet_TXDSP), but the underlying ContainerWidget that backs it was created with id="tx_dsp" (the internal container id, used as the parent-id reference for its sub-containers and persisted via ContainerGeometry_tx_dsp + ContainerTree JSON parent refs). The drag MIME data is set from the container's id in ContainerWidget::startDrag — so dragging TXDSP's title bar produces MIME "tx_dsp", which never matches any AppletEntry.id in the dropEvent lookup. srcIdx stays -1 and the function early-returns. Silent failure. Fix: add a fallback in dropEvent. If no AppletEntry matches the dragged id directly, walk the entries again and check whether any of their underlying ContainerWidgets has that id. That catches the composite-tile case (tx_dsp -> TXDSP) without renaming anything. Why aliasing instead of renaming: The container id "tx_dsp" is persisted in real user settings: - ContainerGeometry_tx_dsp records the floating geometry - ContainerTree JSON has 13+ children with parent: "tx_dsp" - The tx_dsp entry itself appears in ContainerTree Renaming the container id to "TXDSP" would require a one-shot migration to rewrite all those keys, or every existing user would lose their TXDSP layout on first launch with the new code. The alias-in-dropEvent fix is regression-safe: zero migration, container m_id stays as-is, only the lookup gains a fallback. Verified locally: TXDSP now reorders cleanly via drag; non-composite applets (RX, EQ, etc.) unaffected; pop-out + dock cycle still works (parent/child container relationship preserved). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks for the careful triage on this one, @ten9876 — the diagnosis is spot-on. I verified the chain:
ContainerWidget.cpp:150sets MIME fromm_id(="tx_dsp").AppletPanel.cpp:752registers the entry asAppletEntry.id="TXDSP"wrapping the"tx_dsp"container.- Direct lookup at the original
dropEventonly matched onAppletEntry.id, so the drag silently dropped.
The aliasing fallback is the right call. A literal rename would orphan ContainerGeometry_tx_dsp + every ContainerTree child pointing at parent: "tx_dsp" in real users' settings, and you've kept the fast path untouched for non-composite tiles. qobject_cast<ContainerWidget*> is null-safe and the c && guard handles non-container entries cleanly.
Couple of small observations, no changes requested:
-
Drift risk. This adds a second place where the MIME-id ↔ AppletEntry-id relationship is implicit. If another composite tile is added later, whoever writes it has to remember the same alias trick works automatically — which it does here, but it's worth a one-liner in
ContainerWidget::onTitleBarDragStartreferencing this fallback so the contract is discoverable from both ends. Not blocking. -
Long-term cleanup. A follow-up could give
ContainerWidgetan optional "drag id" property that defaults tom_idbut can be set to the owningAppletEntry.idat construction. That would let the fast path always succeed and let the fallback be deleted. Out of scope for a bug fix — just flagging if you want to file a follow-up issue.
The comment in the diff is unusually clear about the why (persistence, migration cost, regression-safety) — exactly the kind of context that ages well. Nice work tracking the persistence dependency before reaching for a rename.
LGTM from a correctness standpoint.
🤖 aethersdr-agent · cost: $4.2088 · model: claude-opus-4-7
…etPanel fallback (#3057). Principle IX. Adds ContainerWidget::dragId() / setDragId() so composite tiles can declare the drag MIME payload that matches their owning AppletEntry.id directly. TXDSP now sets dragId("TXDSP") at the wrap site; the aliasing fallback in AppletPanel::dropEvent (added in #3044 to fix #1836) is now dead code and removed in this PR. Behavior-preserving: - Non-composite tiles: m_dragId stays empty, dragId() returns m_id — drag MIME unchanged. - TXDSP: drag MIME is now "TXDSP" (matches AppletEntry.id) instead of "tx_dsp" (the internal container id) — fast-path lookup hits directly. - Container persistence keys (ContainerGeometry_tx_dsp, ContainerTree parent refs) read m_id, not m_dragId — completely unaffected. No migration needed. Net diff is negative: ~12 LOC added in ContainerWidget header, 1 line changed in ContainerWidget.cpp, +6 lines at the TXDSP wrap site, -14 lines of fallback removed in AppletPanel::dropEvent. Pure refactor. Blast radius: risk_score=0.275, 10 high-risk affected (top: MainWindow, AppletPanel ctor, MainWindow::buildUI). The transitive callers reach via AppletPanel construction; the actual API surface change is purely additive (new method, new field with default-empty semantics), so no caller behavior changes. The only behavior delta is the TXDSP wrap site explicitly opting into the new dragId. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…drag MIME-set (#3056). Principle III. Adds a brief comment in ContainerWidget::onTitleBarDragStart immediately above the setData call, pointing future composite-tile authors at the aliasing fallback in AppletPanel::dropEvent (added in #1836 / PR #3044). Without the cross-reference, a future author wrapping another internal container (e.g. an RXDSP-style composite) would touch the sender side first, ship the same m_id != AppletEntry.id mismatch, and never know that the receiver has a safety net catching it. Pure documentation — no behavioral change, no symbol/signature edits. Blast radius: comment-only edit. PreToolUse hook flagged 37 transitive callers (risk_score=0.208, top: MainWindow ctor/buildUI, AppletPanel ctor), but none can be affected by adding a multi-line comment inside an existing function body.
…hersdr#1836) (aethersdr#3044) ## Summary Fixes aethersdr#1836. Dragging the TXDSP (VUDU) tile's title bar to reorder it in the applet panel silently did nothing because the composite tile's underlying container id (`tx_dsp`) and its AppletEntry id (`TXDSP`) didn't match. ## Root cause \`AppletEntry.id = "TXDSP"\` is the persistence key (\`Applet_TXDSP\`), but the underlying \`ContainerWidget\` was created with id \`"tx_dsp"\` (used as the parent-id reference for its sub-containers). The drag MIME data is set from the container's id in [\`ContainerWidget.cpp:150\`](src/gui/containers/ContainerWidget.cpp#L150), so MIME \`"tx_dsp"\` never matched the \`AppletEntry.id == "TXDSP"\` lookup in \`dropEvent\`. \`srcIdx\` stayed -1, function early-returned. Silent failure. ## Fix Aliasing fallback in [\`AppletPanel.cpp:128-155\`](src/gui/AppletPanel.cpp#L128-L155) \`dropEvent\`: if the dragged id doesn't match any \`AppletEntry.id\` directly, walk the entries again and check whether any of their underlying \`ContainerWidget\` instances has that id. Catches the composite-tile case without renaming anything. ## Why aliasing instead of renaming While investigating, found that the container id \`"tx_dsp"\` is persisted in real user settings: - \`<ContainerGeometry_tx_dsp>0,0,244,988</ContainerGeometry_tx_dsp>\` - 13+ children in \`ContainerTree\` JSON with \`"parent": "tx_dsp"\` - The \`"tx_dsp"\` entry itself in \`ContainerTree\` with its children list A literal rename to \`"TXDSP"\` would orphan every existing user's TXDSP geometry + child layout on first launch. The alias-in-dropEvent fix is regression-safe: zero migration, container m_id stays as-is, only the lookup gains a fallback. ## Stats - 1 file, +15 / -0 - No new flat-key AppSettings (Principle V N/A) - MeterSmoother N/A (no meter code) ## Test plan - [x] Local build clean - [x] Visual confirmation by Jeremy: TXDSP drag now reorders cleanly - [x] Non-composite applets (RX, EQ, etc.) still drag — fallback only triggers when direct lookup fails, so fast path unchanged - [x] Pop-out + dock cycle still works — parent/child container relationship preserved (no renames) - [ ] CI: build + check-paths green; check-windows skipped (no MainWindow.cpp / build deps touched) ## Checklist - [x] No new flat-key \`AppSettings\` - [x] All meter UI uses \`MeterSmoother\` (N/A) - [x] Documentation updated if user-visible behavior changed (release notes will mention TXDSP reorder fix) Closes aethersdr#1836. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Fixes #1836. Dragging the TXDSP (VUDU) tile's title bar to reorder it in the applet panel silently did nothing because the composite tile's underlying container id (
tx_dsp) and its AppletEntry id (TXDSP) didn't match.Root cause
`AppletEntry.id = "TXDSP"` is the persistence key (`Applet_TXDSP`), but the underlying `ContainerWidget` was created with id `"tx_dsp"` (used as the parent-id reference for its sub-containers). The drag MIME data is set from the container's id in `ContainerWidget.cpp:150`, so MIME `"tx_dsp"` never matched the `AppletEntry.id == "TXDSP"` lookup in `dropEvent`. `srcIdx` stayed -1, function early-returned. Silent failure.
Fix
Aliasing fallback in `AppletPanel.cpp:128-155` `dropEvent`: if the dragged id doesn't match any `AppletEntry.id` directly, walk the entries again and check whether any of their underlying `ContainerWidget` instances has that id. Catches the composite-tile case without renaming anything.
Why aliasing instead of renaming
While investigating, found that the container id `"tx_dsp"` is persisted in real user settings:
A literal rename to `"TXDSP"` would orphan every existing user's TXDSP geometry + child layout on first launch. The alias-in-dropEvent fix is regression-safe: zero migration, container m_id stays as-is, only the lookup gains a fallback.
Stats
Test plan
Checklist
Closes #1836.
🤖 Generated with Claude Code