fix(ui): scale unscaled geometry at HiDPI — inputs, send progress cards, chat/pool overlaps, peer rows

At font_scale 1.5 ~13 sites read absolute geometry (schema .size/.width) straight
into ImGui without ×dpiScale(), so they stayed native-size while the font grew and
overlapped/clipped real text or money:

- Shield/Merge fee + UTXO inputs, Request Payment amount, Block Info height input:
  ×dpiScale() so the value no longer clips (e.g. 0.00010000 -> 0.00010).
- Send: the confirm-popup Amount Details divider (floored the row step at the scaled
  caption height so it no longer strikes the Fee row), the tx-progress error and
  sending/success cards, and the zero-balance CTA button — all ×dp.
- Mining pool row: ellipsis-truncate the hostname so it can't collide with the
  right-aligned hashrate.
- Chat conversation list: scale the pane-width clamp AND clip the peer name to the
  column left of the timestamp (measure-then-clip) so name and time never overlap.
- Explorer block-detail label column, Peers row offsets, and DialogConfirmFooter
  button height — ×dp.

transaction_details keeps its negative fill-sentinel widths unscaled (a content
margin, not raw px). Verified at font_scale 1.5 across full-node + Lite + Windows
(ctest green) and an adversarial diff review (three wrong-scale regressions fixed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-18 20:53:29 -05:00
co-authored by Claude Opus 4.8
parent 755cf22ad0
commit 99d1e73676
10 changed files with 84 additions and 55 deletions
+11 -5
View File
@@ -776,7 +776,7 @@ void RenderChatTab(App* app)
}
const ImVec2 avail = ImGui::GetContentRegionAvail();
const float listW = std::clamp(avail.x * 0.32f, 220.0f, 360.0f);
const float listW = std::clamp(avail.x * 0.32f, 220.0f * Layout::dpiScale(), 360.0f * Layout::dpiScale());
// Row geometry is logical px — scale by dpiScale() so rows/padding grow with the (DPI-scaled)
// fonts. Left raw, at higher DPI the row was too short for the enlarged text and the preview's
// right margin (rowW - pad) shrank to ~zero, clipping the last glyph mid-word.
@@ -895,16 +895,22 @@ void RenderChatTab(App* app)
}
const float textX = avC.x + avR + pad;
// Name (top). Hidden conversations (shown via "Show hidden") render dimmed.
dl->AddText(nameFont, nameSz, ImVec2(textX, p.y + pad),
c.hidden ? material::OnSurfaceMedium() : material::OnSurface(), c.peerName.c_str());
// Time (top-right, muted) — compact relative form (Q5).
// Time (top-right, muted) — compact relative form (Q5). Measure/draw it FIRST so the name can be
// clipped to the column left of it — otherwise a long peer name overruns the timestamp (worse at
// HiDPI, where the fixed-length name grows ~1.5x).
const std::string when = relativeTime(c.lastTs);
float nameRight = mx.x - pad;
if (!when.empty()) {
const ImVec2 wsz = metaFont->CalcTextSizeA(metaSz, FLT_MAX, 0.0f, when.c_str());
dl->AddText(metaFont, metaSz, ImVec2(mx.x - pad - wsz.x, p.y + pad + 1.0f),
material::OnSurfaceMedium(), when.c_str());
nameRight = mx.x - pad - wsz.x - pad; // reserve the timestamp column + a gap
}
// Name (top), clipped to the space left of the timestamp. Hidden conversations render dimmed.
dl->PushClipRect(ImVec2(textX, p.y), ImVec2(std::max(textX, nameRight), mx.y), true);
dl->AddText(nameFont, nameSz, ImVec2(textX, p.y + pad),
c.hidden ? material::OnSurfaceMedium() : material::OnSurface(), c.peerName.c_str());
dl->PopClipRect();
// Preview (bottom, clipped to the text column, muted).
const std::string preview = previewOf(c.lastBody);
dl->PushClipRect(ImVec2(textX, p.y), ImVec2(mx.x - pad, mx.y), true);