fix(ui): prevent text/button cutoff and scale hand-drawn geometry at HiDPI

Findings from a UI-cutoff audit — each is a spot where an in-tree helper
(truncateMiddle / TruncateToWidth / measured button width / the *dpiScale/*hs
factors) was bypassed:

- notifications: the toast-pill height/padding/icon-gap were raw logical px while
  the icon/text drawn inside are DPI-baked, so they clipped the pill at HiDPI.
  Scale the geometry by dpiScale (not the already-scaled glyph metrics).
- settings: in the two-column NODE & SECURITY layout the data-directory path could
  overrun into the Daemon-binary column (shared draw list, no clip rect between
  them). Middle-ellipsize it to the column width; the full path stays in the
  tooltip + click-to-open + copy.
- send: the "Confirm & Send" button width came straight from the schema and was
  never measured against the label, clipping the Russian translation on the
  pre-broadcast dialog. Size to max(schema width, measured label + padding).
- balance: the recent-tx address-column offset missed the `* hs` DPI factor its
  sibling (amount-right-margin) uses, overlapping the type label at HiDPI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-10 22:11:07 -05:00
parent 393f3d147e
commit 001e85ac1a
4 changed files with 35 additions and 12 deletions

View File

@@ -822,7 +822,17 @@ void RenderSendConfirmPopup(App* app) {
if (s_sending) {
Type().text(TypeStyle::Body2, TR("sending"));
} else {
if (TactileButton(TR("confirm_and_send"), ImVec2(S.button("tabs.send", "confirm-button").width * Layout::dpiScale(), std::max(schema::UI().drawElement("tabs.send", "confirm-btn-min-height").size, schema::UI().drawElement("tabs.send", "confirm-btn-base-height").size * popVs)), S.resolveFont(S.button("tabs.send", "confirm-button").font))) {
// Size to max(schema width, measured label + padding) so a longer translation (e.g. the
// Russian "Подтвердить и отправить") isn't clipped on this pre-broadcast confirm button.
ImFont* confirmFont = S.resolveFont(S.button("tabs.send", "confirm-button").font);
if (!confirmFont) confirmFont = Type().button();
const float confirmW = std::max(
S.button("tabs.send", "confirm-button").width * Layout::dpiScale(),
confirmFont->CalcTextSizeA(confirmFont->LegacySize, FLT_MAX, 0, TR("confirm_and_send")).x
+ ImGui::GetStyle().FramePadding.x * 2.0f + 16.0f * Layout::dpiScale());
const float confirmH = std::max(schema::UI().drawElement("tabs.send", "confirm-btn-min-height").size,
schema::UI().drawElement("tabs.send", "confirm-btn-base-height").size * popVs);
if (TactileButton(TR("confirm_and_send"), ImVec2(confirmW, confirmH), confirmFont)) {
// Re-validate against LIVE state — the confirm dialog persists across frames, so the
// balance could have dropped or sync (re)started (or the fee bumped total over available)
// since Review. Don't broadcast a now-invalid transaction.