From ba13875eaf2ab57d8e72df8fddaf3f278216cfbd Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 14 Jul 2026 20:10:49 -0500 Subject: [PATCH] fix(receive): size the QR popup to its content, not 85% of the window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QR popup used the same window-relative card width the Export-Key dialog just moved away from (its comment even said "Match the key-export modal: 85% of the window width"). On a large monitor that left the centered AddressCopyField floating far from its left-aligned "Address:" label and inflated the QR's empty margins. Derive the card width from the address field's own natural (chunked) box width (mirroring the key-export fix, incl. the overlay card's 28px content inset so the address stays on one line), bounded to 85% of the window as an upper limit. Also scale the responsive-QR size literals (280 fallback / 420 cap) by dpiScale() so the QR renders at the intended size on HiDPI/font-scale. No change to the QR texture / clipboard logic. Found via a workflow audit of all 27 redesigned modals for the same anti-pattern — the QR popup was the only other occurrence (0 false positives). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/ui/windows/qr_popup_dialog.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/ui/windows/qr_popup_dialog.cpp b/src/ui/windows/qr_popup_dialog.cpp index dd06f74..7e40ea3 100644 --- a/src/ui/windows/qr_popup_dialog.cpp +++ b/src/ui/windows/qr_popup_dialog.cpp @@ -64,9 +64,18 @@ void QRPopupDialog::render(App* app) auto qr = S.drawElement("dialogs.qr-popup", "qr-code"); auto actionBtn = S.button("dialogs.qr-popup", "action-button"); - // Match the key-export modal: 85% of the window width (divide out the dpiScale that - // BeginOverlayDialog re-applies, so the final card is exactly 85% at any font scale). - const float cardW = (0.85f * ImGui::GetMainViewport()->Size.x) / Layout::dpiScale(); + // Size the card to the address's own natural (chunked) box width — the widest content element — so + // AddressCopyField fills the card under its label instead of floating centered in an over-wide card + // (matches the key-export dialog). Adapts to address type + font scale; bounded to 85% of the window. + const float dp = Layout::dpiScale(); + const std::string chunkedAddr = widgets::ChunkString(s_address, 4); + const float addrPadX = ImGui::GetStyle().FramePadding.x + 4.0f; // matches AddressCopyField + const float addrBoxW = ImGui::CalcTextSize(chunkedAddr.c_str()).x + addrPadX * 2.0f + 2.0f; + // The BlurFloat overlay card insets content by 28px per side (draw_helpers BeginOverlayDialog); add + // that (+ a little slack) so the address box fits on one line under its label instead of wrapping. + const float wantW = addrBoxW + 28.0f * 2.0f + 12.0f; + const float maxW = 0.85f * ImGui::GetMainViewport()->Size.x; + const float cardW = (wantW < maxW ? wantW : maxW) / dp; material::OverlayDialogSpec ov; ov.title = TR("qr_title"); ov.p_open = &s_open; ov.style = material::OverlayStyle::BlurFloat; @@ -83,10 +92,10 @@ void QRPopupDialog::render(App* app) // Center the QR code (responsive — larger, to suit the wider modal). float window_width = ImGui::GetWindowWidth(); - float qr_size = qr.size > 0 ? (float)qr.size : 280.0f; - const float responsive = window_width * 0.5f; + float qr_size = (qr.size > 0 ? (float)qr.size : 280.0f) * dp; // schema/fallback are logical px + const float responsive = window_width * 0.5f; // window_width is already dp-scaled if (responsive > qr_size) qr_size = responsive; - if (qr_size > 420.0f) qr_size = 420.0f; + if (qr_size > 420.0f * dp) qr_size = 420.0f * dp; float padding = (window_width - qr_size) / 2.0f; if (padding < 0.0f) padding = 0.0f;