diff --git a/src/ui/material/draw_helpers.h b/src/ui/material/draw_helpers.h index bd442cd..f3222a9 100644 --- a/src/ui/material/draw_helpers.h +++ b/src/ui/material/draw_helpers.h @@ -1039,18 +1039,25 @@ inline bool DrawDialogTitleBar(const char* title, bool* p_open, ImU32 accent_col // "A blur overlay was drawn this frame" flag + a 1-frame latch. App::render builds its // effect-suppression guard at the TOP of the frame, before dialogs dispatch, so it reads the // LAST-frame latch (a stable signal) rather than this frame's in-progress state. -inline bool& BlurOverlayDrawnThisFrameRef() { static bool v = false; return v; } -inline bool& BlurOverlayActiveLastFrameRef() { static bool v = false; return v; } -inline void MarkBlurOverlayDrawn() { BlurOverlayDrawnThisFrameRef() = true; } +inline bool& BlurOverlayDrawnThisFrameRef() { static bool v = false; return v; } +inline bool& BlurOverlayActiveLastFrameRef() { static bool v = false; return v; } +inline bool*& BlurOverlayOpenFlagRef() { static bool* p = nullptr; return p; } +// Record that a blur overlay drew this frame, along with its open flag (so the latch below can tell +// "still open next frame" from "closed this frame" and match the modal's actual open state — no +// extra frame of suppression on close). +inline void MarkBlurOverlayDrawn(bool* openFlag) { BlurOverlayDrawnThisFrameRef() = true; BlurOverlayOpenFlagRef() = openFlag; } inline bool AnyBlurOverlayActiveLastFrame() { return BlurOverlayActiveLastFrameRef(); } -// Latch this frame's state for the next frame's guard; on the open->closed transition, invalidate -// the acrylic capture so the other glass panels re-capture the (overlay-free) background. Call once -// at the end of App::render. +// Latch whether an overlay will still be up next frame (drew this frame AND its open flag is still +// set after this frame's Esc/Close/outside-click handling); on the open->closed transition, +// invalidate the acrylic capture so the other glass panels re-capture the (overlay-free) +// background. Call once at the end of App::render. inline void LatchBlurOverlayActive() { - bool now = BlurOverlayDrawnThisFrameRef(); - if (BlurOverlayActiveLastFrameRef() && !now) effects::ImGuiAcrylic::InvalidateCapture(); - BlurOverlayActiveLastFrameRef() = now; + bool* pf = BlurOverlayOpenFlagRef(); + bool stillOpen = BlurOverlayDrawnThisFrameRef() && (!pf || *pf); + if (BlurOverlayActiveLastFrameRef() && !stillOpen) effects::ImGuiAcrylic::InvalidateCapture(); + BlurOverlayActiveLastFrameRef() = stillOpen; BlurOverlayDrawnThisFrameRef() = false; + BlurOverlayOpenFlagRef() = nullptr; } // True during the frames a blur overlay is (re)capturing the live backdrop — the scroll-fade shader @@ -1197,7 +1204,7 @@ inline bool BeginOverlayDialog(const OverlayDialogSpec& spec) // few frames on open/resize, then reuse the frozen blurred snapshot. Low-spec / acrylic-off falls // back to an opaque base inside DrawFullWindowBlurBackdrop (no blur cost). if (blur) { - MarkBlurOverlayDrawn(); + MarkBlurOverlayDrawn(spec.p_open); BlurCaptureState& st = BlurCaptureStateFor(scrimId); int frame = ImGui::GetFrameCount(); bool justOpened = (st.lastSeenFrame < frame - 1);