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:
@@ -627,6 +627,7 @@ void RenderPeersTab(App* app)
|
||||
ImGui::Dummy(ImVec2(0, 20));
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("peers_no_connected"));
|
||||
} else {
|
||||
const float dp = ui::Layout::dpiScale();
|
||||
float rowH = body2->LegacySize + capFont->LegacySize + Layout::spacingLg();
|
||||
float rowInset = Layout::spacingLg();
|
||||
float innerW = ImGui::GetContentRegionAvail().x - rowInset * 2;
|
||||
@@ -643,13 +644,13 @@ void RenderPeersTab(App* app)
|
||||
ImVec2 rowEnd(rowPos.x + innerW, rowPos.y + rowH);
|
||||
|
||||
if (is_selected) {
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 20), S.drawElement("tabs.peers", "row-selection-rounding").size);
|
||||
dl->AddRectFilled(rowPos, ImVec2(rowPos.x + S.drawElement("tabs.peers", "row-accent-width").size, rowEnd.y), Primary(), S.drawElement("tabs.peers", "row-accent-rounding").size);
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 20), S.drawElement("tabs.peers", "row-selection-rounding").size * dp);
|
||||
dl->AddRectFilled(rowPos, ImVec2(rowPos.x + S.drawElement("tabs.peers", "row-accent-width").size * dp, rowEnd.y), Primary(), S.drawElement("tabs.peers", "row-accent-rounding").size * dp);
|
||||
}
|
||||
|
||||
bool hovered = material::IsRectHovered(rowPos, rowEnd);
|
||||
if (hovered && !is_selected) {
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 15), S.drawElement("tabs.peers", "row-selection-rounding").size);
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 15), S.drawElement("tabs.peers", "row-selection-rounding").size * dp);
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
}
|
||||
|
||||
@@ -662,9 +663,9 @@ void RenderPeersTab(App* app)
|
||||
else if (ping_ms < 500) dotCol = Warning();
|
||||
else dotCol = Error();
|
||||
float pingDotR = S.drawElement("tabs.peers", "ping-dot-radius-base").size + S.drawElement("tabs.peers", "ping-dot-radius-scale").size * hs;
|
||||
dl->AddCircleFilled(ImVec2(cx + S.drawElement("tabs.peers", "ping-dot-x-offset").size, cy + body2->LegacySize * 0.5f), pingDotR, dotCol);
|
||||
dl->AddCircleFilled(ImVec2(cx + S.drawElement("tabs.peers", "ping-dot-x-offset").size * dp, cy + body2->LegacySize * 0.5f), pingDotR, dotCol);
|
||||
|
||||
float addrX = cx + S.drawElement("tabs.peers", "address-x-offset").size;
|
||||
float addrX = cx + S.drawElement("tabs.peers", "address-x-offset").size * dp;
|
||||
// Reserve the line-1 trailing zone (ping + direction pill live on the far right,
|
||||
// the nearest being the ping at innerW - pingW - spacingXl*3). A long IPv6+port
|
||||
// addr must clip before it so it can't run under those. Mirror the ping formula
|
||||
@@ -693,9 +694,9 @@ void RenderPeersTab(App* app)
|
||||
ImU32 dirFg = peer.inbound ? WithAlpha(Success(), 200) : WithAlpha(Secondary(), 200);
|
||||
ImVec2 dirSz = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, dirLabel);
|
||||
float dirX = rowPos.x + innerW - dirSz.x - Layout::spacingXl();
|
||||
ImVec2 pillMin(dirX - S.drawElement("tabs.peers", "dir-pill-padding").size, cy + S.drawElement("tabs.peers", "dir-pill-y-offset").size);
|
||||
ImVec2 pillMax(dirX + dirSz.x + S.drawElement("tabs.peers", "dir-pill-padding").size, cy + capFont->LegacySize + S.drawElement("tabs.peers", "dir-pill-y-bottom").size);
|
||||
dl->AddRectFilled(pillMin, pillMax, dirBg, S.drawElement("tabs.peers", "dir-pill-rounding").size);
|
||||
ImVec2 pillMin(dirX - S.drawElement("tabs.peers", "dir-pill-padding").size * dp, cy + S.drawElement("tabs.peers", "dir-pill-y-offset").size * dp);
|
||||
ImVec2 pillMax(dirX + dirSz.x + S.drawElement("tabs.peers", "dir-pill-padding").size * dp, cy + capFont->LegacySize + S.drawElement("tabs.peers", "dir-pill-y-bottom").size * dp);
|
||||
dl->AddRectFilled(pillMin, pillMax, dirBg, S.drawElement("tabs.peers", "dir-pill-rounding").size * dp);
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(dirX, cy + 2), dirFg, dirLabel);
|
||||
}
|
||||
|
||||
@@ -708,7 +709,7 @@ void RenderPeersTab(App* app)
|
||||
}
|
||||
|
||||
float cy2 = cy + body2->LegacySize + Layout::spacingXs();
|
||||
float subverX = cx + S.drawElement("tabs.peers", "address-x-offset").size;
|
||||
float subverX = cx + S.drawElement("tabs.peers", "address-x-offset").size * dp;
|
||||
|
||||
// Reserve the line-2 trailing widths up front so an untrusted, arbitrarily long
|
||||
// remote subver cannot push the TLS badge / ban-score off the row. Order right→left:
|
||||
@@ -747,7 +748,7 @@ void RenderPeersTab(App* app)
|
||||
ImU32 tlsFg = WithAlpha(Success(), 200);
|
||||
ImVec2 tlsMin(badgeX, cy2);
|
||||
ImVec2 tlsMax(tlsMin.x + tlsBadgeW, tlsMin.y + capFont->LegacySize + 2);
|
||||
dl->AddRectFilled(tlsMin, tlsMax, tlsBg, S.drawElement("tabs.peers", "tls-badge-rounding").size);
|
||||
dl->AddRectFilled(tlsMin, tlsMax, tlsBg, S.drawElement("tabs.peers", "tls-badge-rounding").size * dp);
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(tlsMin.x + 4, cy2 + 1), tlsFg, "TLS");
|
||||
} else {
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(badgeX, cy2),
|
||||
@@ -815,7 +816,7 @@ void RenderPeersTab(App* app)
|
||||
|
||||
if (i < state.peers.size() - 1) {
|
||||
ImVec2 divStart = ImGui::GetCursorScreenPos();
|
||||
dl->AddLine(ImVec2(divStart.x + pad + 18, divStart.y),
|
||||
dl->AddLine(ImVec2(divStart.x + pad + 18 * dp, divStart.y),
|
||||
ImVec2(divStart.x + innerW - pad, divStart.y),
|
||||
IM_COL32(255, 255, 255, 15));
|
||||
}
|
||||
@@ -832,7 +833,8 @@ void RenderPeersTab(App* app)
|
||||
ImGui::Dummy(ImVec2(0, 20));
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("peers_no_banned"));
|
||||
} else {
|
||||
float rowH = capFont->LegacySize + S.drawElement("tabs.peers", "banned-row-height-padding").size;
|
||||
const float dp = ui::Layout::dpiScale();
|
||||
float rowH = capFont->LegacySize + S.drawElement("tabs.peers", "banned-row-height-padding").size * dp;
|
||||
float rowInsetB = pad;
|
||||
float innerW = ImGui::GetContentRegionAvail().x - rowInsetB * 2;
|
||||
listScrollY = ImGui::GetScrollY();
|
||||
@@ -848,21 +850,21 @@ void RenderPeersTab(App* app)
|
||||
ImVec2 rowEnd(rowPos.x + innerW, rowPos.y + rowH);
|
||||
|
||||
if (is_selected) {
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 20), S.drawElement("tabs.peers", "banned-row-rounding").size);
|
||||
dl->AddRectFilled(rowPos, ImVec2(rowPos.x + S.drawElement("tabs.peers", "row-accent-width").size, rowEnd.y), WithAlpha(Error(), 200), S.drawElement("tabs.peers", "banned-accent-rounding").size);
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 20), S.drawElement("tabs.peers", "banned-row-rounding").size * dp);
|
||||
dl->AddRectFilled(rowPos, ImVec2(rowPos.x + S.drawElement("tabs.peers", "row-accent-width").size * dp, rowEnd.y), WithAlpha(Error(), 200), S.drawElement("tabs.peers", "banned-accent-rounding").size * dp);
|
||||
}
|
||||
|
||||
if (material::IsRectHovered(rowPos, rowEnd) && !is_selected) {
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 15), S.drawElement("tabs.peers", "banned-row-rounding").size);
|
||||
dl->AddRectFilled(rowPos, rowEnd, IM_COL32(255, 255, 255, 15), S.drawElement("tabs.peers", "banned-row-rounding").size * dp);
|
||||
}
|
||||
|
||||
float cx = rowPos.x + pad;
|
||||
float cy = rowPos.y + Layout::spacingXs();
|
||||
|
||||
float banDotR = S.drawElement("tabs.peers", "ban-dot-radius-base").size + S.drawElement("tabs.peers", "ban-dot-radius-scale").size * hs;
|
||||
dl->AddCircleFilled(ImVec2(cx + S.drawElement("tabs.peers", "ban-dot-x-offset").size, cy + capFont->LegacySize * 0.4f), banDotR, WithAlpha(Error(), 200));
|
||||
dl->AddCircleFilled(ImVec2(cx + S.drawElement("tabs.peers", "ban-dot-x-offset").size * dp, cy + capFont->LegacySize * 0.4f), banDotR, WithAlpha(Error(), 200));
|
||||
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx + S.drawElement("tabs.peers", "banned-address-x-offset").size, cy),
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx + S.drawElement("tabs.peers", "banned-address-x-offset").size * dp, cy),
|
||||
OnSurfaceDisabled(), banned.address.c_str());
|
||||
|
||||
std::string banUntil = banned.getBannedUntilString();
|
||||
@@ -878,7 +880,7 @@ void RenderPeersTab(App* app)
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(rowPos);
|
||||
ImGui::InvisibleButton("##bannedRow", ImVec2(innerW - S.drawElement("tabs.peers", "banned-row-btn-reserve").size, rowH));
|
||||
ImGui::InvisibleButton("##bannedRow", ImVec2(innerW - S.drawElement("tabs.peers", "banned-row-btn-reserve").size * dp, rowH));
|
||||
if (ImGui::IsItemClicked(0)) {
|
||||
s_selected_banned_idx = static_cast<int>(i);
|
||||
}
|
||||
@@ -898,7 +900,7 @@ void RenderPeersTab(App* app)
|
||||
|
||||
if (i < state.bannedPeers.size() - 1) {
|
||||
ImVec2 divStart = ImGui::GetCursorScreenPos();
|
||||
dl->AddLine(ImVec2(divStart.x + pad + 8, divStart.y),
|
||||
dl->AddLine(ImVec2(divStart.x + pad + 8 * dp, divStart.y),
|
||||
ImVec2(divStart.x + innerW - pad, divStart.y),
|
||||
IM_COL32(255, 255, 255, 15));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user