From 1fd794ccc14ba89869b10a28d85849df7d15b9cf Mon Sep 17 00:00:00 2001 From: DanS Date: Fri, 10 Jul 2026 15:00:15 -0500 Subject: [PATCH] fix(modals): vertically center auto-height dialogs in the window Fixed-height overlay cards were already centered, but auto-height cards hard-anchored at 15% from the top, so shorter dialogs (e.g. Migrate to a seed wallet, Import Key, About) rendered top-heavy with a large empty area below. Center auto-height cards on last frame's measured content height (already cached per dialog id in g_overlayCardHeights). A re-opened dialog centers from frame 1; only the very first open of a given dialog this session briefly anchors near the top before it re-centers. Content taller than the window top-anchors at a 16px margin. One framework change centers every modal (verified across migrate / import-key / about / seed-backup at 100%). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/ui/material/draw_helpers.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/ui/material/draw_helpers.h b/src/ui/material/draw_helpers.h index 464e413..e96a03e 100644 --- a/src/ui/material/draw_helpers.h +++ b/src/ui/material/draw_helpers.h @@ -1396,8 +1396,10 @@ inline bool BeginOverlayDialog(const OverlayDialogSpec& spec) ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle); - // Card geometry: fixed-height (large modals) is centered; auto-height reuses last frame's - // measured content height (short dialogs get short cards), capped at the viewport ratio. + // Card geometry: both fixed- and auto-height cards are VERTICALLY CENTERED in the window. + // Fixed-height centers its known height; auto-height centers last frame's measured content + // height (cached per dialog id, so a re-opened dialog is centered from frame 1 — only the very + // first open of a given dialog this session briefly anchors near the top before it re-centers). float cardX = vp_pos.x + (vp_size.x - cardWidth) * 0.5f; float cardY, cardBottomY; const bool fixedHeight = (spec.cardHeight > 0.0f); @@ -1407,12 +1409,20 @@ inline bool BeginOverlayDialog(const OverlayDialogSpec& spec) cardBottomY = cardY + cardH; g_overlayCurrentKey.clear(); } else { - cardY = vp_pos.y + vp_size.y * 0.15f; g_overlayCurrentKey = childId; - float ratioMaxY = vp_pos.y + vp_size.y * spec.cardBottomViewportRatio; auto it = g_overlayCardHeights.find(childId); - cardBottomY = (it != g_overlayCardHeights.end() && it->second > 0.0f) - ? std::min(cardY + it->second, ratioMaxY) : ratioMaxY; + const float measuredH = (it != g_overlayCardHeights.end()) ? it->second : 0.0f; + if (measuredH > 0.0f) { + // Center the measured content; if it's taller than the window, anchor at the top margin. + cardY = (measuredH < vp_size.y - 32.0f) + ? vp_pos.y + (vp_size.y - measuredH) * 0.5f + : vp_pos.y + 16.0f; + cardBottomY = cardY + measuredH; + } else { + // First frame: content height not yet known. Anchor near the top; it re-centers next frame. + cardY = vp_pos.y + vp_size.y * 0.15f; + cardBottomY = vp_pos.y + vp_size.y * spec.cardBottomViewportRatio; + } } ImVec2 cardMin(cardX, cardY), cardMax(cardX + cardWidth, cardBottomY);