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:
+27
-18
@@ -539,6 +539,8 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
}
|
||||
if (s_tx_status.empty() && !s_sending) return;
|
||||
|
||||
const float dp = Layout::dpiScale();
|
||||
|
||||
// Drive error styling from the authoritative result flag, not English substrings in a
|
||||
// (translatable) status string — otherwise a failed send renders as a green success
|
||||
// under a non-English locale.
|
||||
@@ -547,8 +549,8 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
// ---- ERROR: absolute-positioned overlay, does not displace layout ----
|
||||
if (is_error) {
|
||||
float pad = Layout::spacingLg();
|
||||
float btnH = std::max(schema::UI().drawElement("tabs.send", "error-btn-min-height").size, schema::UI().drawElement("tabs.send", "error-btn-height").size);
|
||||
float textWrapW = w - pad * 2 - schema::UI().drawElement("tabs.send", "error-icon-inset").size; // icon space
|
||||
float btnH = std::max(schema::UI().drawElement("tabs.send", "error-btn-min-height").size, schema::UI().drawElement("tabs.send", "error-btn-height").size) * dp;
|
||||
float textWrapW = w - pad * 2 - schema::UI().drawElement("tabs.send", "error-icon-inset").size * dp; // icon space
|
||||
ImVec2 textSz = body2->CalcTextSizeA(body2->LegacySize, FLT_MAX, textWrapW, s_tx_status.c_str());
|
||||
float contentH = textSz.y + Layout::spacingMd() + btnH + pad * 2;
|
||||
|
||||
@@ -572,7 +574,7 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
DrawGlassPanel(fgDl, pMin, pMax, errGlass);
|
||||
|
||||
// Red accent bar on left
|
||||
fgDl->AddRectFilled(pMin, ImVec2(pMin.x + schema::UI().drawElement("tabs.send", "error-accent-bar-width").size, pMax.y), Error(), errGlass.rounding);
|
||||
fgDl->AddRectFilled(pMin, ImVec2(pMin.x + schema::UI().drawElement("tabs.send", "error-accent-bar-width").size * dp, pMax.y), Error(), errGlass.rounding);
|
||||
|
||||
float ix = pMin.x + pad;
|
||||
float iy = pMin.y + pad;
|
||||
@@ -583,18 +585,18 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
const char* errIcon = ICON_MD_ERROR;
|
||||
ImVec2 iSz = iconFont->CalcTextSizeA(iconFont->LegacySize, 1000.0f, 0.0f, errIcon);
|
||||
fgDl->AddText(iconFont, iconFont->LegacySize,
|
||||
ImVec2(ix + schema::UI().drawElement("tabs.send", "error-icon-x-offset").size, iy + body2->LegacySize * 0.5f - iSz.y * 0.5f),
|
||||
ImVec2(ix + schema::UI().drawElement("tabs.send", "error-icon-x-offset").size * dp, iy + body2->LegacySize * 0.5f - iSz.y * 0.5f),
|
||||
Error(), errIcon);
|
||||
}
|
||||
|
||||
// Error text (wrapped)
|
||||
fgDl->AddText(body2, body2->LegacySize, ImVec2(ix + schema::UI().drawElement("tabs.send", "error-text-x-offset").size, iy), Error(),
|
||||
fgDl->AddText(body2, body2->LegacySize, ImVec2(ix + schema::UI().drawElement("tabs.send", "error-text-x-offset").size * dp, iy), Error(),
|
||||
s_tx_status.c_str(), s_tx_status.c_str() + s_tx_status.size(), textWrapW);
|
||||
|
||||
// Buttons row — use invisible window for interactive widgets on top of overlay
|
||||
float btnY = iy + textSz.y + Layout::spacingMd();
|
||||
ImGui::SetNextWindowPos(ImVec2(ix, btnY));
|
||||
ImGui::SetNextWindowSize(ImVec2(w - pad * 2, btnH + schema::UI().drawElement("tabs.send", "error-btn-area-padding").size));
|
||||
ImGui::SetNextWindowSize(ImVec2(w - pad * 2, btnH + schema::UI().drawElement("tabs.send", "error-btn-area-padding").size * dp));
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
@@ -606,7 +608,7 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
ImGuiWindowFlags_NoBringToFrontOnFocus);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::ColorConvertU32ToFloat4(IM_COL32(255, 255, 255, (int)schema::UI().drawElement("tabs.send", "error-btn-bg-alpha").size)));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertU32ToFloat4(IM_COL32(255, 255, 255, (int)schema::UI().drawElement("tabs.send", "error-btn-hover-alpha").size)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, schema::UI().drawElement("tabs.send", "error-btn-rounding").size);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, schema::UI().drawElement("tabs.send", "error-btn-rounding").size * dp);
|
||||
if (TactileSmallButton(TR("send_copy_error"), schema::UI().resolveFont("button"))) {
|
||||
ImGui::SetClipboardText(s_tx_status.c_str());
|
||||
Notifications::instance().info(TR("send_error_copied"));
|
||||
@@ -629,8 +631,8 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
}
|
||||
|
||||
// ---- SENDING / SUCCESS: inline progress card ----
|
||||
float progCardH = schema::UI().drawElement("tabs.send", "progress-card-height").size;
|
||||
float progCardHTxid = schema::UI().drawElement("tabs.send", "progress-card-height-txid").size;
|
||||
float progCardH = schema::UI().drawElement("tabs.send", "progress-card-height").size * dp;
|
||||
float progCardHTxid = schema::UI().drawElement("tabs.send", "progress-card-height-txid").size * dp;
|
||||
float progH = s_result_txid.empty() ? progCardH : progCardHTxid;
|
||||
ImVec2 pMin(x, y);
|
||||
ImVec2 pMax(x + w, y + progH);
|
||||
@@ -639,8 +641,8 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
progGlass.rounding = Layout::glassRounding() * schema::UI().drawElement("tabs.send", "progress-glass-rounding-ratio").size;
|
||||
DrawGlassPanel(dl, pMin, pMax, progGlass);
|
||||
|
||||
float progPadX = schema::UI().drawElement("tabs.send", "progress-card-pad-x").size;
|
||||
float progPadY = schema::UI().drawElement("tabs.send", "progress-card-pad-y").size;
|
||||
float progPadX = schema::UI().drawElement("tabs.send", "progress-card-pad-x").size * dp;
|
||||
float progPadY = schema::UI().drawElement("tabs.send", "progress-card-pad-y").size * dp;
|
||||
float ix = pMin.x + progPadX;
|
||||
float iy = pMin.y + progPadY;
|
||||
char buf[128];
|
||||
@@ -654,7 +656,7 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
ImVec2(ix, iy), Primary(), spinIcon);
|
||||
double elapsed = ImGui::GetTime() - s_send_start_time;
|
||||
snprintf(buf, sizeof(buf), TR("send_submitting"), elapsed);
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(ix + iSz.x + schema::UI().drawElement("tabs.send", "progress-icon-text-gap").size, iy), OnSurface(), buf);
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(ix + iSz.x + schema::UI().drawElement("tabs.send", "progress-icon-text-gap").size * dp, iy), OnSurface(), buf);
|
||||
} else {
|
||||
// Success checkmark
|
||||
ImFont* iconFont = material::Type().iconMed();
|
||||
@@ -662,19 +664,19 @@ static void RenderTxProgress(ImDrawList* dl, float x, float y, float w,
|
||||
ImVec2 iSz = iconFont->CalcTextSizeA(iconFont->LegacySize, 1000.0f, 0.0f, checkIcon);
|
||||
dl->AddText(iconFont, iconFont->LegacySize,
|
||||
ImVec2(ix, iy), Success(), checkIcon);
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(ix + iSz.x + schema::UI().drawElement("tabs.send", "progress-icon-text-gap").size, iy), Success(), TR("send_tx_sent"));
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(ix + iSz.x + schema::UI().drawElement("tabs.send", "progress-icon-text-gap").size * dp, iy), Success(), TR("send_tx_sent"));
|
||||
|
||||
if (!s_result_txid.empty()) {
|
||||
float txY = iy + body2->LegacySize + schema::UI().drawElement("tabs.send", "txid-y-offset").size;
|
||||
float txY = iy + body2->LegacySize + schema::UI().drawElement("tabs.send", "txid-y-offset").size * dp;
|
||||
int txidThreshold = (int)schema::UI().drawElement("tabs.send", "txid-display-threshold").size;
|
||||
int txidTruncLen = (int)schema::UI().drawElement("tabs.send", "txid-trunc-len").size;
|
||||
std::string dispTxid = (int)s_result_txid.length() > txidThreshold
|
||||
? s_result_txid.substr(0, txidTruncLen) + "..." + s_result_txid.substr(s_result_txid.length() - txidTruncLen)
|
||||
: s_result_txid;
|
||||
snprintf(buf, sizeof(buf), TR("send_txid_label"), dispTxid.c_str());
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(ix + schema::UI().drawElement("tabs.send", "txid-label-x-offset").size, txY),
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(ix + schema::UI().drawElement("tabs.send", "txid-label-x-offset").size * dp, txY),
|
||||
OnSurfaceDisabled(), buf);
|
||||
ImGui::SetCursorScreenPos(ImVec2(pMax.x - schema::UI().drawElement("tabs.send", "txid-copy-btn-right-offset").size, txY - schema::UI().drawElement("tabs.send", "txid-copy-btn-y-offset").size));
|
||||
ImGui::SetCursorScreenPos(ImVec2(pMax.x - schema::UI().drawElement("tabs.send", "txid-copy-btn-right-offset").size * dp, txY - schema::UI().drawElement("tabs.send", "txid-copy-btn-y-offset").size * dp));
|
||||
if (TactileSmallButton(TR("copy"), schema::UI().resolveFont("button"))) {
|
||||
ImGui::SetClipboardText(s_result_txid.c_str());
|
||||
Notifications::instance().info(TR("send_txid_copied"));
|
||||
@@ -726,6 +728,7 @@ void RenderSendConfirmPopup(App* app) {
|
||||
float popupAvailW = ImGui::GetMainViewport()->Size.x * S.drawElement("tabs.send", "confirm-popup-width-ratio").size;
|
||||
float popupW = std::min(schema::UI().drawElement("tabs.send", "confirm-popup-max-width").size, popupAvailW);
|
||||
float popVs = Layout::vScale();
|
||||
const float dp = Layout::dpiScale();
|
||||
material::OverlayDialogSpec ov;
|
||||
ov.title = TR("confirm_send"); ov.p_open = nullptr;
|
||||
ov.style = material::OverlayStyle::BlurFloat;
|
||||
@@ -797,7 +800,12 @@ void RenderSendConfirmPopup(App* app) {
|
||||
|
||||
Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("send_amount_details"));
|
||||
ImVec2 cMin = ImGui::GetCursorScreenPos();
|
||||
// Floor the row step at the *actual* scaled caption-row height (+ a small dp-scaled
|
||||
// gap) so the Fee/Total divider — drawn at rowStep*0.5 below the Fee baseline —
|
||||
// clears the (already-DPI-scaled) fee text instead of striking through it at HiDPI.
|
||||
// capFont->LegacySize is already DPI-scaled; do not scale it again.
|
||||
float rowStep = std::max(schema::UI().drawElement("tabs.send", "confirm-row-step-min").size, schema::UI().drawElement("tabs.send", "confirm-row-step").size * popVs);
|
||||
rowStep = std::max(rowStep, capFont->LegacySize + 6.0f * dp);
|
||||
float configuredH = std::max(schema::UI().drawElement("tabs.send", "confirm-amount-card-min-height").size, schema::UI().drawElement("tabs.send", "confirm-amount-card-height").size * popVs);
|
||||
float contentH = Layout::spacingMd() * 2.0f + capFont->LegacySize * 2.0f + sub1->LegacySize + rowStep * 2.0f;
|
||||
float cH = std::max(configuredH, contentH);
|
||||
@@ -936,9 +944,10 @@ static bool RenderZeroBalanceCTA(App* app, ImDrawList* dl, float width) {
|
||||
|
||||
ImFont* sub1 = Type().subtitle1();
|
||||
ImFont* capFont = Type().caption();
|
||||
const float dp = Layout::dpiScale();
|
||||
|
||||
ImVec2 ctaMin = ImGui::GetCursorScreenPos();
|
||||
float ctaH = schema::UI().drawElement("tabs.send", "cta-height").size;
|
||||
float ctaH = schema::UI().drawElement("tabs.send", "cta-height").size * dp;
|
||||
ImVec2 ctaMax(ctaMin.x + width, ctaMin.y + ctaH);
|
||||
GlassPanelSpec ctaGlass;
|
||||
ctaGlass.rounding = Layout::glassRounding();
|
||||
@@ -952,7 +961,7 @@ static bool RenderZeroBalanceCTA(App* app, ImDrawList* dl, float width) {
|
||||
TR("send_switch_to_receive"));
|
||||
cy += capFont->LegacySize + Layout::spacingMd();
|
||||
ImGui::SetCursorScreenPos(ImVec2(cx, cy));
|
||||
if (TactileButton(TR("send_go_to_receive"), ImVec2(schema::UI().drawElement("tabs.send", "cta-button-width").size, schema::UI().drawElement("tabs.send", "cta-button-height").size), schema::UI().resolveFont("button"))) {
|
||||
if (TactileButton(TR("send_go_to_receive"), ImVec2(schema::UI().drawElement("tabs.send", "cta-button-width").size * dp, schema::UI().drawElement("tabs.send", "cta-button-height").size * dp), schema::UI().resolveFont("button"))) {
|
||||
app->setCurrentPage(NavPage::Receive);
|
||||
}
|
||||
ImGui::SetCursorScreenPos(ImVec2(ctaMin.x, ctaMax.y + Layout::spacingLg()));
|
||||
|
||||
Reference in New Issue
Block a user