Skip to content

feat(cw): resizable CW decode panel + adjustable, persistent font size (#3628)#3824

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
jensenpat:fix/3628-cw-resize
Jun 26, 2026
Merged

feat(cw): resizable CW decode panel + adjustable, persistent font size (#3628)#3824
ten9876 merged 1 commit into
aethersdr:mainfrom
jensenpat:fix/3628-cw-resize

Conversation

@jensenpat

Copy link
Copy Markdown
Collaborator

Summary

Makes the CW decode panel vertically resizable with an adjustable, persistent font size — closing #3628.

Previously the panel was locked to a hardcoded setFixedHeight(80) with a hardcoded 13px monospace font and no persistence, which is hard to read on high-DPI displays and can't show more decoded-text history. The panel already retains full scrollback (m_cwText has no setMaximumBlockCount/trimming), so the only blockers were the fixed height and font — no decoder changes are needed.

Changes (all client-side; no FlexLib/protocol/decoder changes)

  • Resizable height — a thin drag-grip (cwResizeGrip) along the panel's top edge resizes it vertically, clamped 60–600px. A grip strip rather than a QSplitter deliberately: wrapping the layout in a splitter would reparent the GPU SpectrumWidget (QRhiWidget), which carries native-window risk (cf. Mouse cursor disappears when hovering over panadapter, waterfall, and CW decoder panes (Windows 11) #1096). The grip leaves the spectrum surface untouched.
  • Font-size controlA-/A+ buttons (cwFontDown/cwFontUp) in the CW toolbar and "Increase/Decrease font size" actions in the decode-text context menu, clamped 8–32px.
  • Persistence — both fontPx and panelHeight are stored in the existing nested CwDecoder settings blob via CwDecodeSettings (constitution Principle V) and restored in the applet constructor on launch. A new ensureToggles() helper keeps the rx/tx enable state intact when only a display key changes.
  • Addressability — the panel gains objectName "cwDecodePanel" so the agent automation bridge can address and read it.

A taller panel immediately reveals more already-decoded history. Existing decode functionality is unchanged.

Files

  • src/gui/PanadapterApplet.cpp / .h — grip + drag handling in eventFilter, font buttons/menu, applyCwFont/adjustCwFont/setCwPanelHeight, restore on construct.
  • src/gui/CwDecodeSettings.hfontPx()/panelHeight() getters + setters.

How the agent automation bridge proved it

RX-only proof (no TX), against a live FlexRadio panadapter on the fix/3628-cw-resize build:

1 — Panel-height persistence + restore-on-launch. Seeded panelHeight=220 into the settings file, launched, and read the tree back:

dumpTree → cwDecodePanel: { "class":"QWidget", "geometry": { "h": 220, ... } }

The panel height read back 220 (the hardcoded value was 80) — the persisted height is honored on launch.

2 — Font control reachable + adjusts + persists. Invoked the new button via the bridge three times and watched the on-disk CwDecoder blob:

blob BEFORE : {"rx":"True","tx":"False","panelHeight":220}
invoke cwFontUp click  ×3   (each ok=true, resolved=cwFontUp)
blob AFTER  : {"fontPx":16,"panelHeight":220,"rx":"True","tx":"False"}

fontPx went 13 → 16 (three +1 increments) and persisted to disk.

dumpTree also confirmed cwFontUp, cwFontDown, and cwResizeGrip are present in the applet tree. The radio was left untouched (RX-only) and the local settings file was restored afterward.

Agent automation bridge — gap found

  • No mouse-drag / gesture synthesis verb — the bridge can invoke button-style actions but cannot synthesize a press-move-release drag, so the resize grip drag itself could not be exercised end-to-end through the bridge. I proved the persistence/restore path (seed → dumpTree height read-back) and the font path (invoke → disk), but not the literal drag gesture. Proposed: a drag <target> dx dy (or mouse <target> down/move/up) verb so grip/slider-handle drags become provable.

Fixes #3628

💻 Generated with Claude Code (Opus 4.8) with architecture by @jensenpat

…ze (aethersdr#3628)

The CW decode panel was locked to a hardcoded 80px height
(setFixedHeight) with a hardcoded 13px monospace font and no
persistence — hard to read on high-DPI displays and unable to show
more decoded-text history. The full scrollback was already retained,
so the only blockers were the fixed height and font.

Changes (all client-side, no protocol/decoder changes):
- Drag-grip (`cwResizeGrip`) along the panel's top edge resizes it
  vertically, clamped 60–600px. A thin strip rather than a QSplitter
  so the GPU SpectrumWidget (QRhiWidget) is never reparented.
- A-/A+ toolbar buttons (`cwFontDown`/`cwFontUp`) and context-menu
  "Increase/Decrease font size" actions adjust the decoded-text font,
  clamped 8–32px.
- Both font size and panel height persist in the existing nested
  `CwDecoder` settings blob (CwDecodeSettings), restored on launch.
- The panel gains objectName `cwDecodePanel` so the automation bridge
  can address and read it.

Taller panel immediately reveals more already-decoded history; existing
decode functionality is unchanged.

Proven with the agent automation bridge:
- dumpTree after seeding panelHeight=220 → `cwDecodePanel` geometry.h
  reads back 220 (was hardcoded 80): persistence + restore-on-launch.
- invoke cwFontUp ×3 → on-disk CwDecoder blob fontPx 13→16: the font
  control is reachable, increments correctly, and persists.

Fixes aethersdr#3628

💻 Generated with Claude Code (Opus 4.8) with architecture by @jensenpat
@jensenpat jensenpat changed the title feat(gui): resizable CW decode panel + adjustable, persistent font size (#3628) feat(cwx): resizable CW decode panel + adjustable, persistent font size (#3628) Jun 26, 2026
@jensenpat jensenpat marked this pull request as ready for review June 26, 2026 02:16
@jensenpat jensenpat requested a review from a team as a code owner June 26, 2026 02:16

@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 diff against the existing PanadapterApplet and CwDecodeSettings code — this is clean and well-scoped. Thanks @jensenpat. 🙏

Conventions ✓

  • Persistence stays in the nested CwDecoder JSON blob via CwDecodeSettings (Principle V) — no new flat keys.
  • ensureToggles() correctly only fills rx/tx when absent, so a font/height write never clobbers a user's existing enable state.
  • Clamps are consistent between the constructor restore (std::clamp(..., 8, 32) / 60, 600), adjustCwFont, and setCwPanelHeight, so an out-of-range persisted value can't escape.
  • The grip-vs-QSplitter choice (avoiding a QRhiWidget reparent, cf. #1096) is the right call and well-justified.

Correctness ✓

  • The grip event-filter press/move/release uses globalPosition() deltas, and Qt's implicit mouse grab on press keeps move/release routed to m_cwGrip even as the cursor leaves the 4px strip — so the drag tracks correctly.
  • Persisting only on release (not per mouse-move) is the right tradeoff.
  • applyCwFont() runs .arg(m_cwFontPx) on the template before applyStyleSheet substitutes {{color.*}}, and there are no stray % tokens — no format collision.

One minor, optional note (non-blocking)
The new grip branch in eventFilter returns early on MouseButtonPress, which skips the emit activated(m_panId) at the bottom of the function. So grabbing the resize grip won't mark that panadapter as the active pane the way clicking elsewhere on it does. Probably immaterial in practice, but if you want a press on the grip to also focus the pane, emitting activated(m_panId) before the return true would match the rest of the widget's behavior.

The acknowledged gap — no drag-gesture synthesis in the automation bridge, so the literal grip drag wasn't exercised end-to-end — is a fair and clearly-stated limitation; the persistence/restore and font paths are well proven. No changes required from my side.


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

@jensenpat jensenpat changed the title feat(cwx): resizable CW decode panel + adjustable, persistent font size (#3628) feat(cw): resizable CW decode panel + adjustable, persistent font size (#3628) Jun 26, 2026

@ten9876 ten9876 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-implemented. Verified: the drag-grip eventFilter direction/clamp is correct (dy = startY - currentY enlarges the bottom panel on up-drag, clamped 60–600) and persists only on release; adjustCwFont clamps 8–32 + early-returns + persists, applyCwFont re-bakes the stylesheet; persistence is Principle-V clean (nested CwDecoder blob) and ensureToggles only adds rx/tx if absent so it never clobbers an existing toggle value; restore-on-construct applies both keys at build. Good call using a grip strip rather than a QSplitter to avoid reparenting the GPU SpectrumWidget (#1096). No protocol/decoder/TX surface, addressable for the bridge. Thanks @jensenpat.

@ten9876 ten9876 merged commit c40166c into aethersdr:main Jun 26, 2026
6 checks passed
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.

Make CW decode window vertically resizable with adjustable, persistent font size

2 participants