Feature/vu meter popout#1154
Conversation
The S-Meter section can now be detached into a floating window and re-docked exactly like all other applets — using the same FloatingAppletWindow infrastructure, AppSettings geometry persistence, and PR aethersdr#916 / aethersdr#985 bug fixes (drift, WM centering, shutdown race). ## What changed ### src/gui/AppletPanel.h - Added `QWidget* m_sMeterContent` — the floatable content container (SMeterWidget + TX/RX select row + Peak Hold row), analogous to the applet widget held at layout index 1 in every other wrapper. - Added private `floatSMeter()` and `dockSMeter()` methods. ### src/gui/AppletPanel.cpp **S-Meter construction:** - `AppletTitleBar("S-Meter", "VU", this)` — passes the panel pointer so the right-click context menu ("⬈ Pop out" / "↩ Dock") is active. - Introduced `m_sMeterContent` QWidget with its own QVBoxLayout as layout index 1 of `m_sMeterSection` (after the title bar), so the extractor logic in `floatSMeter()` / `dockSMeter()` is identical to every other applet. **ANLG toggle button:** - Updated to the float-aware pattern used by TUN / AMP / AG: raises/hides the floating window when VU is floating, re-floats via `QTimer::singleShot(0)` when IsFloating is persisted but no window is open yet (toggle-off → toggle-on cycle fix from aethersdr#985). **`isAppletFloating()`:** - Added early return for `"VU"`: checks `m_floatingWindows.contains("VU")` directly (VU is not in `m_appletOrder`). **`floatApplet()` / `dockApplet()`:** - Added `if (id == "VU")` dispatch at the top of each, delegating to `floatSMeter()` / `dockSMeter()`. **`floatSMeter()` / `dockSMeter()`:** - Mirror `floatApplet()` / `dockApplet()` exactly: reparent content out of/back into `m_sMeterSection`, create/destroy `FloatingAppletWindow`, persist `FloatingApplet_VU_IsFloating`, save geometry on dock. **Startup restore:** - After the existing `m_appletOrder` restore loop, added a `QTimer::singleShot(0)` restore for `"VU"` so the S-Meter reopens floating if it was floating when the app last closed. Closes aethersdr#993 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks for this, @chibondking — the overall architecture is sound. Using the same FloatingAppletWindow infrastructure, AppSettings geometry persistence, and AetherSDR::floatKey() convention keeps VU consistent with every other applet. Two issues to address before merge:
1. dockSMeter() — fragile layout-walk can crash on failure
The function navigates FloatingAppletWindow's internal layout structure to recover m_sMeterContent, but m_sMeterContent is a named member of AppletPanel — there is no reason to go looking for it through the window's layout.
If the walk fails (e.g. FloatingAppletWindow's layout shape changes in a future refactor, or itemAt returns null at any level), appletWidget stays null and the code still reaches:
win->deleteLater();
m_floatingWindows.remove("VU");
m_sMeterSection->show();At that point m_sMeterContent (and all its children — m_sMeter, m_txSelect, m_rxSelect, the peak-hold widgets) were parented inside the window, so deleteLater() destroys them. The dangling member pointers cause a crash the next time any of them are accessed (signal level update, TX/RX mode change, etc.).
Suggested fix — use the member directly:
void AppletPanel::dockSMeter()
{
if (!m_floatingWindows.contains("VU")) { return; }
FloatingAppletWindow* win = m_floatingWindows.take("VU");
// Re-insert content before deleting the window
if (auto* wl = qobject_cast<QVBoxLayout*>(m_sMeterSection->layout())) {
m_sMeterContent->setParent(m_sMeterSection);
wl->addWidget(m_sMeterContent);
m_sMeterContent->show();
}
if (win) { win->hideAndSave(); win->deleteLater(); }
m_sMeterSection->show();
AppSettings::instance().setValue(AetherSDR::floatKey("VU"), "False");
AppSettings::instance().save();
}Note the reparent-before-delete order: re-parent m_sMeterContent into m_sMeterSection first, then delete the window, so Qt's parent-chain destruction can't reach the widget.
2. .gitignore — Visual Studio artifacts are out of scope
+/.vs
+/out/install/x64-DebugAetherSDR targets Linux (Qt6 + CMake). .vs/ and out/install/x64-Debug/ are Windows Visual Studio IDE artifacts. These belong in a user-level ~/.gitignore_global, not the project-wide .gitignore. Please drop these two lines or submit them as a separate PR if there's a plan to add Windows support.
Everything else looks good — the isAppletFloating("VU") early return, the floatApplet/dockApplet dispatch guards, the deferred QTimer::singleShot(0) restore at startup, and the ANLG button float-awareness all follow the same patterns as the other applets correctly.
The S-Meter section can now be detached into a floating window and re-docked exactly like all other applets — using the same FloatingAppletWindow infrastructure, AppSettings geometry persistence, and PR aethersdr#916 / aethersdr#985 bug fixes (drift, WM centering, shutdown race). ## What changed ### src/gui/AppletPanel.h - Added `QWidget* m_sMeterContent` — the floatable content container (SMeterWidget + TX/RX select row + Peak Hold row), analogous to the applet widget held at layout index 1 in every other wrapper. - Added private `floatSMeter()` and `dockSMeter()` methods. ### src/gui/AppletPanel.cpp **S-Meter construction:** - `AppletTitleBar("S-Meter", "VU", this)` — passes the panel pointer so the right-click context menu ("⬈ Pop out" / "↩ Dock") is active. - Introduced `m_sMeterContent` QWidget with its own QVBoxLayout as layout index 1 of `m_sMeterSection` (after the title bar), so the extractor logic in `floatSMeter()` / `dockSMeter()` is identical to every other applet. **ANLG toggle button:** - Updated to the float-aware pattern used by TUN / AMP / AG: raises/hides the floating window when VU is floating, re-floats via `QTimer::singleShot(0)` when IsFloating is persisted but no window is open yet (toggle-off → toggle-on cycle fix from aethersdr#985). **`isAppletFloating()`:** - Added early return for `"VU"`: checks `m_floatingWindows.contains("VU")` directly (VU is not in `m_appletOrder`). **`floatApplet()` / `dockApplet()`:** - Added `if (id == "VU")` dispatch at the top of each, delegating to `floatSMeter()` / `dockSMeter()`. **`floatSMeter()` / `dockSMeter()`:** - Mirror `floatApplet()` / `dockApplet()` exactly: reparent content out of/back into `m_sMeterSection`, create/destroy `FloatingAppletWindow`, persist `FloatingApplet_VU_IsFloating`, save geometry on dock. **Startup restore:** - After the existing `m_appletOrder` restore loop, added a `QTimer::singleShot(0)` restore for `"VU"` so the S-Meter reopens floating if it was floating when the app last closed. **dockSMeter() — use m_sMeterContent directly (agent review fix)** The original used a fragile layout-walk to recover m_sMeterContent from FloatingAppletWindow's internal layout. If any itemAt() returned null, appletWidget would be null while the code still called win->deleteLater(), destroying m_sMeterContent and all its children (m_sMeter, m_txSelect, m_rxSelect, peak-hold widgets) — crash on next signal-level update. Fix: use the named member directly. Reparent m_sMeterContent into m_sMeterSection before deleteLater() so Qt's parent-chain destruction cannot reach it. **.gitignore — drop Visual Studio artifacts (agent review fix)** /.vs and /out/install/x64-Debug are Windows VS IDE artifacts; they belong in ~/.gitignore_global, not the project-wide .gitignore. Closes aethersdr#993 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The S-Meter section can now be detached into a floating window and re-docked exactly like all other applets — using the same FloatingAppletWindow infrastructure, AppSettings geometry persistence, and PR aethersdr#916 / aethersdr#985 bug fixes (drift, WM centering, shutdown race). ## What changed ### src/gui/AppletPanel.h - Added `QWidget* m_sMeterContent` — the floatable content container (SMeterWidget + TX/RX select row + Peak Hold row), analogous to the applet widget held at layout index 1 in every other wrapper. - Added private `floatSMeter()` and `dockSMeter()` methods. ### src/gui/AppletPanel.cpp **S-Meter construction:** - `AppletTitleBar("S-Meter", "VU", this)` — passes the panel pointer so the right-click context menu ("⬈ Pop out" / "↩ Dock") is active. - Introduced `m_sMeterContent` QWidget with its own QVBoxLayout as layout index 1 of `m_sMeterSection` (after the title bar), so the extractor logic in `floatSMeter()` / `dockSMeter()` is identical to every other applet. **ANLG toggle button:** - Updated to the float-aware pattern used by TUN / AMP / AG: raises/hides the floating window when VU is floating, re-floats via `QTimer::singleShot(0)` when IsFloating is persisted but no window is open yet (toggle-off → toggle-on cycle fix from aethersdr#985). **`isAppletFloating()`:** - Added early return for `"VU"`: checks `m_floatingWindows.contains("VU")` directly (VU is not in `m_appletOrder`). **`floatApplet()` / `dockApplet()`:** - Added `if (id == "VU")` dispatch at the top of each, delegating to `floatSMeter()` / `dockSMeter()`. **`floatSMeter()` / `dockSMeter()`:** - Mirror `floatApplet()` / `dockApplet()` exactly: reparent content out of/back into `m_sMeterSection`, create/destroy `FloatingAppletWindow`, persist `FloatingApplet_VU_IsFloating`, save geometry on dock. **Startup restore:** - After the existing `m_appletOrder` restore loop, added a `QTimer::singleShot(0)` restore for `"VU"` so the S-Meter reopens floating if it was floating when the app last closed. **dockSMeter() — use m_sMeterContent directly (agent review fix)** The original used a fragile layout-walk to recover m_sMeterContent from FloatingAppletWindow's internal layout. If any itemAt() returned null, appletWidget would be null while the code still called win->deleteLater(), destroying m_sMeterContent and all its children (m_sMeter, m_txSelect, m_rxSelect, peak-hold widgets) — crash on next signal-level update. Fix: use the named member directly. Reparent m_sMeterContent into m_sMeterSection before deleteLater() so Qt's parent-chain destruction cannot reach it. **.gitignore — drop Visual Studio artifacts (agent review fix)** /.vs and /out/install/x64-Debug are Windows VS IDE artifacts; they belong in ~/.gitignore_global, not the project-wide .gitignore. Closes aethersdr#993 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Suggestions implemented. |
Add pop-out/pop-in support for the S-Meter (VU) applet (#993)
The S-Meter section can now be detached into a floating window and
re-docked exactly like all other applets — using the same
FloatingAppletWindow infrastructure, AppSettings geometry persistence,
and PR #916 / #985 bug fixes (drift, WM centering, shutdown race).
What changed
src/gui/AppletPanel.h
QWidget* m_sMeterContent— the floatable content container(SMeterWidget + TX/RX select row + Peak Hold row), analogous to
the applet widget held at layout index 1 in every other wrapper.
floatSMeter()anddockSMeter()methods.src/gui/AppletPanel.cpp
S-Meter construction:
AppletTitleBar("S-Meter", "VU", this)— passes the panel pointerso the right-click context menu ("⬈ Pop out" / "↩ Dock") is active.
m_sMeterContentQWidget with its own QVBoxLayout aslayout index 1 of
m_sMeterSection(after the title bar), so theextractor logic in
floatSMeter()/dockSMeter()is identical toevery other applet.
ANLG toggle button:
raises/hides the floating window when VU is floating, re-floats
via
QTimer::singleShot(0)when IsFloating is persisted but nowindow is open yet (toggle-off → toggle-on cycle fix from Fix floating applets losing float state and position across restarts (#959) #985).
isAppletFloating():"VU": checksm_floatingWindows.contains("VU")directly (VU is not in
m_appletOrder).floatApplet()/dockApplet():if (id == "VU")dispatch at the top of each, delegating tofloatSMeter()/dockSMeter().floatSMeter()/dockSMeter():floatApplet()/dockApplet()exactly: reparent contentout of/back into
m_sMeterSection, create/destroyFloatingAppletWindow, persistFloatingApplet_VU_IsFloating,save geometry on dock.
Startup restore:
m_appletOrderrestore loop, added aQTimer::singleShot(0)restore for"VU"so the S-Meter reopensfloating if it was floating when the app last closed.
Closes #993
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com