fix(keys): auto-width action buttons + content-fit key/address fields

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 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 17:38:20 -05:00
parent 00ee61fe64
commit 4d78ca0d7d

View File

@@ -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;
}
}