feat(market): rework Manage-Portfolio as a full-window master-detail modal

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>
This commit is contained in:
2026-07-03 18:46:46 -05:00
parent 3e6987d72f
commit 4aed72c73b
3 changed files with 339 additions and 238 deletions

View File

@@ -476,6 +476,24 @@ inline void DrawGlassPanel(ImDrawList* dl, const ImVec2& pMin,
}
}
// Full-window backdrop for a modal overlay. Lays an OPAQUE base first (so the sheet reads as
// opaque regardless of the UI-opacity slider — the acrylic path multiplies its alpha by
// GetUIOpacity(), so it can't guarantee opacity on its own), then — only when the acrylic backdrop
// is active and we are NOT in low-performance mode — draws a strong blur of the (static) window
// backdrop on top plus a dim. In low-perf mode only the opaque base is drawn (no blur cost),
// mirroring DrawGlassPanel's gating.
inline void DrawFullWindowBlurBackdrop(ImDrawList* dl, const ImVec2& pMin, const ImVec2& pMax)
{
dl->AddRectFilled(pMin, pMax, IM_COL32(9, 10, 16, 255)); // opaque base — guarantees opacity
if (IsBackdropActive() && !dragonx::ui::effects::isLowSpecMode()
&& effects::ImGuiAcrylic::IsEnabled() && effects::ImGuiAcrylic::IsAvailable()) {
auto params = GetCurrentAcrylicTheme().card;
params.blurRadius = 40.0f; // strong — spans the whole window
effects::ImGuiAcrylic::DrawAcrylicRect(dl, pMin, pMax, params, 0.0f);
dl->AddRectFilled(pMin, pMax, IM_COL32(6, 8, 18, 90)); // dim so the card reads as foreground
}
}
// ============================================================================
// Glass Card Scope (RAII) — channel-split glass-card scaffold
// ============================================================================