feat(ui): width-responsiveness — content max-width cap + per-surface form/input clamps
Wide/ultrawide (1440-3440px) responsiveness was unhealthy: no page/content-level max-width cap existed, and every card/form/table derived width from raw GetContentRegionAvail().x with floor-only clamps, so surfaces stretched edge-to-edge (2000-3000px inputs, ballooning cards, giant grid cells, 2000px+ dead row-voids). Root cause: adopt the (previously dead-code) clamp helpers. - New Layout::kContentMaxWidth() (~1600dp, tunable via ui.toml [layout] content-max-width; <=0 disables). Cap ##ContentArea to it and center the column in wider windows — every tab derives from this child, so one change tames the app at wide widths. No-op below the cap (fills as before), so 1080p/1440p are unaffected. Per-surface upper-clamps (std::min(cap*dp, expr), floors preserved) where a single element is still too wide even within the capped column: - Settings: Theme/Layout/Language combos, the font-scale slider (~3000px -> 360dp), the effect sliders, Explorer URL and RPC credential fields. - Send / Receive: cap the compose / receive cards to a readable form width and center them (Indent(pad+offset) so the auto-layout fields align with the hand-drawn card); the recent-tx lists below keep the full column width. - Chat message bubbles + composer, mining pool URL/payout inputs + stats left/right split, contacts search, and the lite-network add-server row / server cards / status panel (capped + centered). - Wizard: vertically center the cards when they fit (was top-anchored, leaving a void on tall monitors), compensating the content-height measurement so it can't oscillate. The 1600 cap also subsumes the fixed-4-column balance grids (~400px cards) and the right-anchored row dead-gaps (voids shrink from ~2700px to ~800px), so those are left to the cap rather than blind column/row redesigns. Verified at 1024/1280 (and via a temporary 900dp cap to exercise the cap+center path, since the test display clamps to 1280) across full-node + Lite + Windows (ctest green) and an adversarial diff review (clean). The true wide/ultrawide look and the 1600dp cap value still want eyes on a real wide monitor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,9 +93,12 @@ void RenderLiteNetworkTab(App* app)
|
||||
const bool connected = ws.connected;
|
||||
ImDrawList* sdl = ImGui::GetWindowDrawList();
|
||||
const float panelH = 56.0f * dp;
|
||||
const float panelW = ImGui::GetContentRegionAvail().x;
|
||||
const float availPanelW = ImGui::GetContentRegionAvail().x;
|
||||
const float panelW = std::min(1000.0f * dp, availPanelW);
|
||||
const float panelOffsetX = std::max(0.0f, (availPanelW - panelW) * 0.5f);
|
||||
const float pad2 = 12.0f * dp;
|
||||
ImVec2 pMin = ImGui::GetCursorScreenPos();
|
||||
pMin.x += panelOffsetX;
|
||||
ImVec2 pMax(pMin.x + panelW, pMin.y + panelH);
|
||||
GlassPanelSpec sspec; sspec.rounding = 8.0f * dp;
|
||||
DrawGlassPanel(sdl, pMin, pMax, sspec);
|
||||
@@ -150,7 +153,7 @@ void RenderLiteNetworkTab(App* app)
|
||||
Primary(), barH * 0.5f);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(panelW, panelH)); // reserve the panel (proper boundary growth)
|
||||
ImGui::Dummy(ImVec2(availPanelW, panelH)); // reserve the full row (proper boundary growth)
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
@@ -174,8 +177,8 @@ void RenderLiteNetworkTab(App* app)
|
||||
{
|
||||
const float availW = ImGui::GetContentRegionAvail().x;
|
||||
const float addBtnW = 80.0f * dp;
|
||||
const float urlW = (availW - addBtnW - 16.0f * dp) * 0.6f;
|
||||
const float lblW = (availW - addBtnW - 16.0f * dp) * 0.4f;
|
||||
const float urlW = std::min(550.0f * dp, (availW - addBtnW - 16.0f * dp) * 0.6f);
|
||||
const float lblW = std::min(300.0f * dp, (availW - addBtnW - 16.0f * dp) * 0.4f);
|
||||
ImGui::SetNextItemWidth(urlW);
|
||||
ImGui::InputTextWithHint("##LiteAddUrl", TR("lite_net_add_url_hint"), s_addUrl, sizeof(s_addUrl));
|
||||
ImGui::SameLine();
|
||||
@@ -236,8 +239,11 @@ void RenderLiteNetworkTab(App* app)
|
||||
auto it = probe.find(sv.url);
|
||||
if (it != probe.end()) pr = it->second;
|
||||
|
||||
const float cardW = ImGui::GetContentRegionAvail().x;
|
||||
const float availCardW = ImGui::GetContentRegionAvail().x;
|
||||
const float cardW = std::min(1000.0f * dp, availCardW);
|
||||
const float cardOffsetX = std::max(0.0f, (availCardW - cardW) * 0.5f);
|
||||
ImVec2 cardMin = ImGui::GetCursorScreenPos();
|
||||
cardMin.x += cardOffsetX;
|
||||
ImVec2 cardMax(cardMin.x + cardW, cardMin.y + cardH);
|
||||
const float rnd = 8.0f * dp;
|
||||
const float cardBtnW = cardW - hideW;
|
||||
@@ -326,8 +332,10 @@ void RenderLiteNetworkTab(App* app)
|
||||
|
||||
// Advance to the next card via a real item (Dummy) below the card, so the scroll region's
|
||||
// content height actually grows — ImGui won't extend bounds from a bare SetCursorScreenPos.
|
||||
ImGui::SetCursorScreenPos(ImVec2(cardMin.x, cardMax.y));
|
||||
ImGui::Dummy(ImVec2(cardW, gap));
|
||||
// Reset X to the (unshifted) region origin so next card's GetContentRegionAvail() isn't
|
||||
// cumulatively narrowed by this card's centering offset.
|
||||
ImGui::SetCursorScreenPos(ImVec2(cardMin.x - cardOffsetX, cardMax.y));
|
||||
ImGui::Dummy(ImVec2(availCardW, gap));
|
||||
};
|
||||
|
||||
// ── Visible servers ────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user