Address two GUI-review points:
1. Light themes no longer get a dark modal backdrop: DrawFullWindowBlurBackdrop
now tints toward the theme app background (WithAlpha(Background(), ...)) for
both the opaque base and the frost, so a light theme gets a light frosted
backdrop and a dark theme a dark one. Fixes all blur overlays, not just the
lock screen.
2. The lock screen now blurs the WHOLE window (sidebar included), not just the
content area: renderLockScreen opens a full-viewport borderless overlay window
(##LockOverlay, same pattern as the modal overlays / portfolio, opened from
within ##ContentArea) with an input blocker, instead of drawing in the content
child. Removed the theme-independent dark scrim (contradicted point 1).
Auth logic untouched. Needs GUI re-verify of all auth paths + that the whole
screen (incl. sidebar) obscures on lock and unlock returns cleanly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The two Phase 3 "bespoke overlays" aren't content modals: the send-error is an
in-tab glass banner (already consistent — left as-is), and the shutdown screen is
a teardown screen where a blur backdrop would be semantically wrong (should read
as "closing") + risky on the teardown path. Per that finding, apply minor
consistency polish to the shutdown screen only:
- Share the overlay-scrim tone via a new material::OverlayScrimColor(opacity),
used by both the dialog scrim and the shutdown scrim (was a slightly different
hardcoded 0.06/0.06/0.08 → now the 0.04/0.04/0.06 dialog base).
- "Shutting Down" title → theme Warning() amber (was hardcoded gold).
- Force-Quit confirm destructive button → theme Error() (alpha-varied) instead of
hardcoded reds.
No behavior change; the shutdown scrim stays opaque (no blur).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Flip the positional BeginOverlayDialog overload's default to blurBackdrop=true, so
every app dialog (~43 call sites) now renders its card on the live-blur backdrop
instead of the opaque scrim — matching the Manage-Portfolio look. Cards stay
auto-height (small dialogs stay small = "card for small") and render opaque via
the existing sole-consumer fallback (a translucent glass card would thrash the
single-slot blur cache against the radius-64 backdrop). Nested dialogs (address
book edit) already pass a distinct idSuffix, so their blur windows/capture keys
don't collide. A dialog that wants the old scrim can pass a spec with
blurBackdrop=false. Big visual change — needs a GUI sweep; trivially reverted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The adversarial review found the ModalRenderGuard lagged the old
PortfolioEditorActive() signal by one extra frame on CLOSE (a possible 1-frame
"opaque panels" flash). Latch the overlay's open flag (already available via
spec.p_open) — "drew this frame AND still open after Esc/Close/outside handling" —
instead of just "drew last frame", so the guard drops and the acrylic re-capture
fire on the same frame the overlay closes, matching the old inline behavior on
both edges.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dogfood the Phase 0 framework: RenderPortfolioEditor now opens via
material::BeginOverlayDialog(BlurFloat) + EndOverlayDialog instead of its own
inline overlay scaffold, and uses the promoted material:: SegmentedControl /
RightAlignX / BeginFadeScrollChild helpers (overlay_scroll.h). Delete the
portfolio's inline backdrop/capture-once state machine + its PfEditState capture
statics + the four local helper copies. App::render's ModalRenderGuard is now
driven by the modal-agnostic AnyBlurOverlayActiveLastFrame() (timing-equivalent),
and LatchBlurOverlayActive() at frame end handles the acrylic re-capture on close.
Framework tweak: floating cards pop the card WindowPadding after BeginChild (so
nested children don't inherit it) and center button labels, keeping the net
style-var count at 2 so EndOverlayDialog is unchanged and GlassCard stays
byte-identical. RenderPortfolioEditor: 357 -> 282 lines. Needs GUI verification
that the portfolio modal is visually/behaviourally unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refactor BeginOverlayDialog to run through an OverlayDialogSpec + OverlayStyle
(GlassCard vs BlurFloat) with orthogonal flags (blurBackdrop / floatingContent /
plainHeading, fixed vs auto card height). The classic look is now GlassCard with
all flags off; the existing positional overload forwards to it → all ~43 current
dialogs are byte-identical (verified line-by-line). The BlurFloat path — live-blur
backdrop with per-overlay capture-once (frame-gap arming), floating content, plain
h6 heading — is implemented but unused until Phase 1 dogfoods it on the portfolio.
Also replace the unusable open-refcount with a per-frame drawn flag + last-frame
latch that invalidates the acrylic capture on the overlay's close transition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First step toward unifying all app modals on the Manage-Portfolio visual style.
Add, as shared material:: helpers (additive — no caller yet, no visible change):
- blur-overlay open refcount + 1-frame latch (Push/Pop/AnyBlurOverlayActive[LastFrame],
LatchBlurOverlayActive) so App::render's effect guard can be modal-agnostic;
- capture-frame query (IsCapturingBlurBackdrop) for scroll-fade suppression;
- RightAlignX and SegmentedControl (promoted verbatim from market_tab);
- BeginFadeScrollChild/EndFadeScrollChild in a dedicated overlay_scroll.h (kept
out of the widely-included draw_helpers.h because effects::ScrollFadeShader's GL
headers clash with SDL's in some TUs).
Also fix IsCurrentWindowOverlayDialog to prefix-match "##OverlayScrim" so suffixed
overlay windows are recognized by the modal-aware hover check.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Raising the backdrop radius alone would thrash the shared radius-keyed blur cache (the
glass panels blur at ~30). Instead, while a full-window blur overlay is active, glass
panels use their opaque fallback (IsFullWindowBlurOverlayActive) — they're covered by the
backdrop anyway — so the backdrop is the SOLE applyBlur caller and can use a strong custom
radius (64) with the cache staying coherent and frozen. The flag is toggled alongside the
theme-effect suppression by a RAII guard in App::render().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switch the live-blur behind the modal from a per-frame capture (which flickered from
per-frame re-blur non-determinism) to capture-once-on-open, re-captured only on resize.
- Insert the acrylic live-capture callback into the overlay draw list ONLY for a few
frames on open and whenever the viewport size changes; other frames reuse the frozen
blurred snapshot (blurCacheValid_), so there's no per-frame capture/re-blur cost. State:
s_pf_was_open (reset on close), s_pf_capture_frames, s_pf_capture_w/h.
Two fixes from an adversarial review of the timing/pipeline interaction:
- Do NOT override the backdrop blurRadius to 40. applyBlur caches one blurred buffer
keyed on radius, shared with every glass panel (market cards + the modal preview card,
radius ~30). A different radius thrashed that cache every frame and made the backdrop
sample the wrong blur, defeating the frozen-blur guarantee. Using the theme card's
radius keeps one blur serving all surfaces, frozen.
- Skip the blur on the overlay's first frame (allowBlur=false) — the live content isn't
captured until that frame's render, so blurring then would show stale/background pixels
for one frame; draw the plain opaque scrim instead.
Compiles on OpenGL (Linux) + DX11 (Windows). Needs on-device visual verification.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The acrylic system only blurred a frozen snapshot of the static app background. Add
an overlay-time re-capture so the Manage-portfolio modal blurs the LIVE tab content
behind it.
- AcrylicMaterial::captureLiveFramebuffer() (GL blit of FB 0 / DX11 CopyResource of the
backbuffer + no-backend stub) mirrors captureBackgroundDirect but bypasses the
dirtyFrames_ gate so it refreshes every frame the overlay is open, forcing a re-blur.
- ImGuiAcrylic::GetLiveCaptureCallback() returns a draw callback for it.
- market_tab: the modal inserts that callback (+ ImDrawCallback_ResetRenderState) at the
START of its overlay draw list, before the backdrop, so the capture holds the app UI
drawn below and the backdrop blurs it. On close, InvalidateCapture() re-captures the
background so other glass panels don't keep blurring the stale live capture.
- Panel theme-effects are suppressed during the market render while the modal is open
(their foreground-draw-list borders draw above all windows and would otherwise bleed
over the overlay). Market tab body is rendered again (no longer skipped).
- Backdrop draws the acrylic at full strength (fallbackColor.w=1) over an opaque base so
the blurred content reads clearly; lighter dim.
Design mapped via an Explore investigation of the capture/blur pipeline; compiles on
both OpenGL (Linux) and DX11 (Windows cross-build). Needs on-device visual verification.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Combine the old list/edit modes into one master-detail view rendered as a
full-window overlay instead of a floating dialog.
- Backdrop: new material::DrawFullWindowBlurBackdrop draws an opaque base first
(so the sheet is opaque regardless of the UI-opacity slider — the acrylic path
multiplies its alpha by GetUIOpacity), then a strong full-window blur of the
backdrop, gated exactly like DrawGlassPanel so low-performance mode skips the
blur entirely (just the opaque scrim).
- Frame: bespoke full-window overlay (not BeginOverlayDialog) that mirrors the
scrim plumbing and preserves both overlay popup gotchas verbatim (no focus-steal
and no outside-click dismiss while a combo / color picker is open). Title-bar X,
Esc, and outside-click all dismiss.
- Left (master): selectable group list with accent bar + icon + name + value line,
and a pinned "Add group" button.
- Right (detail): live preview + label header, then a single-open accordion
(Appearance = color + outline opacity + icon; Price; Addresses) so only one
control group shows at a time — far less cluttered than the old two-column form.
- Footer: Delete / Revert / Save. Editing auto-commits named groups on navigation
and on close (preserving grid geometry); unnamed drafts are dropped.
- s_pf_editing tri-state replaced by s_pf_sel (+ accordion open-state); the Manage
button and grid-card click open with a valid selection.
Design + adversarial review done via multi-agent workflows (understand/design, then
a 3-lens ImGui-lifecycle / state-safety / backdrop review; zero confirmed defects).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BeginOverlayDialog called ImGui::SetNextWindowFocus() every frame to keep the
dialog on top. That forced the scrim back to the front each frame and closed
any popup opened from inside the dialog — so the portfolio editor's price-basis
Combo and the custom color-picker popup flashed open then vanished, and clicking
a dropdown item that overhung the card could trip the outside-click-dismiss and
close the whole dialog.
Make the overlay popup-aware: compute overlayPopupOpen (IsPopupOpen with
AnyPopupId|AnyPopupLevel) and (1) skip SetNextWindowFocus while a popup is
showing so it stays focused/on-top, and (2) skip the outside-click-dismiss while
a popup is open so clicks inside it don't close the dialog. No change when no
popup is open, so existing dialogs are unaffected.
Full-node + Lite build clean; ctest 1/1; hygiene clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mechanical, behavior-preserving consolidations from the audit. Rendering
extractions were kept byte-equivalent; sites that couldn't be made identical
were left as-is (noted below).
Shared helpers:
- util::truncateMiddle(s,maxLen) / (s,front,back) in text_format.h — replaces
6 file-local middle-ellipsis truncators + several inline substr sites
(send/receive/transactions/balance_recent_tx/explorer + app.cpp + 3 dialogs).
Carries the maxLen<=3 guard, fixing the latent unsigned-underflow copies.
- material::LoadingDots() in draw_helpers.h — one animated-ellipsis source for
8 copy-pasted spinner sites (identical GetTime()*3 phase preserved).
- Reuse the existing FormatHashrate() in explorer_tab + peers_tab (dropped two
inline hashrate ladders).
- material::DrawButtonGlassOverlay() — the glass-fill/rim/tactile overlay block
shared by TactileButton / TactileSmallButton / schema TactileButton.
- material::CollapsibleHeader() — the invisible-button + label + chevron idiom
(3 of 5 settings_page sites; RPC/Debug headers skipped — non-identical).
- material::GlassCardScope (RAII) — the ChannelsSplit/Indent/DrawGlassPanel/
ChannelsMerge card scaffold (5 settings_page cards; About/send/receive skipped
— different padding / logo interleaving).
- material::DialogWarningHeader()/DialogConfirmFooter() — warning header +
50/50 Cancel/danger footer across the confirm dialogs; button height moved
from a hardcoded 40px into ui.toml (components.overlay-dialog.confirm-btn-height).
- File-local enterLowSpec()/exitLowSpec() collapse the 3 low-spec snapshot copies.
i18n: wrapped hardcoded English in the shared balance render paths and the
whole Lite lifecycle/security section in TR(), with English defaults added to
loadBuiltinEnglish() (res/lang/*.json left for the translation tooling — TR
falls back to English, so output is unchanged).
Full-node + Lite build clean; ctest 1/1; hygiene clean. These are rendering
changes — the Settings page (cards/headers/confirm dialogs), all tactile
buttons, and the Lite settings section warrant a screenshot check.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add material::Tooltip / BeginTooltip / EndTooltip wrappers (tooltip_style.h)
that scope a small window padding (8x4, dpi-scaled) and ~85% opacity to
tooltips only, then route the tooltip call sites through them. Menus and combo
dropdowns are untouched (they keep the global opaque PopupBg).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The overlay dialog's content child is AutoResizeY, but the glass card behind
it was drawn to a fixed viewport ratio — leaving a tall band of empty glass
below short dialogs (e.g. the key-export modal had a gap under its Close
button). Measure the rendered card height each frame and reuse it next frame
to draw the glass to the content; fall back to (and stay capped at) the ratio
so tall dialogs are unchanged and can't run off-screen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every BeginOverlayDialog is passed a raw pixel card width (550, 620, …), but the fonts and
spacing inside scale with Layout::dpiScale() — which includes the user's font-size setting. At
any non-default scale the content outgrew the fixed card, so text overflowed the card edge and
elements misaligned. Scale the card width by dpiScale() (no-op at the default 1.0 scale) and clamp
it to the viewport so a large scale can't push it off-screen. Fixes all overlay dialogs at once.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BeginOverlayDialog dismisses on a click outside the card via IsMouseClicked (mouse-down). When
the dialog is opened by a button that fires on the same frame (e.g. the mining tab's
"Update miner…" button), that opening click is still registered as an outside-click, so the
dialog opens and instantly closes — it just "flashes". Skip the outside-click dismissal on the
frame the scrim window first appears (ImGui::IsWindowAppearing()); normal outside-click closing
is unaffected on every subsequent frame. Fixes all overlay dialogs, not just the xmrig updater.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add expanded address icon picker with search, bottom-aligned actions, and improved modal sizing
- Embed a pickaxe icon font subset and wire it into typography/address icon rendering
- Track view-only shielded addresses and prevent sends from non-spendable z-addresses
- Improve address transfer dialog sizing, max amount handling, and text clipping
- Tune main header layout values in ui.toml
- Update README, codebase overview, and third-party license documentation
- Replace all hardcoded English strings with TR() translation keys across
every tab, dialog, and component (~20 UI files)
- Expand all 8 language files (de, es, fr, ja, ko, pt, ru, zh) with
complete translations (~37k lines added)
- Improve i18n loader with exe-relative path fallback and English base
fallback for missing keys
- Add pool-side hashrate polling via pool stats API in xmrig_manager
- Introduce Layout::beginFrame() per-frame caching and refresh balance
layout config only on schema generation change
- Offload daemon output parsing to worker thread
- Add CJK subset fallback font for Chinese/Japanese/Korean glyphs
- Fix z_importwallet to use full path instead of filename only
- Add rescanBlockchain() method that restarts daemon with -rescan flag
- Track rescan progress via daemon output parsing and getrescaninfo RPC
- Display rescan progress in status bar with animated indicator when starting
- Improve dark theme card contrast: lighter surface-variant, tinted borders, stronger rim-light
Full-node GUI wallet for DragonX cryptocurrency.
Built with Dear ImGui, SDL3, and OpenGL3/DX11.
Features:
- Send/receive shielded and transparent transactions
- Autoshield with merged transaction display
- Built-in CPU mining (xmrig)
- Peer management and network monitoring
- Wallet encryption with PIN lock
- QR code generation for receive addresses
- Transaction history with pagination
- Console for direct RPC commands
- Cross-platform (Linux, Windows)