ui: reorganize settings page with collapsible sections
- Rename APPEARANCE section to THEME & LANGUAGE - Move font scale slider out of effects into main section - Collapse visual effects into "Advanced Effects..." toggle - Collapse wallet tools into "Tools & Actions..." toggle - Remove redundant Tools & Actions divider/section from wallet card - Add i18n strings: theme_language, advanced_effects, tools_actions
This commit is contained in:
@@ -122,6 +122,8 @@ static bool sp_verbose_logging = false;
|
||||
static std::set<std::string> sp_debug_categories;
|
||||
static bool sp_debug_cats_dirty = false; // true when changed but daemon not yet restarted
|
||||
static bool sp_debug_expanded = false; // collapsible card state
|
||||
static bool sp_effects_expanded = false; // "Advanced Effects..." toggle
|
||||
static bool sp_tools_expanded = false; // "Tools & Actions..." toggle
|
||||
static bool sp_confirm_clear_ztx = false; // confirmation dialog for clearing z-tx history
|
||||
|
||||
// (APPEARANCE card now uses ChannelsSplit like all other cards)
|
||||
@@ -377,11 +379,11 @@ void RenderSettingsPage(App* app) {
|
||||
ImFont* sub1 = Type().subtitle1();
|
||||
|
||||
// ====================================================================
|
||||
// APPEARANCE — card (draw-first approach; avoids ChannelsSplit which
|
||||
// breaks BeginCombo popup rendering in some ImGui versions)
|
||||
// THEME & LANGUAGE — card (draw-first approach; avoids ChannelsSplit
|
||||
// which breaks BeginCombo popup rendering in some ImGui versions)
|
||||
// ====================================================================
|
||||
{
|
||||
Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("appearance"));
|
||||
Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("theme_language"));
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
|
||||
|
||||
ImVec2 cardMin = ImGui::GetCursorScreenPos();
|
||||
@@ -561,9 +563,59 @@ void RenderSettingsPage(App* app) {
|
||||
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
// --- Visual Effects (checkboxes on one row, Quality+Blur paired) ---
|
||||
// --- Font Scale slider (always visible) ---
|
||||
{
|
||||
ImGui::PushFont(body2);
|
||||
ImGui::TextUnformatted(TR("font_scale"));
|
||||
float fontSliderW = std::max(S.drawElement("components.settings-page", "effects-input-min-width").size, contentW);
|
||||
ImGui::SetNextItemWidth(fontSliderW);
|
||||
sp_font_scale = Layout::userFontScale();
|
||||
float prev_font_scale = sp_font_scale;
|
||||
{
|
||||
char fs_fmt[16];
|
||||
snprintf(fs_fmt, sizeof(fs_fmt), "%.2fx", sp_font_scale);
|
||||
ImGui::SliderFloat("##FontScale", &sp_font_scale, 1.0f, 1.5f, fs_fmt,
|
||||
ImGuiSliderFlags_AlwaysClamp);
|
||||
}
|
||||
sp_font_scale = std::max(1.0f, std::min(1.5f,
|
||||
std::round(sp_font_scale * 20.0f) / 20.0f));
|
||||
if (sp_font_scale != prev_font_scale)
|
||||
Layout::setUserFontScaleVisual(sp_font_scale);
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
Layout::setUserFontScale(sp_font_scale);
|
||||
saveSettingsPageState(app->settings());
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_font_scale"));
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
// --- Collapsible: Advanced Effects... ---
|
||||
{
|
||||
const char* arrow = sp_effects_expanded ? ICON_MD_EXPAND_LESS : ICON_MD_EXPAND_MORE;
|
||||
ImGui::PushFont(body2);
|
||||
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));
|
||||
{
|
||||
ImVec2 hdrPos = ImGui::GetCursorScreenPos();
|
||||
if (ImGui::Button("##EffectsToggle", ImVec2(contentW, ImGui::GetFrameHeight()))) {
|
||||
sp_effects_expanded = !sp_effects_expanded;
|
||||
}
|
||||
float textY = hdrPos.y + (ImGui::GetFrameHeight() - body2->LegacySize) * 0.5f;
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(hdrPos.x, textY), OnSurfaceMedium(), TR("advanced_effects"));
|
||||
ImFont* iconFont = Type().iconSmall();
|
||||
if (!iconFont) iconFont = body2;
|
||||
float arrowW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, arrow).x;
|
||||
dl->AddText(iconFont, iconFont->LegacySize, ImVec2(hdrPos.x + contentW - arrowW, textY), OnSurfaceMedium(), arrow);
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
if (sp_effects_expanded) {
|
||||
ImGui::PushFont(body2);
|
||||
|
||||
// Checkbox row: Low-spec | Console scanline | Theme effects | Gradient background
|
||||
if (ImGui::Checkbox(TrId("low_spec_mode", "low_spec").c_str(), &sp_low_spec_mode)) {
|
||||
@@ -603,7 +655,6 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_low_spec"));
|
||||
|
||||
// Simple background is lightweight — always interactive, even in low-spec mode
|
||||
ImGui::SameLine(0, Layout::spacingLg());
|
||||
if (ImGui::Checkbox(TrId("simple_background", "simple_bg").c_str(), &sp_gradient_background)) {
|
||||
schema::SkinManager::instance().setGradientMode(sp_gradient_background);
|
||||
@@ -635,12 +686,10 @@ void RenderSettingsPage(App* app) {
|
||||
float baseX = ImGui::GetCursorScreenPos().x;
|
||||
float rightX = baseX + ctrlW + Layout::spacingLg();
|
||||
|
||||
// Acrylic label + slider (left column)
|
||||
ImGui::TextUnformatted(TR("acrylic"));
|
||||
float row1Y = ImGui::GetCursorScreenPos().y;
|
||||
ImGui::SetNextItemWidth(ctrlW);
|
||||
{
|
||||
// Build display format: "Off" at zero, percentage otherwise
|
||||
char blur_fmt[16];
|
||||
if (sp_blur_amount < 0.01f)
|
||||
snprintf(blur_fmt, sizeof(blur_fmt), "Off");
|
||||
@@ -648,7 +697,6 @@ void RenderSettingsPage(App* app) {
|
||||
snprintf(blur_fmt, sizeof(blur_fmt), "%.0f%%%%", sp_blur_amount * 25.0f);
|
||||
if (ImGui::SliderFloat("##AcrylicBlur", &sp_blur_amount, 0.0f, 4.0f, blur_fmt,
|
||||
ImGuiSliderFlags_AlwaysClamp)) {
|
||||
// Snap to off when dragged near 0%
|
||||
if (sp_blur_amount > 0.0f && sp_blur_amount < 0.15f) sp_blur_amount = 0.0f;
|
||||
sp_acrylic_enabled = (sp_blur_amount > 0.001f);
|
||||
effects::ImGuiAcrylic::ApplyBlurAmount(sp_blur_amount);
|
||||
@@ -658,7 +706,6 @@ void RenderSettingsPage(App* app) {
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_blur"));
|
||||
float afterRow1Y = ImGui::GetCursorScreenPos().y;
|
||||
|
||||
// Noise label + slider (right column, same row)
|
||||
float lblH = ImGui::GetTextLineHeight() + ImGui::GetStyle().ItemSpacing.y;
|
||||
ImGui::SetCursorScreenPos(ImVec2(rightX, row1Y - lblH));
|
||||
ImGui::TextUnformatted(TR("noise"));
|
||||
@@ -678,10 +725,8 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_noise"));
|
||||
|
||||
// Reset cursor to left column, past row 1
|
||||
ImGui::SetCursorScreenPos(ImVec2(baseX, afterRow1Y));
|
||||
|
||||
// Row 2: UI Opacity + Window Opacity (labels above)
|
||||
ImGui::TextUnformatted(TR("ui_opacity"));
|
||||
float row2Y = ImGui::GetCursorScreenPos().y;
|
||||
ImGui::SetNextItemWidth(ctrlW);
|
||||
@@ -697,7 +742,6 @@ void RenderSettingsPage(App* app) {
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_ui_opacity"));
|
||||
float afterRow2Y = ImGui::GetCursorScreenPos().y;
|
||||
|
||||
// Window label + slider (right column, same row)
|
||||
ImGui::SetCursorScreenPos(ImVec2(rightX, row2Y - lblH));
|
||||
ImGui::TextUnformatted(TR("window_opacity"));
|
||||
ImGui::SetCursorScreenPos(ImVec2(rightX, row2Y));
|
||||
@@ -712,12 +756,11 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_window_opacity"));
|
||||
|
||||
// Reset cursor to left column, past row 2
|
||||
ImGui::SetCursorScreenPos(ImVec2(baseX, afterRow2Y));
|
||||
|
||||
ImGui::EndDisabled(); // low-spec
|
||||
ImGui::PopFont();
|
||||
}
|
||||
} // sp_effects_expanded
|
||||
} else {
|
||||
// ============================================================
|
||||
// Narrow: stacked combos + 2-column effects (original layout)
|
||||
@@ -810,11 +853,62 @@ void RenderSettingsPage(App* app) {
|
||||
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
// --- Visual Effects (checkboxes + controls) ---
|
||||
// --- Font Scale slider (always visible) ---
|
||||
{
|
||||
ImGui::PushFont(body2);
|
||||
ImGui::TextUnformatted(TR("font_scale"));
|
||||
float fontSliderW = std::max(S.drawElement("components.settings-page", "effects-input-min-width").size,
|
||||
availWidth - pad * 2);
|
||||
ImGui::SetNextItemWidth(fontSliderW);
|
||||
sp_font_scale = Layout::userFontScale();
|
||||
float prev_font_scale = sp_font_scale;
|
||||
{
|
||||
char fs_fmt[16];
|
||||
snprintf(fs_fmt, sizeof(fs_fmt), "%.2fx", sp_font_scale);
|
||||
ImGui::SliderFloat("##FontScale", &sp_font_scale, 1.0f, 1.5f, fs_fmt,
|
||||
ImGuiSliderFlags_AlwaysClamp);
|
||||
}
|
||||
sp_font_scale = std::max(1.0f, std::min(1.5f,
|
||||
std::round(sp_font_scale * 20.0f) / 20.0f));
|
||||
if (sp_font_scale != prev_font_scale)
|
||||
Layout::setUserFontScaleVisual(sp_font_scale);
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
Layout::setUserFontScale(sp_font_scale);
|
||||
saveSettingsPageState(app->settings());
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_font_scale"));
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
// --- Collapsible: Advanced Effects... ---
|
||||
{
|
||||
const char* arrow = sp_effects_expanded ? ICON_MD_EXPAND_LESS : ICON_MD_EXPAND_MORE;
|
||||
ImGui::PushFont(body2);
|
||||
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));
|
||||
{
|
||||
float narrowContentW = availWidth - pad * 2;
|
||||
ImVec2 hdrPos = ImGui::GetCursorScreenPos();
|
||||
if (ImGui::Button("##EffectsToggleN", ImVec2(narrowContentW, ImGui::GetFrameHeight()))) {
|
||||
sp_effects_expanded = !sp_effects_expanded;
|
||||
}
|
||||
float textY = hdrPos.y + (ImGui::GetFrameHeight() - body2->LegacySize) * 0.5f;
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(hdrPos.x, textY), OnSurfaceMedium(), TR("advanced_effects"));
|
||||
ImFont* iconFont = Type().iconSmall();
|
||||
if (!iconFont) iconFont = body2;
|
||||
float arrowW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, arrow).x;
|
||||
dl->AddText(iconFont, iconFont->LegacySize, ImVec2(hdrPos.x + narrowContentW - arrowW, textY), OnSurfaceMedium(), arrow);
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
if (sp_effects_expanded) {
|
||||
ImGui::PushFont(body2);
|
||||
|
||||
// Checkbox row 1: Low-spec
|
||||
if (ImGui::Checkbox(TrId("low_spec_mode", "low_spec").c_str(), &sp_low_spec_mode)) {
|
||||
effects::setLowSpecMode(sp_low_spec_mode);
|
||||
if (sp_low_spec_mode) {
|
||||
@@ -852,7 +946,6 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_low_spec"));
|
||||
|
||||
// Simple background is lightweight — always interactive, even in low-spec mode
|
||||
if (ImGui::Checkbox(TrId("settings_gradient_bg", "gradient_bg").c_str(), &sp_gradient_background)) {
|
||||
schema::SkinManager::instance().setGradientMode(sp_gradient_background);
|
||||
saveSettingsPageState(app->settings());
|
||||
@@ -861,7 +954,6 @@ void RenderSettingsPage(App* app) {
|
||||
|
||||
ImGui::BeginDisabled(sp_low_spec_mode);
|
||||
|
||||
// Checkbox row 2: Console scanline | Theme effects
|
||||
if (ImGui::Checkbox(TrId("console_scanline", "scanline").c_str(), &sp_scanline_enabled)) {
|
||||
ConsoleTab::s_scanline_enabled = sp_scanline_enabled;
|
||||
app->settings()->setScanlineEnabled(sp_scanline_enabled);
|
||||
@@ -876,9 +968,8 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_theme_effects"));
|
||||
|
||||
// Acrylic blur slider (label above)
|
||||
float ctrlW = std::max(S.drawElement("components.settings-page", "effects-input-min-width").size,
|
||||
contentW);
|
||||
availWidth - pad * 2.0f);
|
||||
ImGui::TextUnformatted(TR("acrylic"));
|
||||
ImGui::SetNextItemWidth(ctrlW);
|
||||
{
|
||||
@@ -897,7 +988,6 @@ void RenderSettingsPage(App* app) {
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) saveSettingsPageState(app->settings());
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_blur"));
|
||||
|
||||
// Noise opacity slider (label above)
|
||||
ImGui::TextUnformatted(TR("noise"));
|
||||
ImGui::SetNextItemWidth(ctrlW);
|
||||
{
|
||||
@@ -914,7 +1004,6 @@ void RenderSettingsPage(App* app) {
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) saveSettingsPageState(app->settings());
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_noise"));
|
||||
|
||||
// UI Opacity slider (label above)
|
||||
ImGui::TextUnformatted(TR("ui_opacity"));
|
||||
ImGui::SetNextItemWidth(ctrlW);
|
||||
{
|
||||
@@ -928,7 +1017,6 @@ void RenderSettingsPage(App* app) {
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) saveSettingsPageState(app->settings());
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_ui_opacity"));
|
||||
|
||||
// Window Opacity slider (label above)
|
||||
ImGui::TextUnformatted(TR("window_opacity"));
|
||||
ImGui::SetNextItemWidth(ctrlW);
|
||||
{
|
||||
@@ -943,44 +1031,7 @@ void RenderSettingsPage(App* app) {
|
||||
|
||||
ImGui::EndDisabled(); // low-spec
|
||||
ImGui::PopFont();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Font Scale slider (always enabled, not affected by low-spec)
|
||||
// ============================================================
|
||||
{
|
||||
ImGui::PushFont(body2);
|
||||
ImGui::Spacing();
|
||||
ImGui::TextUnformatted(TR("font_scale"));
|
||||
float fontSliderW = std::max(S.drawElement("components.settings-page", "effects-input-min-width").size,
|
||||
availWidth - pad * 2);
|
||||
ImGui::SetNextItemWidth(fontSliderW);
|
||||
// Sync from Layout so Alt+scroll hotkey changes are reflected
|
||||
sp_font_scale = Layout::userFontScale();
|
||||
float prev_font_scale = sp_font_scale;
|
||||
{
|
||||
char fs_fmt[16];
|
||||
snprintf(fs_fmt, sizeof(fs_fmt), "%.2fx", sp_font_scale);
|
||||
ImGui::SliderFloat("##FontScale", &sp_font_scale, 1.0f, 1.5f, fs_fmt,
|
||||
ImGuiSliderFlags_AlwaysClamp);
|
||||
}
|
||||
// Snap to 0.05 increments for consistent stepping.
|
||||
// Visual scaling uses FontScaleMain (no atlas rebuild),
|
||||
// atlas rebuild is deferred to slider release for crisp text.
|
||||
sp_font_scale = std::max(1.0f, std::min(1.5f,
|
||||
std::round(sp_font_scale * 20.0f) / 20.0f));
|
||||
if (sp_font_scale != prev_font_scale) {
|
||||
// While dragging: update layout scale without atlas rebuild
|
||||
Layout::setUserFontScaleVisual(sp_font_scale);
|
||||
}
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
// On release: rebuild font atlas at final size
|
||||
Layout::setUserFontScale(sp_font_scale);
|
||||
saveSettingsPageState(app->settings());
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_font_scale"));
|
||||
ImGui::PopFont();
|
||||
} // sp_effects_expanded
|
||||
}
|
||||
|
||||
// Bottom padding
|
||||
@@ -1000,7 +1051,7 @@ void RenderSettingsPage(App* app) {
|
||||
ImGui::Dummy(ImVec2(0, gap));
|
||||
|
||||
// ====================================================================
|
||||
// WALLET — card (Keys, Backup, Tools, Maintenance, Node/RPC)
|
||||
// WALLET — card (privacy/daemon toggles + collapsible tools)
|
||||
// ====================================================================
|
||||
{
|
||||
Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("wallet"));
|
||||
@@ -1013,56 +1064,6 @@ void RenderSettingsPage(App* app) {
|
||||
ImGui::Indent(pad);
|
||||
|
||||
float contentW = availWidth - pad * 2;
|
||||
float btnSpacing = Layout::spacingMd();
|
||||
float btnPad = S.drawElement("components.settings-page", "wallet-btn-padding").sizeOr(24.0f);
|
||||
|
||||
// Calculate button width that fits available space
|
||||
// 6 buttons total: on wide screens 3+3, on narrow screens 2+2+2
|
||||
int btnsPerRow = (contentW >= 600.0f) ? 3 : 2;
|
||||
float bw = (contentW - btnSpacing * (btnsPerRow - 1)) / btnsPerRow;
|
||||
// Clamp to reasonable size
|
||||
float minBtnW = S.drawElement("components.settings-page", "wallet-btn-min-width").sizeOr(100.0f);
|
||||
bw = std::max(minBtnW, bw);
|
||||
|
||||
// Row 1 — Tools & Actions
|
||||
{
|
||||
if (TactileButton(TR("settings_address_book"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
AddressBookDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_address_book"));
|
||||
ImGui::SameLine(0, btnSpacing);
|
||||
if (TactileButton(TR("settings_validate_address"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ValidateAddressDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_validate"));
|
||||
if (btnsPerRow >= 3) { ImGui::SameLine(0, btnSpacing); } else { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); }
|
||||
if (TactileButton(TR("settings_request_payment"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
RequestPaymentDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_request_payment"));
|
||||
if (btnsPerRow >= 3) { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); } else { ImGui::SameLine(0, btnSpacing); }
|
||||
if (TactileButton(TR("settings_shield_mining"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ShieldDialog::show(ShieldDialog::Mode::ShieldCoinbase);
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_shield_mining"));
|
||||
ImGui::SameLine(0, btnSpacing);
|
||||
if (TactileButton(TR("settings_merge_to_address"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ShieldDialog::show(ShieldDialog::Mode::MergeToAddress);
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_merge"));
|
||||
if (btnsPerRow >= 3) { ImGui::SameLine(0, btnSpacing); } else { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); }
|
||||
if (TactileButton(TR("settings_clear_ztx"), ImVec2(bw, 0), S.resolveFont("button"))) {
|
||||
sp_confirm_clear_ztx = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_clear_ztx"));
|
||||
}
|
||||
|
||||
// Thin divider
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
{
|
||||
float divAlpha = S.drawElement("components.settings-page", "section-divider-alpha").opacity;
|
||||
if (divAlpha <= 0.0f) divAlpha = 0.08f;
|
||||
ImU32 baseDivCol = S.resolveColor("var(--status-divider)", IM_COL32(255, 255, 255, 20));
|
||||
ImU32 divCol = material::ScaleAlpha(baseDivCol, divAlpha / 0.08f);
|
||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
dl->AddLine(ImVec2(p.x, p.y), ImVec2(p.x + contentW, p.y), divCol);
|
||||
}
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
// Privacy, Network & Daemon checkboxes — all on one line, shrink text to fit
|
||||
{
|
||||
@@ -1111,47 +1112,94 @@ void RenderSettingsPage(App* app) {
|
||||
if (scale < 1.0f) ImGui::SetWindowFontScale(1.0f);
|
||||
}
|
||||
|
||||
// Mine when idle — checkbox + delay combo
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
// --- Collapsible: Tools & Actions... ---
|
||||
{
|
||||
if (ImGui::Checkbox(TrId("mine_when_idle", "mine_idle").c_str(), &sp_mine_when_idle)) {
|
||||
saveSettingsPageState(app->settings());
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", TR("tt_mine_idle"));
|
||||
|
||||
if (sp_mine_when_idle) {
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextColored(ImVec4(1, 1, 1, 0.5f), "%s", TR("settings_idle_after"));
|
||||
ImGui::SameLine(0, Layout::spacingSm());
|
||||
|
||||
struct DelayOption { int seconds; const char* label; };
|
||||
static const DelayOption delays[] = {
|
||||
{30, "30s"}, {60, "1m"}, {120, "2m"}, {300, "5m"}, {600, "10m"}
|
||||
};
|
||||
const char* previewLabel = "2m";
|
||||
for (const auto& d : delays) {
|
||||
if (d.seconds == sp_mine_idle_delay) { previewLabel = d.label; break; }
|
||||
const char* arrow = sp_tools_expanded ? ICON_MD_EXPAND_LESS : ICON_MD_EXPAND_MORE;
|
||||
ImGui::PushFont(body2);
|
||||
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));
|
||||
{
|
||||
ImVec2 hdrPos = ImGui::GetCursorScreenPos();
|
||||
if (ImGui::Button("##ToolsToggle", ImVec2(contentW, ImGui::GetFrameHeight()))) {
|
||||
sp_tools_expanded = !sp_tools_expanded;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(schema::UI().drawElement("components.settings-page", "idle-combo-width").sizeOr(64.0f));
|
||||
if (ImGui::BeginCombo("##IdleDelay", previewLabel, ImGuiComboFlags_NoArrowButton)) {
|
||||
for (const auto& d : delays) {
|
||||
bool selected = (d.seconds == sp_mine_idle_delay);
|
||||
if (ImGui::Selectable(d.label, selected)) {
|
||||
sp_mine_idle_delay = d.seconds;
|
||||
saveSettingsPageState(app->settings());
|
||||
}
|
||||
if (selected) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", TR("tt_idle_delay"));
|
||||
float textY = hdrPos.y + (ImGui::GetFrameHeight() - body2->LegacySize) * 0.5f;
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(hdrPos.x, textY), OnSurfaceMedium(), TR("tools_actions"));
|
||||
ImFont* iconFont = Type().iconSmall();
|
||||
if (!iconFont) iconFont = body2;
|
||||
float arrowW = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, arrow).x;
|
||||
dl->AddText(iconFont, iconFont->LegacySize, ImVec2(hdrPos.x + contentW - arrowW, textY), OnSurfaceMedium(), arrow);
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
// Bottom row — Keys & Data left-aligned, Setup Wizard right-aligned
|
||||
if (sp_tools_expanded) {
|
||||
float btnSpacing = Layout::spacingMd();
|
||||
int btnsPerRow = (contentW >= 600.0f) ? 3 : 2;
|
||||
float bw = (contentW - btnSpacing * (btnsPerRow - 1)) / btnsPerRow;
|
||||
float minBtnW = S.drawElement("components.settings-page", "wallet-btn-min-width").sizeOr(100.0f);
|
||||
bw = std::max(minBtnW, bw);
|
||||
|
||||
if (TactileButton(TR("settings_address_book"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
AddressBookDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_address_book"));
|
||||
ImGui::SameLine(0, btnSpacing);
|
||||
if (TactileButton(TR("settings_validate_address"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ValidateAddressDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_validate"));
|
||||
if (btnsPerRow >= 3) { ImGui::SameLine(0, btnSpacing); } else { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); }
|
||||
if (TactileButton(TR("settings_request_payment"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
RequestPaymentDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_request_payment"));
|
||||
if (btnsPerRow >= 3) { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); } else { ImGui::SameLine(0, btnSpacing); }
|
||||
if (TactileButton(TR("settings_shield_mining"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ShieldDialog::show(ShieldDialog::Mode::ShieldCoinbase);
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_shield_mining"));
|
||||
ImGui::SameLine(0, btnSpacing);
|
||||
if (TactileButton(TR("settings_merge_to_address"), ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ShieldDialog::show(ShieldDialog::Mode::MergeToAddress);
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_merge"));
|
||||
if (btnsPerRow >= 3) { ImGui::SameLine(0, btnSpacing); } else { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); }
|
||||
if (TactileButton(TR("settings_clear_ztx"), ImVec2(bw, 0), S.resolveFont("button"))) {
|
||||
sp_confirm_clear_ztx = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", TR("tt_clear_ztx"));
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, bottomPad));
|
||||
ImGui::Unindent(pad);
|
||||
|
||||
ImVec2 cardMax(cardMin.x + availWidth, ImGui::GetCursorScreenPos().y);
|
||||
dl->ChannelsSetCurrent(0);
|
||||
DrawGlassPanel(dl, cardMin, cardMax, glassSpec);
|
||||
dl->ChannelsMerge();
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(cardMin.x, cardMax.y));
|
||||
ImGui::Dummy(ImVec2(availWidth, 0));
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, gap));
|
||||
|
||||
// ====================================================================
|
||||
// BACKUP & DATA — card
|
||||
// ====================================================================
|
||||
{
|
||||
Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("backup_data"));
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
|
||||
|
||||
ImVec2 cardMin = ImGui::GetCursorScreenPos();
|
||||
dl->ChannelsSplit(2);
|
||||
dl->ChannelsSetCurrent(1);
|
||||
ImGui::SetCursorScreenPos(ImVec2(cardMin.x, cardMin.y + pad));
|
||||
ImGui::Indent(pad);
|
||||
|
||||
float contentW = availWidth - pad * 2;
|
||||
float btnPad = S.drawElement("components.settings-page", "wallet-btn-padding").sizeOr(24.0f);
|
||||
|
||||
{
|
||||
const char* r1[] = {TR("settings_import_key"), TR("settings_export_key"), TR("settings_export_all"), TR("settings_backup"), TR("settings_export_csv")};
|
||||
const char* t1[] = {
|
||||
@@ -1165,13 +1213,12 @@ void RenderSettingsPage(App* app) {
|
||||
float sp = Layout::spacingSm();
|
||||
ImFont* btnFont = S.resolveFont("button");
|
||||
|
||||
// Measure natural widths
|
||||
float btnPadX = btnPad * 2;
|
||||
float naturalW = 0;
|
||||
for (int i = 0; i < 5; i++)
|
||||
naturalW += ImGui::CalcTextSize(r1[i]).x + btnPadX;
|
||||
float wizW = ImGui::CalcTextSize(wizLabel).x + btnPadX;
|
||||
float totalW = naturalW + wizW + sp * 6; // 5 gaps between data btns + 1 gap before wizard
|
||||
float totalW = naturalW + wizW + sp * 6;
|
||||
|
||||
float scale = (totalW > contentW) ? contentW / totalW : 1.0f;
|
||||
if (scale < 1.0f) ImGui::SetWindowFontScale(scale);
|
||||
|
||||
@@ -174,6 +174,9 @@ void I18n::loadBuiltinEnglish()
|
||||
|
||||
// Settings sections
|
||||
strings_["appearance"] = "APPEARANCE";
|
||||
strings_["theme_language"] = "THEME & LANGUAGE";
|
||||
strings_["advanced_effects"] = "Advanced Effects...";
|
||||
strings_["tools_actions"] = "Tools & Actions...";
|
||||
strings_["wallet"] = "WALLET";
|
||||
strings_["node_security"] = "NODE & SECURITY";
|
||||
strings_["node"] = "NODE";
|
||||
|
||||
Reference in New Issue
Block a user