Skip to content

[ux] Fix RX applet frequency font scope on restart#4267

Merged
NF0T merged 1 commit into
aethersdr:mainfrom
jensenpat:aether/fix-4159-theme-font-persistence
Jul 17, 2026
Merged

[ux] Fix RX applet frequency font scope on restart#4267
NF0T merged 1 commit into
aethersdr:mainfrom
jensenpat:aether/fix-4159-theme-font-persistence

Conversation

@jensenpat

Copy link
Copy Markdown
Collaborator

Summary

  • fix the RX applet frequency font reverting to the root theme token after restart
  • preserve live Theme Editor behavior and the existing shared font.family.freq token
  • keep the change local to the RX frequency widget hierarchy

Fixes #4159.

Related context: #3653 and #3688 fixed custom-theme serialization/loading, but the persisted scoped token still resolved incorrectly while the RX applet was being constructed.

Root cause

RxApplet registered the frequency label and editor styles while their QStackedWidget had no parent. ThemeManager therefore walked an incomplete ancestor chain and resolved the root frequency token at startup. Qt reparented the stack later during nested-layout activation, but that ancestor-only parent change did not reach the already-registered children. A live theme edit reapplied every style after the tree was complete, which is why the saved font appeared to work until the next launch.

Fix

Construct the frequency stack with RxApplet as its explicit parent before registering either child stylesheet. Both widgets can now resolve the applet/rx scope immediately; later layout placement remains unchanged.

Validation

  • clean RelWithDebInfo configure and full cmake --build build -j8: passed
  • theme_manager_test: 1/1 passed
  • tools/check_a11y.py: passed (8 existing warnings outside this diff)
  • tools/check_engine_boundary.py --strict: passed, 0 blockers
  • git diff --check: passed
  • signed commit verified with the configured SSH signing key

Automation bridge proof

The app was launched disconnected with auto-connect disabled. A proof-only Default Dark fixture set applet/rx frequency text to Courier New at 12 px, making scoped resolution unmistakable; the fixture was removed before the final build and commit.

Before the fix, startup rendered the root DSEG frequency font and selecting Default Dark again changed it to the scoped Courier font. After explicitly parenting the stack, the immediate-startup capture and same-theme-reapply capture were byte-for-byte identical (SHA-256 449a45f21b1aed4f5014b90cf23a190cb0f3fb08ff1b51dd77884323f1fb5c0f). No radio connection or transmit action occurred.

Before: persisted scoped font missed at startup.

Before

After: scoped font is already active at startup and remains unchanged after live reapply.

After

💻 Generated with Codex with architecture by @jensenpat

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.6 Sol) and tested by @jensenpat

@jensenpat jensenpat self-assigned this Jul 16, 2026
@jensenpat jensenpat changed the title Fix RX applet frequency font scope on restart [ux] Fix RX applet frequency font scope on restart Jul 16, 2026
@jensenpat
jensenpat marked this pull request as ready for review July 16, 2026 15:36
@jensenpat
jensenpat requested a review from a team as a code owner July 16, 2026 15:36

@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.

Traced this through ThemeManager and it holds up. RxApplet declares its applet/rx scope in the constructor (RxApplet.cpp:320) before buildUI(), and applyStyleSheet resolves tokens via resolveForcontainerPathFor, which walks the widget's Qt parent chain and re-resolves on QEvent::ParentChange (ThemeManager.cpp:1709). The freq label/editor are styled while unparented and then reparented into the stack by addWidget; before this change the stack itself had no parent, so that re-resolve dead-ended at root scope and font.family.freq fell back to the root token — exactly the restart symptom in #4159. Parenting the stack to this gives the child chain a path up to applet/rx, and the scoped override is the one already covered by theme_manager_test. The root-cause writeup matches the code.

Change is minimal, uses standard Qt parent-ownership, and is confined to the RX frequency hierarchy — no null/leak/settings concerns. Nice, well-targeted fix.

Nothing blocking. Thanks for the clear root-cause narrative — it made verification straightforward.

Non-blocking note: the fix leans on the ParentChange-triggered re-resolution (the styles are still applied to the label/editor while they're unparented, and only land in scope once addWidget reparents them). That's precisely how the tracking is designed to work, so it's fine as-is — just worth knowing that the first resolveFor pass still runs at root scope and the event filter is what makes it correct.


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

@NF0T NF0T 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.

Verified the fix mechanism directly against ThemeManager::containerPathFor/applyStyleSheet (src/core/ThemeManager.cpp:1668-1724,1853-1869), not just the PR's narrative: the critical moment is m_freqStack->addWidget(m_freqLabel/m_freqEdit) (RxApplet.cpp:585,596), which fires each child's one-shot QEvent::ParentChange re-resolution before m_freqStack itself is later reparented via layout activation (:636-637). Pre-fix, m_freqStack was unparented at that moment, so the ancestor walk dead-ended at root scope — exactly the #4159 symptom. Post-fix, m_freqStack already has this as parent, so the walk finds the applet/rx scope immediately. The fix is correct.

CI green across all 7 checks. Commit signed.

Two non-blocking notes for a future pass, not blockers here:

  • Since m_freqStack's explicit parent (this) differs from its eventual layout-activation parent (inner, which is itself already parented to this earlier in the same function), Qt's layout system will emit a harmless "widget in wrong parent; moving to correct parent" warning on every RxApplet construction. Parenting to inner directly instead of this would give the identical fix without the warning.
  • This exact pattern (container built + children styled before the container itself is attached to the real widget tree) recurs elsewhere: VfoWidget.cpp's own m_freqStack/m_digOffsetStack (the PR's own comment cross-references VfoWidget as sharing this token), and — more urgently — RxApplet.cpp's own m_agcContainer/m_agcTSlider, where color.slider.foreground is scope-overridden (applet/rx green vs. root blue), meaning the AGC threshold slider is rendering the wrong color at every startup today, live, right now, unrelated to this PR. Worth a follow-up issue — recommend filing one for the AGC slider specifically since it's a currently-visible defect with no tracking issue yet.

Approving — Tier 3 only (src/gui/RxApplet.cpp), no Tier 2/1 gate to satisfy.

@NF0T
NF0T merged commit a17fec4 into aethersdr:main Jul 17, 2026
7 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.

Follow up on: Theme Editor - applet/rx font not persistant (Issue #3653)

2 participants