fix(ui): make HiDPI-overflowing containers scrollable — wizard, overlay dialogs, balance recent-tx
At font_scale 1.5 (dpiScale 1.5) three fixed, non-scrolling containers clipped content off the bottom with no scroll escape: - First-run wizard: the hand-drawn cards grow ~1.5x past the fixed window, pushing Continue / Encrypt & Continue / Skip off-screen (a setup blocker). Inject a wheel-driven scroll offset into the layout seed + a scroll indicator; gate the wheel on !IsPopupOpen + NoPopupHierarchy so an open combo popup does not scroll the wizard behind it. No-op at 1.0x. - Overlay dialogs (BeginOverlayDialog): auto-height cards taller than the viewport (About, Request Payment) ran their footer off the bottom. Add a sticky per-open overflow flag that clamps the card to the viewport and makes the content child scrollable; short dialogs still center unchanged. Give the nested settings clear-history confirm its own idSuffix so it can't inherit the parent dialog's overflow state or collide on the child window id. - Balance Recent Transactions: the dp-scaled address card evicted the recent-tx list off the non-scrolling tab host. Cap the card inside RenderSharedAddressList against the space that actually remains (minus a caller-provided reserve) so the section below stays on-screen — covers all 10 balance layouts. Verified at font_scale 1.5 across full-node + Lite + Windows (ctest green) and an adversarial diff review (two low-severity regressions found + fixed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+36
-1
@@ -177,8 +177,28 @@ void App::renderFirstRunWizard() {
|
||||
// DPI scale factor — multiply all pixel constants by dp
|
||||
const float dp = ui::Layout::dpiScale();
|
||||
|
||||
// Vertical scroll: the wizard cards are hand-drawn at absolute Y offsets and grow ~1.5x with the
|
||||
// font-scale setting, so at high scale the focused card's primary button (Continue / Encrypt & Continue
|
||||
// / Skip) can fall below the fixed window. Offset the whole layout by a wheel-driven scroll, clamped to
|
||||
// last frame's measured content height, so every control stays reachable. The window keeps
|
||||
// NoScrollWithMouse, so ImGui doesn't consume the wheel — we read the raw delta and apply our own offset.
|
||||
static float s_wizScroll = 0.0f, s_wizContentH = 0.0f;
|
||||
if (ImGui::IsWindowAppearing()) s_wizScroll = 0.0f;
|
||||
const float wizMaxScroll = std::max(0.0f, s_wizContentH - winSize.y);
|
||||
// Don't steal the wheel from an open combo popup (e.g. the 9-item Language dropdown, which is a
|
||||
// scrollable popup): NoPopupHierarchy stops the popup counting as hovering the wizard, and the
|
||||
// IsPopupOpen guard ensures no wheel is consumed for the whole wizard while any popup is showing.
|
||||
const bool wizPopupOpen = ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel);
|
||||
if (wizMaxScroll > 0.0f && !wizPopupOpen &&
|
||||
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) {
|
||||
float wheel = ImGui::GetIO().MouseWheel;
|
||||
if (wheel != 0.0f) s_wizScroll -= wheel * 60.0f * dp;
|
||||
}
|
||||
s_wizScroll = std::max(0.0f, std::min(s_wizScroll, wizMaxScroll));
|
||||
const float scrollY = s_wizScroll;
|
||||
|
||||
// --- Header: Logo + Welcome ---
|
||||
float headerCy = winPos.y + 20.0f * dp;
|
||||
float headerCy = winPos.y - scrollY + 20.0f * dp;
|
||||
float logoSize = S.drawElement("screens.first-run", "logo").sizeOr(56.0f);
|
||||
if (logo_tex_ != 0) {
|
||||
float aspect = (logo_h_ > 0) ? (float)logo_w_ / (float)logo_h_ : 1.0f;
|
||||
@@ -1428,6 +1448,21 @@ void App::renderFirstRunWizard() {
|
||||
// Merge channels: backgrounds → content → overlays
|
||||
dl->ChannelsMerge();
|
||||
|
||||
// Measure this frame's content height (feeds next frame's scroll clamp) and, when it overflows the
|
||||
// window, draw a slim scroll indicator so the off-screen content is discoverable.
|
||||
{
|
||||
float contentBottom = std::max(card0Bot, std::max(card1Bot, card2Bot));
|
||||
s_wizContentH = (contentBottom - winPos.y + scrollY) + 24.0f * dp;
|
||||
if (wizMaxScroll > 0.0f && s_wizContentH > 0.0f) {
|
||||
float trackH = winSize.y - 8.0f * dp;
|
||||
float thumbH = std::min(trackH, std::max(32.0f * dp, trackH * (winSize.y / s_wizContentH)));
|
||||
float thumbY = winPos.y + 4.0f * dp + (trackH - thumbH) * (scrollY / wizMaxScroll);
|
||||
float barX = winPos.x + winSize.x - 6.0f * dp;
|
||||
dl->AddRectFilled(ImVec2(barX, thumbY), ImVec2(barX + 3.0f * dp, thumbY + thumbH),
|
||||
ui::material::WithAlpha(ui::material::OnSurface(), 55), 1.5f * dp);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user