From 4d78ca0d7d989abeb9259638d9aceb2739f1ce1a Mon Sep 17 00:00:00 2001 From: DanS Date: Thu, 11 Jun 2026 17:38:20 -0500 Subject: [PATCH] fix(keys): auto-width action buttons + content-fit key/address fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three layout fixes in the export-key modal, all symptoms of widths/heights authored as raw pixels while text scales with the user's font setting: - "Copy to Clipboard" no longer clips — the Show/Hide · Copy · QR buttons are auto-width (size 0) so they always fit their label; - those buttons now share one font, so Show/Hide matches Copy (was a smaller toggle-button font); - the read-only address and key fields are sized to the wrapped text instead of a fixed 60/80px, removing the empty space below their value. Co-Authored-By: Claude Opus 4.8 --- src/ui/windows/key_export_dialog.cpp | 43 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/ui/windows/key_export_dialog.cpp b/src/ui/windows/key_export_dialog.cpp index a92d4cc..88aabe8 100644 --- a/src/ui/windows/key_export_dialog.cpp +++ b/src/ui/windows/key_export_dialog.cpp @@ -66,7 +66,6 @@ void KeyExportDialog::render(App* app) auto addrInput = S.input("dialogs.key-export", "address-input"); auto revealBtn = S.button("dialogs.key-export", "reveal-button"); auto keyDisplay = S.drawElement("dialogs.key-export", "key-display"); - auto toggleBtn = S.button("dialogs.key-export", "toggle-button"); auto copyBtn = S.button("dialogs.key-export", "copy-button"); auto closeBtn = S.button("dialogs.key-export", "close-button"); @@ -107,9 +106,14 @@ void KeyExportDialog::render(App* app) char addr_buf[512]; strncpy(addr_buf, s_address.c_str(), sizeof(addr_buf) - 1); addr_buf[sizeof(addr_buf) - 1] = '\0'; + // Fit the field to the wrapped address (no excess empty space below it). + (void)addrInput; + const float addrFieldH = + ImGui::CalcTextSize(addr_buf, nullptr, false, + ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x * 2.0f).y + + ImGui::GetStyle().FramePadding.y * 2.0f + 4.0f; ImGui::InputTextMultiline("##Address", addr_buf, sizeof(addr_buf), - ImVec2(-1, (addrInput.height > 0 ? addrInput.height : 60) * Layout::dpiScale()), - ImGuiInputTextFlags_ReadOnly); + ImVec2(-1, addrFieldH), ImGuiInputTextFlags_ReadOnly); } else { char addr_buf[128]; strncpy(addr_buf, s_address.c_str(), sizeof(addr_buf) - 1); @@ -199,34 +203,36 @@ void KeyExportDialog::render(App* app) } else { // Key has been fetched - display it + // Fit the field to the wrapped key (same length whether shown or masked). + (void)keyDisplay; + char key_buf[1024]; if (s_show_key) { - // Show the actual key - char key_buf[1024]; strncpy(key_buf, s_key.c_str(), sizeof(key_buf) - 1); - key_buf[sizeof(key_buf) - 1] = '\0'; - ImGui::InputTextMultiline("##Key", key_buf, sizeof(key_buf), - ImVec2(-1, (keyDisplay.height > 0 ? keyDisplay.height : 80) * Layout::dpiScale()), ImGuiInputTextFlags_ReadOnly); } else { - // Show masked std::string masked(s_key.length(), '*'); - char masked_buf[1024]; - strncpy(masked_buf, masked.c_str(), sizeof(masked_buf) - 1); - masked_buf[sizeof(masked_buf) - 1] = '\0'; - ImGui::InputTextMultiline("##Key", masked_buf, sizeof(masked_buf), - ImVec2(-1, (keyDisplay.height > 0 ? keyDisplay.height : 80) * Layout::dpiScale()), ImGuiInputTextFlags_ReadOnly); + strncpy(key_buf, masked.c_str(), sizeof(key_buf) - 1); } + key_buf[sizeof(key_buf) - 1] = '\0'; + const float keyFieldH = + ImGui::CalcTextSize(key_buf, nullptr, false, + ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x * 2.0f).y + + ImGui::GetStyle().FramePadding.y * 2.0f + 4.0f; + ImGui::InputTextMultiline("##Key", key_buf, sizeof(key_buf), + ImVec2(-1, keyFieldH), ImGuiInputTextFlags_ReadOnly); - // Action row: Show/Hide · Copy · QR + // Action row: Show/Hide · Copy · QR. Auto-width buttons (size 0) so the label text never + // clips at the user's font scale, and ONE shared font so they all match. ImGui::Spacing(); + ImFont* actionFont = S.resolveFont(copyBtn.font); - if (material::StyledButton(s_show_key ? TR("hide") : TR("show"), ImVec2(toggleBtn.width, 0), S.resolveFont(toggleBtn.font))) { + if (material::StyledButton(s_show_key ? TR("hide") : TR("show"), ImVec2(0, 0), actionFont)) { s_show_key = !s_show_key; if (!s_show_key) s_show_qr = false; // hiding the key also hides its QR } ImGui::SameLine(); - if (material::StyledButton(TR("copy_to_clipboard"), ImVec2(copyBtn.width, 0), S.resolveFont(copyBtn.font))) { + if (material::StyledButton(TR("copy_to_clipboard"), ImVec2(0, 0), actionFont)) { // Auto-clearing clipboard: the key (as sensitive as the seed) is wiped after ~45s. app->copySecretToClipboard(s_key); } @@ -234,8 +240,7 @@ void KeyExportDialog::render(App* app) // QR (only once revealed) — for scanning the key into another wallet. if (s_show_key) { ImGui::SameLine(); - if (material::StyledButton(s_show_qr ? TR("hide_qr") : TR("show_qr"), - ImVec2(copyBtn.width, 0), S.resolveFont(copyBtn.font))) { + if (material::StyledButton(s_show_qr ? TR("hide_qr") : TR("show_qr"), ImVec2(0, 0), actionFont)) { s_show_qr = !s_show_qr; } }