fix(ui): finish HiDPI pass — cosmetic ×dpiScale, narrow-width reflow, recent-list reserves

The tail of the DPI/font-scale/responsiveness audit — ~26 remaining findings.

Container / recent-list (Theme-1 leftovers):
- Send: drop NoScrollbar|NoScrollWithMouse on ##SendFormScroll so Recent Sends is
  reachable at font_scale 1.5 (parity with receive).
- Receive: cap the QR/form card via std::min(mainCardTargetH, availH - recentReserve)
  so RECENT RECEIVED stays on-screen (identity at 1.0x).
- Wallets dialog: size the capped-mode list to whole rows so it no longer clips a
  partial row / crowds "Create a new wallet".

Narrow-width (1024px) reflow:
- Console toolbar reserves space for ALL trailing controls (both icon toggles + zoom
  buttons) so the +/- zoom no longer runs off-window.
- History sort combo sized to its measured widest localized label ("Newest first").
- Settings Theme/Layout/Language row: scale the wide→stacked breakpoint by dpiScale so
  it drops to full-width stacked combos at 1.5x (Consolidated Card no longer clips).
- Recent-tx type label: derive the address column X from the measured label width so it
  can't collide at narrow widths.
- Mining Recent Pool Payouts: floor the panel height to fit the empty-state caption.

Cosmetic ×dpiScale() on absolute geometry (no-ops at 1.0x): mining SOLO|POOL toggle &
idle combos, market pair-chips, password/PIN strength bars, receive/send currency
toggles, explorer search bar/rows/rounding, About-card logo, chat empty-state wrap,
recent-list address/time offsets, address-toolbar & two-row action buttons, console
line-gap/status-dot/pane rounding.

Verified at font_scale 1.5 and at 1024px across full-node + Lite + Windows (ctest
green) and an adversarial diff review (one over-reserve regression fixed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-18 21:29:10 -05:00
co-authored by Claude Opus 4.8
parent 99d1e73676
commit ce8c7696d4
15 changed files with 118 additions and 54 deletions
+14 -6
View File
@@ -617,7 +617,7 @@ void ConsoleTab::drawToolbarStatus(ConsoleCommandExecutor& exec)
ConsoleStatusLine st = exec.toolbarStatus();
if (!st.text.empty()) {
ImVec2 cp = ImGui::GetCursorScreenPos();
float dotR = schema::UI().drawElement("tabs.console", "status-dot-radius-base").size + schema::UI().drawElement("tabs.console", "status-dot-radius-scale").size * Layout::hScale();
float dotR = (schema::UI().drawElement("tabs.console", "status-dot-radius-base").size + schema::UI().drawElement("tabs.console", "status-dot-radius-scale").size) * Layout::hScale();
float dotY = cp.y + ImGui::GetTextLineHeight() * 0.5f;
float dotX = cp.x + dotR + 2.0f * Layout::dpiScale();
@@ -687,9 +687,14 @@ void ConsoleTab::drawLogFilterToggles(const ConsoleLogFilterCaps& caps)
void ConsoleTab::drawFilterInput()
{
using namespace material;
float zoomBtnSpace = ImGui::GetFrameHeight() * 2.0f + Layout::spacingSm() * 3.0f;
float filterAvail = ImGui::GetContentRegionAvail().x - zoomBtnSpace;
float filterW = std::min(schema::UI().drawElement("tabs.console", "filter-max-width").size, filterAvail * schema::UI().drawElement("tabs.console", "filter-width-ratio").size);
// Reserve room for EVERY trailing same-line control drawn AFTER this filter on the toolbar
// row: the two icon toggles (accent-fill + text-color) and the two zoom buttons, plus the
// group spacers between them. Otherwise the filter eats the row and the trailing controls
// run off-window (worst at 1024px / font_scale 1.5). All four are GetFrameHeight() wide.
float trailingBtnSpace = ImGui::GetFrameHeight() * 4.0f + Layout::spacingSm() * 7.0f;
float filterAvail = ImGui::GetContentRegionAvail().x - trailingBtnSpace;
float filterMaxW = schema::UI().drawElement("tabs.console", "filter-max-width").size * Layout::dpiScale();
float filterW = std::min(filterMaxW, filterAvail * schema::UI().drawElement("tabs.console", "filter-width-ratio").size);
ImGui::SetNextItemWidth(filterW);
ImGui::InputTextWithHint("##ConsoleFilter", TR("console_filter_hint"), filter_text_, sizeof(filter_text_));
if (filter_text_[0] != '\0') {
@@ -768,7 +773,10 @@ void ConsoleTab::renderOutput()
// height. The inter-line gap is added explicitly to layout_.heights
// so that layout_.cumulativeY stays perfectly in sync with actual
// cursor positions (avoiding selection-offset drift).
float interLineGap = S.drawElement("tabs.console", "output").getFloat("line-spacing", 0.0f);
// Raw logical px from the schema; scale it so the inter-line gap grows at font_scale 1.5
// (it is added to the already-DPI-scaled GetTextLineHeight in BuildConsoleLayout — scale the
// gap only, never the line height).
float interLineGap = S.drawElement("tabs.console", "output").getFloat("line-spacing", 0.0f) * Layout::dpiScale();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
// Inner padding for glass panel
@@ -1894,7 +1902,7 @@ void ConsoleTab::renderCommandsPopup(ConsoleCommandExecutor& exec)
// Both panes sit on soft Material glass surfaces (no hard 1px child border) with inner padding.
GlassPanelSpec paneGlass;
paneGlass.rounding = 14.0f;
paneGlass.rounding = 14.0f * dp;
paneGlass.fillAlpha = 30;
paneGlass.borderAlpha = 30;