From a1e4acfe861d63e9b6354117170dd0341e1d6339 Mon Sep 17 00:00:00 2001 From: DanS Date: Wed, 1 Jul 2026 23:48:45 -0500 Subject: [PATCH] =?UTF-8?q?feat(settings):=20fix=20Node=20&=20Security=20e?= =?UTF-8?q?mpty=20space=20=E2=80=94=2070/30=20split=20+=20Advanced=20in=20?= =?UTF-8?q?right=20column?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fixed 60/40 split left a large empty gap in the bottom-right: the SECURITY column is short while NODE (data dir + RPC grid) is tall, and the DAEMON BINARY row spans full width below both. Two changes: - Widen the side-by-side split to 70/30 so NODE (the content-heavy column, esp. the RPC grid) gets the room and the right-side gap shrinks. - Move the "Advanced" destructive-actions expander out of the full-width DAEMON BINARY row and into the right column below Security, filling the gap. Its four actions now stack vertically to fit the narrow column. Full-node + lite build clean; source hygiene clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/ui/pages/settings_page.cpp | 115 +++++++++++++++++---------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/src/ui/pages/settings_page.cpp b/src/ui/pages/settings_page.cpp index 41987b3..5f42efe 100644 --- a/src/ui/pages/settings_page.cpp +++ b/src/ui/pages/settings_page.cpp @@ -1515,8 +1515,10 @@ void RenderSettingsPage(App* app) { // grid especially), so stack them into one full-width column instead. float stackWidth = S.drawElement("components.settings-page", "node-sec-stack-width").sizeOr(600.0f); bool stacked = contentW < stackWidth; - float leftColW = stacked ? contentW : (contentW - colGap) * 0.6f; - float rightColW = stacked ? contentW : (contentW - colGap) * 0.4f; + // 70/30 when side by side: NODE holds far more (data dir + RPC grid) than the + // short SECURITY column, so give it the width and shrink the right-side gap. + float leftColW = stacked ? contentW : (contentW - colGap) * 0.7f; + float rightColW = stacked ? contentW : (contentW - colGap) * 0.3f; ImVec2 sectionOrigin = ImGui::GetCursorScreenPos(); float leftX = sectionOrigin.x; float rightX = stacked ? sectionOrigin.x : (sectionOrigin.x + leftColW + colGap); @@ -2146,6 +2148,59 @@ void RenderSettingsPage(App* app) { } } + // Advanced — rare/destructive daemon actions (full-node only), placed in the + // right column below Security so that space isn't left empty. Buttons stack + // vertically to fit the narrow column. + if (app->supportsFullNodeLifecycleActions()) { + ImGui::Dummy(ImVec2(0, Layout::spacingSm())); + ImGui::SetCursorScreenPos(ImVec2(rightX, ImGui::GetCursorScreenPos().y)); + ImVec2 advPos = ImGui::GetCursorScreenPos(); + const char* advArrow = s_settingsState.node_advanced_expanded ? ICON_MD_EXPAND_LESS : ICON_MD_EXPAND_MORE; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1,1,1,0.05f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1,1,1,0.08f)); + if (ImGui::Button("##NodeAdvancedToggle", ImVec2(rightColW, ImGui::GetFrameHeight()))) + s_settingsState.node_advanced_expanded = !s_settingsState.node_advanced_expanded; + ImGui::PopStyleColor(3); + ImFont* ovA = Type().overline(); + float advTextY = advPos.y + (ImGui::GetFrameHeight() - ovA->LegacySize) * 0.5f; + dl->AddText(ovA, ovA->LegacySize, ImVec2(advPos.x, advTextY), OnSurfaceMedium(), TR("advanced")); + ImFont* icoA = Type().iconSmall(); if (!icoA) icoA = ovA; + float arrowW = icoA->CalcTextSizeA(icoA->LegacySize, FLT_MAX, 0, advArrow).x; + dl->AddText(icoA, icoA->LegacySize, ImVec2(advPos.x + rightColW - arrowW, advTextY), OnSurfaceMedium(), advArrow); + + if (s_settingsState.node_advanced_expanded) { + ImFont* advBtnFont = S.resolveFont("button"); + auto advRow = [&]() { ImGui::SetCursorScreenPos(ImVec2(rightX, ImGui::GetCursorScreenPos().y)); }; + ImGui::Dummy(ImVec2(0, Layout::spacingXs())); + advRow(); + ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon() || !s_settingsState.bundled_daemon.available); + if (TactileButton(TR("daemon_install_bundled"), ImVec2(rightColW, 0), advBtnFont)) + s_settingsState.confirm_reinstall_daemon = true; + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_daemon_install_bundled")); + ImGui::EndDisabled(); + advRow(); + ImGui::BeginDisabled(!app->isConnected()); + if (TactileButton(TR("rescan"), ImVec2(rightColW, 0), advBtnFont)) { + s_settingsState.confirm_rescan = true; + s_settingsState.rescan_height_detecting = false; + s_settingsState.rescan_height_detected = false; + } + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_rescan")); + ImGui::EndDisabled(); + advRow(); + ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon()); + if (TactileButton(TR("delete_blockchain"), ImVec2(rightColW, 0), advBtnFont)) + s_settingsState.confirm_delete_blockchain = true; + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_delete_blockchain")); + ImGui::EndDisabled(); + advRow(); + if (TactileButton(TR("repair_wallet"), ImVec2(rightColW, 0), advBtnFont)) + s_settingsState.confirm_repair_wallet = true; + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_repair_wallet")); + } + } + float rightBottom = ImGui::GetCursorScreenPos().y; ImGui::PopClipRect(); @@ -2262,60 +2317,8 @@ void RenderSettingsPage(App* app) { } if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_test_conn")); ImGui::EndDisabled(); - - // Advanced — rare + destructive daemon actions behind a collapsible header - // (reuses the DEBUG LOGGING expander idiom). - ImGui::Dummy(ImVec2(0, Layout::spacingSm())); - { - ImVec2 advPos = ImGui::GetCursorScreenPos(); - const char* advArrow = s_settingsState.node_advanced_expanded ? ICON_MD_EXPAND_LESS : ICON_MD_EXPAND_MORE; - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1,1,1,0.05f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1,1,1,0.08f)); - if (ImGui::Button("##NodeAdvancedToggle", ImVec2(contentW, ImGui::GetFrameHeight()))) { - s_settingsState.node_advanced_expanded = !s_settingsState.node_advanced_expanded; - } - ImGui::PopStyleColor(3); - ImFont* ovFont = Type().overline(); - float textY = advPos.y + (ImGui::GetFrameHeight() - ovFont->LegacySize) * 0.5f; - dl->AddText(ovFont, ovFont->LegacySize, ImVec2(advPos.x, textY), OnSurfaceMedium(), TR("advanced")); - ImFont* iconFont = Type().iconSmall(); - if (!iconFont) iconFont = ovFont; - float arrowW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, advArrow).x; - dl->AddText(iconFont, iconFont->LegacySize, ImVec2(advPos.x + contentW - arrowW, textY), OnSurfaceMedium(), advArrow); - } - if (s_settingsState.node_advanced_expanded) { - ImGui::Dummy(ImVec2(0, Layout::spacingXs())); - ImGui::SetCursorScreenPos(ImVec2(dbLeftX, ImGui::GetCursorScreenPos().y)); - ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon() || !bun.available); - if (TactileButton(TR("daemon_install_bundled"), ImVec2(0, 0), dbBtnFont)) { - s_settingsState.confirm_reinstall_daemon = true; - } - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_daemon_install_bundled")); - ImGui::EndDisabled(); - ImGui::SameLine(0, Layout::spacingMd()); - ImGui::BeginDisabled(!app->isConnected()); - if (TactileButton(TR("rescan"), ImVec2(0, 0), dbBtnFont)) { - s_settingsState.confirm_rescan = true; - // Re-probe the available block range each time the dialog is opened. - s_settingsState.rescan_height_detecting = false; - s_settingsState.rescan_height_detected = false; - } - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_rescan")); - ImGui::EndDisabled(); - ImGui::SameLine(0, Layout::spacingMd()); - ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon()); - if (TactileButton(TR("delete_blockchain"), ImVec2(0, 0), dbBtnFont)) { - s_settingsState.confirm_delete_blockchain = true; - } - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_delete_blockchain")); - ImGui::SameLine(0, Layout::spacingMd()); - if (TactileButton(TR("repair_wallet"), ImVec2(0, 0), dbBtnFont)) { - s_settingsState.confirm_repair_wallet = true; - } - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) material::Tooltip("%s", TR("tt_repair_wallet")); - ImGui::EndDisabled(); - } + // (The "Advanced" destructive-actions expander now lives in the Security + // column above, filling what used to be empty space.) } }