refactor(settings): import dialog layout polish
Several layout refinements to the Import Private/Viewing Key dialog: - Widen the dialog to 640px so the one-line warning under the heading no longer wraps. - Vertically center DialogWarningHeader's label with the (taller) warning icon instead of top-aligning it — a consistent fix for every warning header. - Add a small gap between the key input's text and the flush eye toggle. - Center + slightly enlarge the Paste / Clear buttons. - Center the Import/Sweep + Close action buttons. - Scan-height control: put the numeric input first with the slider below it, and drop the redundant "0 = rescan from the start" hint (0 is the field default; the transparent-key note is kept). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
src/app.cpp
42
src/app.cpp
@@ -2775,8 +2775,15 @@ static void RenderScanHeightControl(char* buf, size_t bufSize, int tipHeight, bo
|
|||||||
|
|
||||||
ImGui::BeginDisabled(!enabled);
|
ImGui::BeginDisabled(!enabled);
|
||||||
|
|
||||||
|
// Numeric entry first — the slider sits below it.
|
||||||
|
ImGui::SetNextItemWidth(availW);
|
||||||
|
ImGui::InputText("##importscanheight", buf, bufSize, ImGuiInputTextFlags_CharsDecimal);
|
||||||
|
cur = buf[0] ? std::atoi(buf) : 0; // reflect a just-typed value in the slider below
|
||||||
|
if (cur < 0) cur = 0;
|
||||||
|
|
||||||
if (tipHeight > 0) {
|
if (tipHeight > 0) {
|
||||||
const float barW = availW; // slider spans the panel interior, stacked above the field
|
ImGui::Spacing();
|
||||||
|
const float barW = availW; // slider spans the panel interior, below the field
|
||||||
const float barH = ImGui::GetFrameHeight(); // match the numeric field's height (already dp-scaled)
|
const float barH = ImGui::GetFrameHeight(); // match the numeric field's height (already dp-scaled)
|
||||||
const float barRound = barH * 0.5f;
|
const float barRound = barH * 0.5f;
|
||||||
const float thumbR = barH * 0.5f;
|
const float thumbR = barH * 0.5f;
|
||||||
@@ -2828,10 +2835,6 @@ static void RenderScanHeightControl(char* buf, size_t bufSize, int tipHeight, bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exact numeric entry — full-width beneath the slider.
|
|
||||||
ImGui::SetNextItemWidth(availW);
|
|
||||||
ImGui::InputText("##importscanheight", buf, bufSize, ImGuiInputTextFlags_CharsDecimal);
|
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2845,7 +2848,7 @@ void App::renderImportKeyDialog()
|
|||||||
ov.title = viewMode ? TR("import_viewkey_title") : TR("import_key_title");
|
ov.title = viewMode ? TR("import_viewkey_title") : TR("import_key_title");
|
||||||
ov.p_open = &show_import_key_;
|
ov.p_open = &show_import_key_;
|
||||||
ov.style = m::OverlayStyle::BlurFloat;
|
ov.style = m::OverlayStyle::BlurFloat;
|
||||||
ov.cardWidth = 520.0f;
|
ov.cardWidth = 640.0f; // wide enough that the one-line warning under the heading doesn't wrap
|
||||||
ov.idSuffix = "importkey";
|
ov.idSuffix = "importkey";
|
||||||
if (!m::BeginOverlayDialog(ov)) return;
|
if (!m::BeginOverlayDialog(ov)) return;
|
||||||
|
|
||||||
@@ -2902,21 +2905,26 @@ void App::renderImportKeyDialog()
|
|||||||
// revealed) — like the send tab — so the user can verify before pasting.
|
// revealed) — like the send tab — so the user can verify before pasting.
|
||||||
const float fieldH = ImGui::GetFrameHeight();
|
const float fieldH = ImGui::GetFrameHeight();
|
||||||
const ImVec2 iconSz(fieldH, fieldH);
|
const ImVec2 iconSz(fieldH, fieldH);
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - fieldH);
|
const float eyeGap = ui::Layout::spacingSm(); // breathing room between the text and the eye button
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - fieldH - eyeGap);
|
||||||
ImGuiInputTextFlags flags = import_key_reveal_ ? 0 : ImGuiInputTextFlags_Password;
|
ImGuiInputTextFlags flags = import_key_reveal_ ? 0 : ImGuiInputTextFlags_Password;
|
||||||
ImGui::InputText("##importkey", import_key_input_, sizeof(import_key_input_), flags);
|
ImGui::InputText("##importkey", import_key_input_, sizeof(import_key_input_), flags);
|
||||||
const ImVec2 fieldMin = ImGui::GetItemRectMin(); // anchor for the paste-preview overlay
|
const ImVec2 fieldMin = ImGui::GetItemRectMin(); // anchor for the paste-preview overlay
|
||||||
ImGui::SameLine(0, 0);
|
ImGui::SameLine(0, eyeGap);
|
||||||
m::IconButtonStyle eyeSt;
|
m::IconButtonStyle eyeSt;
|
||||||
eyeSt.hoverBg = m::WithAlpha(m::OnSurface(), 30);
|
eyeSt.hoverBg = m::WithAlpha(m::OnSurface(), 30);
|
||||||
eyeSt.bgRounding = 4.0f * dp; // match the input frame's corners (it sits flush at the field's edge)
|
eyeSt.bgRounding = 4.0f * dp;
|
||||||
eyeSt.tooltip = TR("import_key_reveal_tip");
|
eyeSt.tooltip = TR("import_key_reveal_tip");
|
||||||
if (m::IconButton("##revealkey", import_key_reveal_ ? ICON_MD_VISIBILITY_OFF : ICON_MD_VISIBILITY,
|
if (m::IconButton("##revealkey", import_key_reveal_ ? ICON_MD_VISIBILITY_OFF : ICON_MD_VISIBILITY,
|
||||||
m::Type().iconSmall(), iconSz, eyeSt))
|
m::Type().iconSmall(), iconSz, eyeSt))
|
||||||
import_key_reveal_ = !import_key_reveal_;
|
import_key_reveal_ = !import_key_reveal_;
|
||||||
|
|
||||||
// Paste / Clear — labelled buttons.
|
// Paste / Clear — centered, slightly larger labelled buttons.
|
||||||
const bool pasteClicked = m::TactileButton(TR("paste"));
|
const float actBtnW = 104.0f * dp;
|
||||||
|
const float actTotal = actBtnW * 2.0f + ImGui::GetStyle().ItemSpacing.x;
|
||||||
|
const float actOff = (ImGui::GetContentRegionAvail().x - actTotal) * 0.5f;
|
||||||
|
if (actOff > 0.0f) ImGui::SetCursorPosX(ImGui::GetCursorPosX() + actOff);
|
||||||
|
const bool pasteClicked = m::TactileButton(TR("paste"), ImVec2(actBtnW, 0));
|
||||||
const bool pasteHovered = ImGui::IsItemHovered();
|
const bool pasteHovered = ImGui::IsItemHovered();
|
||||||
if (pasteClicked) {
|
if (pasteClicked) {
|
||||||
const char* clipboard = ImGui::GetClipboardText();
|
const char* clipboard = ImGui::GetClipboardText();
|
||||||
@@ -2928,7 +2936,7 @@ void App::renderImportKeyDialog()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (m::TactileButton(TR("clear"))) sodium_memzero(import_key_input_, sizeof(import_key_input_));
|
if (m::TactileButton(TR("clear"), ImVec2(actBtnW, 0))) sodium_memzero(import_key_input_, sizeof(import_key_input_));
|
||||||
|
|
||||||
// While Paste is hovered and the field is empty, preview the trimmed clipboard INSIDE the field —
|
// While Paste is hovered and the field is empty, preview the trimmed clipboard INSIDE the field —
|
||||||
// masked with '*' unless the key is revealed — coloured by how it would classify (green ok / amber
|
// masked with '*' unless the key is revealed — coloured by how it would classify (green ok / amber
|
||||||
@@ -3079,8 +3087,10 @@ void App::renderImportKeyDialog()
|
|||||||
RenderScanHeightControl(import_key_scan_height_, sizeof(import_key_scan_height_),
|
RenderScanHeightControl(import_key_scan_height_, sizeof(import_key_scan_height_),
|
||||||
tip, !transparentKey, dp, availW);
|
tip, !transparentKey, dp, availW);
|
||||||
|
|
||||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(m::OnSurfaceDisabled()), "%s",
|
// Only note why the control is inert for a transparent key; the generic "0 = rescan from the
|
||||||
transparentKey ? TR("import_scan_transparent") : TR("import_scan_hint"));
|
// start" hint was dropped as self-evident (0 is the field's default).
|
||||||
|
if (transparentKey)
|
||||||
|
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(m::OnSurfaceDisabled()), "%s", TR("import_scan_transparent"));
|
||||||
|
|
||||||
ImGui::Unindent(padX);
|
ImGui::Unindent(padX);
|
||||||
ImGui::Dummy(ImVec2(0, padY));
|
ImGui::Dummy(ImVec2(0, padY));
|
||||||
@@ -3150,6 +3160,10 @@ void App::renderImportKeyDialog()
|
|||||||
// Sweep needs a spending key AND a destination (a picked address when not using a fresh one).
|
// Sweep needs a spending key AND a destination (a picked address when not using a fresh one).
|
||||||
const bool destReady = !sweepMode || sweep_dest_mode_ == 0 || sweep_dest_pick_[0] != '\0';
|
const bool destReady = !sweepMode || sweep_dest_mode_ == 0 || sweep_dest_pick_[0] != '\0';
|
||||||
const bool canAct = recognized && state_.connected && !running && destReady;
|
const bool canAct = recognized && state_.connected && !running && destReady;
|
||||||
|
// Center the action + Close buttons in the (wider) dialog.
|
||||||
|
const float footTotal = btnW * 2.0f + ImGui::GetStyle().ItemSpacing.x;
|
||||||
|
const float footOff = (ImGui::GetContentRegionAvail().x - footTotal) * 0.5f;
|
||||||
|
if (footOff > 0.0f) ImGui::SetCursorPosX(ImGui::GetCursorPosX() + footOff);
|
||||||
ImGui::BeginDisabled(!canAct);
|
ImGui::BeginDisabled(!canAct);
|
||||||
if (m::TactileButton(sweepMode ? TR("sweep_button") : TR("import_key_import"), ImVec2(btnW, 0))) {
|
if (m::TactileButton(sweepMode ? TR("sweep_button") : TR("import_key_import"), ImVec2(btnW, 0))) {
|
||||||
int startHeight = 0; // 0 = full rescan. Shielded imports (z_importkey) honor it; transparent
|
int startHeight = 0; // 0 = full rescan. Shielded imports (z_importkey) honor it; transparent
|
||||||
|
|||||||
@@ -1666,10 +1666,16 @@ inline void BeginOverlayDialogFooter(float totalActionWidth, bool drawSeparator
|
|||||||
// TextColored(label). The label text is passed in (already translated).
|
// TextColored(label). The label text is passed in (already translated).
|
||||||
inline void DialogWarningHeader(const char* warningLabel, const ImVec4& col = WarningVec4())
|
inline void DialogWarningHeader(const char* warningLabel, const ImVec4& col = WarningVec4())
|
||||||
{
|
{
|
||||||
ImGui::PushFont(Type().iconLarge());
|
ImFont* iconF = Type().iconLarge();
|
||||||
|
const float rowTop = ImGui::GetCursorPosY();
|
||||||
|
const float iconH = iconF->LegacySize; // already dp-scaled
|
||||||
|
const float textH = ImGui::GetFontSize();
|
||||||
|
ImGui::PushFont(iconF);
|
||||||
ImGui::TextColored(col, ICON_MD_WARNING);
|
ImGui::TextColored(col, ICON_MD_WARNING);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
// Vertically center the label with the taller warning glyph (stays within the icon's row height).
|
||||||
|
if (iconH > textH) ImGui::SetCursorPosY(rowTop + (iconH - textH) * 0.5f);
|
||||||
ImGui::TextColored(col, "%s", warningLabel);
|
ImGui::TextColored(col, "%s", warningLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user