system settings
git clone https://git.lucas.co/cce-system-interface.git
refactor: remove manual spacing, clean up status controls, and strip current layout preview
- Remove manual widget spacing across all page sections, delegating to layout auto-gap spacing.
- Clean up unused Status controls (underline, separators, loading toggles, and reload button).
- Completely strip the "Current Layout" visual preview, preview structs (PreviewWindow, LayoutStatusInfo), socket helpers, and background watcher channels.
- Add Grid Gap slider and link its value changes.
src/main.rs | 17 +-
src/pages/accounts.rs | 33 ---
src/pages/audio.rs | 10 -
src/pages/display.rs | 11 -
src/pages/input.rs | 19 --
src/pages/interface.rs | 726 +++++++----------------------------------------
src/pages/network.rs | 6 -
src/pages/packages.rs | 23 --
src/pages/processes.rs | 2 -
src/pages/storage.rs | 12 -
src/pages/system_info.rs | 38 +--
src/watchers.rs | 31 --
12 files changed, 104 insertions(+), 824 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 0e3f107..34b4c07 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -176,14 +176,12 @@ struct SystemInterface {
rx_fingers: std::sync::mpsc::Receiver<Vec<Finger>>,
rx_processes: std::sync::mpsc::Receiver<pages::processes::ProcessesState>,
rx_system: std::sync::mpsc::Receiver<pages::system_info::SystemState>,
- rx_status: std::sync::mpsc::Receiver<pages::interface::StatusData>,
rx_storage: std::sync::mpsc::Receiver<pages::storage::StorageState>,
rx_notifications: std::sync::mpsc::Receiver<pages::system_info::NotificationsConfig>,
rx_typeface: std::sync::mpsc::Receiver<pages::interface::InterfaceState>,
rx_services: std::sync::mpsc::Receiver<Vec<pages::processes::ServiceInfo>>,
rx_interface: std::sync::mpsc::Receiver<pages::interface::InterfaceState>,
rx_accounts: std::sync::mpsc::Receiver<Vec<pages::accounts::AccountInfo>>,
- rx_layout_status: std::sync::mpsc::Receiver<pages::interface::LayoutStatusInfo>,
tx_backup: std::sync::mpsc::Sender<pages::storage::StorageMessage>,
rx_backup: std::sync::mpsc::Receiver<pages::storage::StorageMessage>,
rx_packages: std::sync::mpsc::Receiver<pages::packages::PackagesState>,
@@ -279,14 +277,12 @@ impl cce_ui::engine::Application for SystemInterface {
rx_fingers: watchers.rx_fingers,
rx_processes: watchers.rx_processes,
rx_system: watchers.rx_system,
- rx_status: watchers.rx_status,
rx_storage: watchers.rx_storage,
rx_notifications: watchers.rx_notifications,
rx_typeface: watchers.rx_typeface,
rx_services: watchers.rx_services,
rx_interface: watchers.rx_interface,
rx_accounts: watchers.rx_accounts,
- rx_layout_status: watchers.rx_layout_status,
tx_backup,
rx_backup,
rx_packages: watchers.rx_packages,
@@ -684,12 +680,6 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
self.needs_rebuild = true;
}
}
- while let Ok(s) = self.rx_status.try_recv() {
- interface::update(&mut self.app.interface, interface::InterfaceMessage::StatusRefreshed(s));
- if self.app.current_page == Page::Interface {
- self.needs_rebuild = true;
- }
- }
while let Ok(s) = self.rx_storage.try_recv() {
storage::update(&mut self.app.storage, storage::StorageMessage::Refreshed(s));
if self.app.current_page == Page::Storage {
@@ -723,12 +713,7 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
self.needs_rebuild = true;
}
}
- while let Ok(s) = self.rx_layout_status.try_recv() {
- interface::update(&mut self.app.interface, pages::interface::InterfaceMessage::LayoutStatusRefreshed(s));
- if self.app.current_page == Page::Interface {
- self.needs_rebuild = true;
- }
- }
+
while let Ok(s) = self.rx_accounts.try_recv() {
accounts::update(&mut self.app.accounts, accounts::AccountsMessage::Refreshed(s));
if self.app.current_page == Page::Accounts {
diff --git a/src/pages/accounts.rs b/src/pages/accounts.rs
index f326341..d3fa5af 100644
--- a/src/pages/accounts.rs
+++ b/src/pages/accounts.rs
@@ -350,22 +350,18 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
let lm = cce_ui::layout::label_margin();
let row_h = cce_ui::layout::spinbox_height();
- let row_gap = lm * 1.0;
let widget_h = cce_ui::layout::spinbox_height();
- let field_gap = lm * 1.5;
let btn_gap = lm * 1.0;
// ── Accounts Section ──
builder.add_section(&mut final_pc, "Accounts", false, |sec_accounts| {
if !state.loaded {
sec_accounts.text("Loading online accounts...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec_accounts.spacing(lm * 1.5);
} else {
let item_w = sec_accounts.cw - 2.0 * (sec_accounts.padding() + 12.0);
if state.accounts.is_empty() {
sec_accounts.text("No accounts configured.", 12.0, 0.0, 12.0, TEXT_DIM);
- sec_accounts.spacing(lm * 1.5);
} else {
for (idx, acc) in state.accounts.iter().enumerate() {
let label = if acc.is_default {
@@ -386,11 +382,9 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[0.90, 0.90, 0.95, 1.0],
AppAction::Accounts(AccountsMessage::SelectAccount(idx)),
);
- sec_accounts.spacing(row_gap);
}
}
- sec_accounts.spacing(lm * 1.2);
let half_btn_w = (item_w - btn_gap) / 2.0;
let add_bg = if state.adding_new { [0.20, 0.40, 0.65, 0.4] } else { [0.13, 0.18, 0.14, 1.0] };
@@ -417,7 +411,6 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::GoogleLoginInit),
);
- sec_accounts.spacing(row_gap);
let oauth_bg = if state.editing_oauth_creds { [0.20, 0.40, 0.65, 0.4] } else { [0.15, 0.15, 0.20, 1.0] };
sec_accounts.button(
@@ -431,7 +424,6 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::EditOAuthCredsStart),
);
- sec_accounts.spacing(row_gap);
if let Some(selected_idx) = state.selected_idx {
if selected_idx < state.accounts.len() && !state.adding_new && !state.editing_oauth_creds {
@@ -448,7 +440,6 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::MakeDefault(selected_idx)),
);
- sec_accounts.spacing(row_gap);
}
sec_accounts.button(
"Delete Account",
@@ -461,7 +452,6 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 0.33, 0.33, 1.0],
AppAction::Accounts(AccountsMessage::DeleteAccount(selected_idx)),
);
- sec_accounts.spacing(row_gap);
}
}
}
@@ -475,30 +465,24 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
if state.loaded {
if state.adding_new {
sec_modify.text("Add New Account", 12.0, 0.0, 14.0, [0.35, 0.65, 0.90, 1.0]);
- sec_modify.spacing(lm * 2.5);
sec_modify.text("Note: Gmail uses Google Login. iCloud requires App PW.", 12.0, 0.0, 11.0, TEXT_DIM);
- sec_modify.spacing(lm * 1.8);
// Email Address textbox
state.email_box.set_row_rect(rx + 12.0, item_w);
sec_modify.widget(&mut state.email_box, 12.0, item_w, widget_h, ctx);
- sec_modify.spacing(field_gap);
// Password textbox
state.password_box.set_row_rect(rx + 12.0, item_w);
sec_modify.widget(&mut state.password_box, 12.0, item_w, widget_h, ctx);
- sec_modify.spacing(field_gap);
// IMAP Server textbox
state.imap_box.set_row_rect(rx + 12.0, item_w);
sec_modify.widget(&mut state.imap_box, 12.0, item_w, widget_h, ctx);
- sec_modify.spacing(field_gap);
// SMTP Server textbox
state.smtp_box.set_row_rect(rx + 12.0, item_w);
sec_modify.widget(&mut state.smtp_box, 12.0, item_w, widget_h, ctx);
- sec_modify.spacing(field_gap);
let helper_w = (item_w - btn_gap) / 2.0;
let btn_y = sec_modify.ay();
@@ -524,7 +508,6 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::ICloudLoginHelp),
);
- sec_modify.spacing(lm * 1.8);
let btn_y2 = sec_modify.ay();
sec_modify.button(
@@ -549,25 +532,19 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::AddAccountCancel),
);
- sec_modify.spacing(lm * 1.5);
} else if state.editing_oauth_creds {
sec_modify.text("Google OAuth Credentials", 12.0, 0.0, 14.0, [0.35, 0.65, 0.90, 1.0]);
- sec_modify.spacing(lm * 2.5);
sec_modify.text("Configures client ID & secret from your Google Cloud Console.", 12.0, 0.0, 11.0, TEXT_DIM);
- sec_modify.spacing(lm * 1.5);
sec_modify.text("Required: Gmail API enabled & redirect URI set to http://127.0.0.1:8080", 12.0, 0.0, 11.0, TEXT_DIM);
- sec_modify.spacing(lm * 1.8);
// Client ID textbox
state.oauth_client_id_box.set_row_rect(rx + 12.0, item_w);
sec_modify.widget(&mut state.oauth_client_id_box, 12.0, item_w, widget_h, ctx);
- sec_modify.spacing(field_gap);
// Client Secret textbox
state.oauth_client_secret_box.set_row_rect(rx + 12.0, item_w);
sec_modify.widget(&mut state.oauth_client_secret_box, 12.0, item_w, widget_h, ctx);
- sec_modify.spacing(field_gap);
let helper_w = (item_w - btn_gap) / 2.0;
let btn_y3 = sec_modify.ay();
@@ -593,26 +570,20 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::EditOAuthCredsCancel),
);
- sec_modify.spacing(lm * 1.5);
} else if let Some(selected_idx) = state.selected_idx {
if selected_idx < state.accounts.len() {
let acc = &state.accounts[selected_idx];
sec_modify.text("Account Details", 12.0, 0.0, 14.0, [0.35, 0.65, 0.90, 1.0]);
- sec_modify.spacing(lm * 2.5);
sec_modify.text(&format!("Email Address: {}", acc.email), 12.0, 0.0, 12.0, [0.90, 0.90, 0.95, 1.0]);
- sec_modify.spacing(lm * 1.8);
let auth_type = if acc.is_oauth { "OAuth2 (Google)" } else { "Password-based" };
sec_modify.text(&format!("Authentication: {}", auth_type), 12.0, 0.0, 12.0, [0.83, 0.83, 0.83, 1.0]);
- sec_modify.spacing(lm * 1.8);
sec_modify.text(&format!("IMAP Server: {}", acc.imap), 12.0, 0.0, 12.0, [0.83, 0.83, 0.83, 1.0]);
- sec_modify.spacing(lm * 1.8);
sec_modify.text(&format!("SMTP Server: {}", acc.smtp), 12.0, 0.0, 12.0, [0.83, 0.83, 0.83, 1.0]);
- sec_modify.spacing(lm * 2.2);
if acc.is_oauth {
sec_modify.button(
@@ -626,18 +597,14 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
[1.0, 1.0, 1.0, 1.0],
AppAction::Accounts(AccountsMessage::GoogleLoginInit),
);
- sec_modify.spacing(lm * 1.5);
}
}
} else {
sec_modify.text("Select an account to view details, or click Add Account.", 12.0, 0.0, 12.0, TEXT_DIM);
- sec_modify.spacing(lm * 1.8);
}
if let Some(ref msg) = state.status_msg {
- sec_modify.spacing(lm * 1.2);
sec_modify.text(msg, 12.0, 0.0, 12.0, [0.56, 0.83, 0.56, 1.0]);
- sec_modify.spacing(lm * 2.0);
}
}
});
diff --git a/src/pages/audio.rs b/src/pages/audio.rs
index 6323738..9bd795a 100644
--- a/src/pages/audio.rs
+++ b/src/pages/audio.rs
@@ -234,10 +234,8 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
builder.add_section(&mut final_pc, "Output", sec_focused.first().copied().unwrap_or(false), |sec| {
if !state.loaded {
sec.text("Loading output devices...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else if state.sinks.is_empty() {
sec.text("No output devices found", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
}
if state.loaded {
@@ -250,11 +248,8 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
sec.add_section(&sec_title, false, |subsec| {
if !sink.active {
- subsec.spacing(8.0);
subsec.text("Device is inactive.", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(8.0);
} else {
- subsec.spacing(8.0);
let label = if sink.muted {
format!("Volume: {:.0}% (muted)", sink.volume * 100.0)
} else {
@@ -302,10 +297,8 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
builder.add_section(&mut final_pc, "Input", sec_focused.get(1).copied().unwrap_or(false), |sec| {
if !state.loaded {
sec.text("Loading input devices...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else if state.sources.is_empty() {
sec.text("No input devices found", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
}
if state.loaded {
@@ -318,11 +311,8 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
sec.add_section(&sec_title, false, |subsec| {
if !src.active {
- subsec.spacing(8.0);
subsec.text("Device is inactive.", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(8.0);
} else {
- subsec.spacing(8.0);
let label = if src.muted {
format!("Volume: {:.0}% (muted)", src.volume * 100.0)
} else {
diff --git a/src/pages/display.rs b/src/pages/display.rs
index e516eac..c5dd167 100644
--- a/src/pages/display.rs
+++ b/src/pages/display.rs
@@ -279,7 +279,6 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
builder.add_section(&mut final_pc, "Brightness", false, |sec| {
if !state.loaded {
sec.text("Loading display settings...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else {
let bright_pct = if state.max_brightness > 0.0 {
(state.brightness / state.max_brightness * 100.0).round() as i32
@@ -290,11 +289,9 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
let label_h = cce_ui::widget::label_offset(&state.brightness_slider);
let slider_h = cce_ui::layout::slider_height() + label_h;
sec.widget_full(&mut state.brightness_slider, slider_h, ctx);
- sec.spacing(12.0);
state.brightness_spinbox.value = bright_pct;
sec.widget_full(&mut state.brightness_spinbox, cce_ui::layout::spinbox_height(), ctx);
- sec.spacing(12.0);
}
});
@@ -302,12 +299,10 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
builder.add_section(&mut final_pc, "Night Light", false, |sec| {
if !state.loaded {
sec.text("Loading...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else {
let nl_label = if state.night_light { "Night Light: ON" } else { "Night Light: OFF" };
state.night_light_label.set_text(nl_label);
sec.widget(&mut state.night_light_label, 12.0, sec_w - 24.0, 20.0, ctx);
- sec.spacing(8.0);
}
});
@@ -315,7 +310,6 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
builder.add_section(&mut final_pc, "Outputs", false, |sec| {
if !state.loaded {
sec.text("Loading outputs...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else {
for out in &mut state.outputs {
sec.add_section(&out.name, false, |subsec| {
@@ -332,18 +326,14 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
builder.add_section(&mut final_pc, "Screensaver Settings", false, |sec| {
state.screensaver_enable_toggle.set_toggled(state.screensaver_enable);
sec.widget_full(&mut state.screensaver_enable_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(8.0);
state.screensaver_lock_screen_toggle.set_toggled(state.screensaver_lock_screen);
sec.widget_full(&mut state.screensaver_lock_screen_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(16.0);
state.screensaver_timeout_spinbox.value = state.screensaver_timeout;
sec.widget_full(&mut state.screensaver_timeout_spinbox, cce_ui::layout::spinbox_height(), ctx);
- sec.spacing(16.0);
sec.widget_full(&mut state.screensaver_style_menu, cce_ui::layout::dropdown_height(), ctx);
- sec.spacing(24.0);
let btn_h = 32.0;
let btn_y = sec.ay();
@@ -361,7 +351,6 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
crate::app::AppAction::Display(DisplayMessage::StartScreensaverPreview),
);
}
- sec.spacing(12.0);
});
final_pc
diff --git a/src/pages/input.rs b/src/pages/input.rs
index 464688f..c931be7 100644
--- a/src/pages/input.rs
+++ b/src/pages/input.rs
@@ -390,87 +390,68 @@ pub fn view(state: &mut InputState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
builder.add_section(&mut final_pc, "Touchpad", false, |sec| {
state.tap_toggle.set_toggled(state.tap_to_click);
sec.widget_full(&mut state.tap_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(8.0);
// Built-in trackpad visualizer widget
let pad_h = 158.0;
state.trackpad.set_fingers(state.fingers.clone());
sec.widget_full(&mut state.trackpad, pad_h, ctx);
- sec.spacing(12.0);
});
// ── Trackpoint ──
builder.add_section(&mut final_pc, "Trackpoint", sec_focused.first().copied().unwrap_or(false), |sec| {
state.dwtp_toggle.set_toggled(state.dwtp);
sec.widget_full(&mut state.dwtp_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.trackpoint_accel_speed_spinbox, 44.0, ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.trackpoint_accel_profile_menu, 44.0, ctx);
- sec.spacing(8.0);
});
// ── Keyboard ──
builder.add_section(&mut final_pc, "Keyboard", sec_focused.get(1).copied().unwrap_or(false), |sec| {
sec.widget_full(&mut state.rate_spinbox, 44.0, ctx);
- sec.spacing(8.0);
sec.widget_full(&mut state.delay_spinbox, 44.0, ctx);
- sec.spacing(8.0);
});
// ── Cursor ──
builder.add_section(&mut final_pc, "Cursor", sec_focused.get(2).copied().unwrap_or(false), |sec| {
sec.widget_full(&mut state.cursor_theme_menu, 44.0, ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.cursor_size_spinbox, 44.0, ctx);
- sec.spacing(8.0);
});
// ── Scrolling ──
builder.add_section(&mut final_pc, "Scrolling", sec_focused.get(3).copied().unwrap_or(false), |sec| {
state.scroll_toggle.set_toggled(state.inertial_scroll);
sec.widget_full(&mut state.scroll_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.scroll_friction_spinbox, 44.0, ctx);
- sec.spacing(12.0);
state.natural_toggle.set_toggled(state.natural_scroll);
sec.widget_full(&mut state.natural_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.scroll_speed_spinbox, 44.0, ctx);
- sec.spacing(8.0);
});
// ── Inertial Input ──
builder.add_section(&mut final_pc, "Inertial Input", sec_focused.get(4).copied().unwrap_or(false), |sec| {
state.pointer_toggle.set_toggled(state.inertial_pointer);
sec.widget_full(&mut state.pointer_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.pointer_friction_spinbox, 44.0, ctx);
- sec.spacing(16.0);
state.trackpad_toggle.set_toggled(state.inertial_trackpad);
sec.widget_full(&mut state.trackpad_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.trackpad_friction_spinbox, 44.0, ctx);
- sec.spacing(8.0);
});
// ── Graph ──
builder.add_section(&mut final_pc, "Graph", sec_focused.get(5).copied().unwrap_or(false), |sec| {
sec.widget_full(&mut state.zoom_in_box, 44.0, ctx);
- sec.spacing(12.0);
sec.widget_full(&mut state.zoom_out_box, 44.0, ctx);
- sec.spacing(8.0);
});
// ── Keyboard Bindings ──
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index 3212c13..798aaf6 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -1,26 +1,15 @@
use std::fs;
use std::io::Write;
-use crate::app::{AppAction, PageContent, SectionContextExt};
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
+use crate::app::{AppAction, PageContent};
+use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
use cce_ui::widget::{
ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle, MultiControl,
- LayoutPreview, PreviewLayoutMode, Label, Slider
+ Slider
};
const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.json";
const LINKS_PATH: &str = "/home/lsgalante/.config/cce/cce-system-interface/links.json";
-#[derive(Debug, Clone)]
-pub struct StatusData {
- pub font_size: u16,
- pub padding: u16,
- pub separators: bool,
- pub underline: bool,
- pub running: bool,
- pub bg_opacity: f32,
- pub bg_blur: f32,
-}
-
thread_local! {
static TEST_CONFIG_PATH: std::cell::RefCell<Option<String>> = std::cell::RefCell::new(None);
}
@@ -49,43 +38,7 @@ fn get_socket_path() -> String {
}
}
-fn get_status_socket_path() -> String {
- match std::env::var("WAYLAND_DISPLAY") {
- Ok(display) => format!("/tmp/cce-status-{}.sock", display),
- Err(_) => "/tmp/cce-status.sock".to_string(),
- }
-}
-fn query_ipc(cmd: &str) -> String {
- use std::io::{Read, Write};
- if let Ok(mut stream) = std::os::unix::net::UnixStream::connect(get_socket_path()) {
- let _ = stream.set_read_timeout(Some(std::time::Duration::from_millis(20)));
- let _ = stream.set_write_timeout(Some(std::time::Duration::from_millis(20)));
- if stream.write_all(format!("{}\n", cmd).as_bytes()).is_ok() {
- let mut reply = String::new();
- if stream.read_to_string(&mut reply).is_ok() {
- return reply;
- }
- }
- }
- String::new()
-}
-
-fn query_status(sub: &str) -> String {
- use std::io::{BufRead, Write};
- if let Ok(mut stream) = std::os::unix::net::UnixStream::connect(get_status_socket_path()) {
- let _ = stream.set_read_timeout(Some(std::time::Duration::from_millis(20)));
- let _ = stream.set_write_timeout(Some(std::time::Duration::from_millis(20)));
- if stream.write_all(format!("{}\n", sub).as_bytes()).is_ok() {
- let mut reader = std::io::BufReader::new(stream);
- let mut line = String::new();
- if reader.read_line(&mut line).is_ok() {
- return line;
- }
- }
- }
- String::new()
-}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WidthParam {
@@ -262,14 +215,6 @@ pub enum WindowsMessage {
#[derive(Debug, Clone)]
pub struct StatusInterfaceControls {
- pub loaded: bool,
- pub font_size: u16,
- pub separators: bool,
- pub underline: bool,
- pub running: bool,
- pub label: Label,
- pub separators_toggle: Toggle,
- pub underline_toggle: Toggle,
pub box_opacity: f32,
pub box_blur: f32,
pub box_opacity_slider: Slider,
@@ -280,19 +225,13 @@ pub struct StatusInterfaceControls {
impl Default for StatusInterfaceControls {
fn default() -> Self {
+ let opacity = read_status_box_opacity().unwrap_or(1.0);
+ let blur = read_status_box_blur().unwrap_or(0.0);
Self {
- loaded: false,
- font_size: 11,
- separators: true,
- underline: true,
- running: false,
- label: Label::new("Status Interface: Stopped").with_font_size(14.0).with_color([170, 51, 51]),
- separators_toggle: Toggle::new().with_label("Show Separators").with_config(CONFIG_PATH, "status_separators"),
- underline_toggle: Toggle::new().with_label("Show Underline").with_config(CONFIG_PATH, "status_underline"),
- box_opacity: 1.0,
- box_blur: 0.0,
- box_opacity_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(1.0).with_label("Background Opacity").with_config(CONFIG_PATH, "status_box_opacity"),
- box_blur_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(0.0).with_label("Background Blur").with_config(CONFIG_PATH, "status_box_blur"),
+ box_opacity: opacity,
+ box_blur: blur,
+ box_opacity_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(opacity).with_label("Background Opacity").with_config(CONFIG_PATH, "status_box_opacity"),
+ box_blur_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(blur).with_label("Background Blur").with_config(CONFIG_PATH, "status_box_blur"),
opacity_dragging: false,
blur_dragging: false,
}
@@ -359,6 +298,8 @@ pub struct InterfaceState {
pub page_margin_spinbox: Spinbox,
pub grid_min_col_width: u16,
pub grid_min_col_width_spinbox: Spinbox,
+ pub layout_grid_gap: u16,
+ pub layout_grid_gap_spinbox: Spinbox,
pub spinbox_height: u16,
pub spinbox_height_spinbox: Spinbox,
pub spinbox_corner_radius: u16,
@@ -456,7 +397,6 @@ pub struct InterfaceState {
pub graph_gap_width: u16,
pub graph_gap_width_spinbox: Spinbox,
pub custom_multicontrol: MultiControl,
- pub layout_status: Option<LayoutStatusInfo>,
}
impl Default for InterfaceState {
@@ -537,6 +477,8 @@ impl Default for InterfaceState {
page_margin_spinbox: Spinbox::new(20, 0, 100, 1).with_label("Page Margin").with_unit("px").with_config(CONFIG_PATH, "page_margin"),
grid_min_col_width: 260,
grid_min_col_width_spinbox: Spinbox::new(260, 100, 1000, 10).with_label("Minimum Width").with_unit("px").with_config(CONFIG_PATH, "grid_min_col_width"),
+ layout_grid_gap: 8,
+ layout_grid_gap_spinbox: Spinbox::new(8, 0, 100, 1).with_label("Gap").with_unit("px").with_config(CONFIG_PATH, "grid_gap"),
spinbox_height: 26,
spinbox_height_spinbox: Spinbox::new(26, 10, 100, 1).with_label("Height").with_unit("px").with_config(CONFIG_PATH, "spinbox_height"),
spinbox_corner_radius: 4,
@@ -644,7 +586,6 @@ impl Default for InterfaceState {
status_module_spacing_spinbox: Spinbox::new(8, 0, 100, 1).with_label("Spacing").with_unit("px").with_config(CONFIG_PATH, "status_module_spacing"),
status_controls: StatusInterfaceControls::default(),
custom_multicontrol: MultiControl::new("custom_parameters".to_string()).with_label("custom_parameters"),
- layout_status: None,
}
}
}
@@ -694,6 +635,7 @@ pub enum InterfaceMessage {
SetPageMargin(u16),
SetGridMinColWidth(u16),
+ SetLayoutGridGap(u16),
SetSpinboxHeight(u16),
SetSpinboxCornerRadius(u16),
SetToggleHeight(u16),
@@ -750,11 +692,6 @@ pub enum InterfaceMessage {
PickLayerColor,
Refreshed(InterfaceState),
TypefaceRefreshed(InterfaceState),
- LayoutStatusRefreshed(LayoutStatusInfo),
- StatusRefreshed(StatusData),
- StatusToggleSeparators,
- StatusToggleUnderline,
- StatusReload,
StatusSetPadding(u16),
StatusSetBoxOpacity(f32),
StatusSetBoxBlur(f32),
@@ -833,6 +770,7 @@ pub fn read_interface_config() -> InterfaceState {
let page_margin = parse_u16_from(&content, "page_margin", 20);
let grid_min_col_width = parse_u16_from(&content, "grid_min_col_width", 260);
+ let layout_grid_gap = parse_u16_from(&content, "grid_gap", 8);
let spinbox_height = parse_u16_from(&content, "spinbox_height", 26);
let spinbox_corner_radius = parse_u16_from(&content, "spinbox_corner_radius", 4);
let toggle_height = parse_u16_from(&content, "toggle_height", 44);
@@ -955,6 +893,8 @@ pub fn read_interface_config() -> InterfaceState {
page_margin_spinbox: Spinbox::new(page_margin as i32, 0, 100, 1).with_label("Page Margin").with_unit("px").with_config(CONFIG_PATH, "page_margin"),
grid_min_col_width,
grid_min_col_width_spinbox: Spinbox::new(grid_min_col_width as i32, 100, 1000, 10).with_label("Minimum Width").with_unit("px").with_config(CONFIG_PATH, "grid_min_col_width"),
+ layout_grid_gap,
+ layout_grid_gap_spinbox: Spinbox::new(layout_grid_gap as i32, 0, 100, 1).with_label("Gap").with_unit("px").with_config(CONFIG_PATH, "grid_gap"),
spinbox_height,
spinbox_height_spinbox: Spinbox::new(spinbox_height as i32, 10, 100, 1).with_label("Height").with_unit("px").with_config(CONFIG_PATH, "spinbox_height"),
spinbox_corner_radius,
@@ -1061,7 +1001,6 @@ pub fn read_interface_config() -> InterfaceState {
backplate_corner_radius,
backplate_corner_radius_spinbox: Spinbox::new(backplate_corner_radius as i32, 0, 100, 1).with_label("Corner Radius").with_unit("px").with_config(CONFIG_PATH, "backplate_corner_radius"),
custom_multicontrol: MultiControl::new("custom_parameters".to_string()).with_label("custom_parameters"),
- layout_status: None,
}
}
@@ -1285,145 +1224,7 @@ fn apply_edge_gap(val: u16) {
send_ipc_command(&format!("layout gap_bottom {}", val));
}
-#[derive(Debug, Clone, Default)]
-#[allow(dead_code)]
-pub struct PreviewWindow {
- pub app_id: String,
- pub title: String,
- pub x: f32,
- pub y: f32,
- pub w: f32,
- pub h: f32,
- pub tags: u32,
- pub _minimized: bool,
- pub has_parent: bool,
- pub layout_mode: String,
-}
-
-#[derive(Debug, Clone, Default)]
-#[allow(dead_code)]
-pub struct LayoutStatusInfo {
- pub active_tags: u32,
- pub focused_tags: u32,
- pub _num_tags: u32,
- pub windows: Vec<PreviewWindow>,
- pub focused_title: String,
- pub focused_layout_mode: String,
-}
-
-fn get_closest_tag(x: f64, y: f64) -> i32 {
- let centers = [(0.0, 0.0), (2000.0, 0.0), (0.0, 2000.0), (2000.0, 2000.0)];
- let mut min_dist = f64::MAX;
- let mut best_tag = 1;
- for (i, &(cx, cy)) in centers.iter().enumerate() {
- let dx = x - cx;
- let dy = y - cy;
- let dist = dx * dx + dy * dy;
- if dist < min_dist {
- min_dist = dist;
- best_tag = (i + 1) as i32;
- }
- }
- best_tag
-}
-
-pub fn read_current_layout_status() -> LayoutStatusInfo {
- let mut active_tags = 1;
- let mut focused_tags = 1;
- let mut _num_tags = 4;
-
- let tags_content = query_status("tags");
- if let Some(pan_idx) = tags_content.find("Pan: (") {
- let coords_str = &tags_content[pan_idx + "Pan: (".len()..];
- if let Some(end_idx) = coords_str.find(")") {
- let parts: Vec<&str> = coords_str[..end_idx].split(',').collect();
- if parts.len() == 2 {
- let pan_x = parts[0].trim().parse::<f64>().unwrap_or(0.0);
- let pan_y = parts[1].trim().parse::<f64>().unwrap_or(0.0);
- let best_tag = get_closest_tag(pan_x, pan_y);
- active_tags = 1 << (best_tag - 1);
- focused_tags = active_tags;
- }
- }
- }
- let focused_title = query_status("title").trim().to_string();
- let focused_layout_mode = query_status("layout").trim().to_string();
-
- let windows_content = query_ipc("windows");
-
- let mut windows = Vec::new();
- for line in windows_content.lines() {
- if !line.starts_with("window ") { continue; }
-
- let mut app_id = String::new();
- let mut title = String::new();
- let mut x = 0.0;
- let mut y = 0.0;
- let mut w = 0.0;
- let mut h = 0.0;
- let mut tags = 0;
- let mut minimized = false;
- let mut has_parent = false;
- let mut layout_mode = "Cascade".to_string();
-
- let parts = line.strip_prefix("window ").unwrap_or(line);
-
- let get_val = |p: &str, k: &str| -> Option<String> {
- if let Some(idx) = p.find(k) {
- let start = idx + k.len();
- let mut end = p.len();
- let next_keys = [
- " app_id=", " title=", " mode=", " decoration=", " presentation=",
- " tags=", " x=", " y=", " w=", " h=", " has_parent=", " minimized="
- ];
- for nk in next_keys {
- if nk != k {
- if let Some(nidx) = p[start..].find(nk) {
- end = end.min(start + nidx);
- }
- }
- }
- Some(p[start..end].trim().to_string())
- } else {
- None
- }
- };
-
- if let Some(val) = get_val(parts, "app_id=") { app_id = val; }
- if let Some(val) = get_val(parts, "title=") { title = val; }
- if let Some(val) = get_val(parts, "x=") { x = val.parse().unwrap_or(0.0); }
- if let Some(val) = get_val(parts, "y=") { y = val.parse().unwrap_or(0.0); }
- if let Some(val) = get_val(parts, "w=") { w = val.parse().unwrap_or(0.0); }
- if let Some(val) = get_val(parts, "h=") { h = val.parse().unwrap_or(0.0); }
- if let Some(val) = get_val(parts, "tags=") { tags = val.parse().unwrap_or(0); }
- if let Some(val) = get_val(parts, "minimized=") { minimized = val == "true"; }
- if let Some(val) = get_val(parts, "has_parent=") { has_parent = val == "true"; }
- if let Some(val) = get_val(parts, "mode=") { layout_mode = val; }
-
- windows.push(PreviewWindow {
- app_id,
- title,
- x,
- y,
- w,
- h,
- tags,
- _minimized: minimized,
- has_parent,
- layout_mode,
- });
- }
-
- LayoutStatusInfo {
- active_tags,
- focused_tags,
- _num_tags,
- windows,
- focused_title,
- focused_layout_mode,
- }
-}
fn set_width(state: &mut WindowsState, param: WidthParam, val: u16) {
let val = val.min(100);
@@ -1672,6 +1473,15 @@ pub fn propagate_links(state: &mut InterfaceState, key: &str, val_str: &str) {
apply_grid_min_col_width(val);
}
}
+ "grid_gap" => {
+ if let Ok(val) = val_str.parse::<u16>() {
+ state.layout_grid_gap = val;
+ state.layout_grid_gap_spinbox.value = val as i32;
+ state.windows.grid_gap = val;
+ state.windows.grid_gap_spinbox.value = val as i32;
+ apply_layout_grid_gap(val);
+ }
+ }
"spinbox_height" => {
if let Ok(val) = val_str.parse::<u16>() {
state.spinbox_height = val;
@@ -1968,11 +1778,7 @@ fn write_status_value(key: &str, value: &str) {
write_config_value_path(&get_config_path(), key, value);
}
-fn read_status_font_size() -> Option<u16> {
- let content = std::fs::read_to_string(&get_config_path()).ok()?;
- Some(parse_u16_from(&content, "status_font_size", 11))
-}
-
+#[allow(dead_code)]
fn read_status_padding() -> Option<u16> {
let content = std::fs::read_to_string(&get_config_path()).ok()?;
Some(parse_u16_from(&content, "status_padding", 8))
@@ -1982,24 +1788,6 @@ fn write_status_padding(padding: u16) {
write_status_value("status_padding", &padding.to_string());
}
-fn read_status_separators() -> Option<bool> {
- let content = std::fs::read_to_string(&get_config_path()).ok()?;
- Some(parse_bool_from(&content, "status_separators", true))
-}
-
-fn write_status_separators(val: bool) {
- write_status_value("status_separators", &val.to_string());
-}
-
-fn read_status_underline() -> Option<bool> {
- let content = std::fs::read_to_string(&get_config_path()).ok()?;
- Some(parse_bool_from(&content, "status_underline", true))
-}
-
-fn write_status_underline(val: bool) {
- write_status_value("status_underline", &val.to_string());
-}
-
fn read_status_box_opacity() -> Option<f32> {
let content = std::fs::read_to_string(&get_config_path()).ok()?;
Some(parse_f32_from(&content, "status_box_opacity", 1.0))
@@ -2018,30 +1806,6 @@ fn write_status_box_blur(val: f32) {
write_status_value("status_box_blur", &val.to_string());
}
-pub async fn fetch_status_state() -> StatusData {
- let running = tokio::process::Command::new("pgrep")
- .args(["-f", "cce-status-interface"]).output().await.ok()
- .map(|o| !o.stdout.is_empty())
- .unwrap_or(false);
-
- let font_size = read_status_font_size().unwrap_or(11);
- let padding = read_status_padding().unwrap_or(8);
- let separators = read_status_separators().unwrap_or(true);
- let underline = read_status_underline().unwrap_or(true);
- let bg_opacity = read_status_box_opacity().unwrap_or(1.0);
- let bg_blur = read_status_box_blur().unwrap_or(0.0);
-
- StatusData {
- font_size,
- padding,
- separators,
- underline,
- running,
- bg_opacity,
- bg_blur,
- }
-}
-
fn apply_visual_guides_color(rgb: [u8; 3]) {
let hex = format!("\"#{:02x}{:02x}{:02x}\"", rgb[0], rgb[1], rgb[2]);
@@ -2286,6 +2050,12 @@ fn apply_grid_min_col_width(width: u16) {
cce_ui::layout::set_grid_min_col_width(width as f32);
}
+fn apply_layout_grid_gap(gap: u16) {
+ write_config_value("grid_gap", &gap.to_string());
+ cce_ui::layout::set_grid_gap(gap as f32);
+ send_ipc_command(&format!("layout grid_gap {}", gap));
+}
+
fn apply_section_padding(padding: u16) {
write_config_value("section_padding", &padding.to_string());
cce_ui::layout::set_section_padding(padding as f32);
@@ -2795,371 +2565,235 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
// 1. Custom Parameters Section
builder.add_section_with_width(&mut final_pc, cw, "Custom Parameters", false, |sec| {
- sec.spacing(8.0);
let h = state.custom_multicontrol.preferred_height().unwrap_or(100.0);
sec.widget_full(&mut state.custom_multicontrol, h, ctx);
- sec.spacing(8.0);
});
// 2. Layout Section
builder.add_section_with_width(&mut final_pc, cw, "Layout", false, |sec| {
- sec.spacing(8.0);
state.color_selectors[1].color = state.high_color;
sec.widget_full(&mut state.color_selectors[1], 40.0, ctx);
- sec.spacing(8.0);
state.color_selectors[2].color = state.visual_guides_color;
sec.widget_full(&mut state.color_selectors[2], 40.0, ctx);
- sec.spacing(12.0);
// Grid Layout child section
sec.add_section("Adaptive Grid", false, |subsec| {
- subsec.spacing(8.0);
state.grid_min_col_width_spinbox.value = state.grid_min_col_width as i32;
subsec.widget_full(&mut state.grid_min_col_width_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
+ state.layout_grid_gap_spinbox.value = state.layout_grid_gap as i32;
+ subsec.widget_full(&mut state.layout_grid_gap_spinbox, 44.0, ctx);
});
- sec.spacing(12.0);
});
// 3. Status Section
builder.add_section_with_width(&mut final_pc, cw, "Status", false, |sec| {
- const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
- sec.spacing(8.0);
state.color_selectors[7].color = state.normal_color;
sec.widget_full(&mut state.color_selectors[7], 40.0, ctx);
- sec.spacing(8.0);
state.color_selectors[3].color = state.disabled_color;
sec.widget_full(&mut state.color_selectors[3], 40.0, ctx);
- sec.spacing(8.0);
state.color_selectors[22].color = state.status_box_background_color;
sec.widget_full(&mut state.color_selectors[22], 40.0, ctx);
- sec.spacing(8.0);
state.status_box_corner_radius_spinbox.value = state.status_box_corner_radius as i32;
sec.widget_full(&mut state.status_box_corner_radius_spinbox, 44.0, ctx);
- sec.spacing(8.0);
state.status_padding_spinbox.value = state.status_padding as i32;
sec.widget_full(&mut state.status_padding_spinbox, 44.0, ctx);
- sec.spacing(8.0);
state.status_module_spacing_spinbox.value = state.status_module_spacing as i32;
sec.widget_full(&mut state.status_module_spacing_spinbox, 44.0, ctx);
- sec.spacing(8.0);
- if !state.status_controls.loaded {
- sec.text("Loading Status Interface status...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(8.0);
- } else {
- // Status
- let status_text = if state.status_controls.running { "Status Interface: Running" } else { "Status Interface: Stopped" };
- let status_color = if state.status_controls.running { [92, 143, 97] } else { [170, 51, 51] };
- state.status_controls.label.set_text(status_text);
- state.status_controls.label.set_color(status_color);
- sec.widget_full(&mut state.status_controls.label, 20.0, ctx);
- sec.spacing(8.0);
-
- // Separators toggle
- state.status_controls.separators_toggle.set_toggled(state.status_controls.separators);
- sec.widget_full(&mut state.status_controls.separators_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(8.0);
-
- // Underline toggle
- state.status_controls.underline_toggle.set_toggled(state.status_controls.underline);
- sec.widget_full(&mut state.status_controls.underline_toggle, cce_ui::layout::toggle_height(), ctx);
- sec.spacing(8.0);
-
- // Opacity slider
- state.status_controls.box_opacity_slider.set_label(&format!("Background Opacity: {}%", (state.status_controls.box_opacity * 100.0).round() as i32));
- state.status_controls.box_opacity_slider.set_value(state.status_controls.box_opacity);
- let label_h_op = cce_ui::widget::label_offset(&state.status_controls.box_opacity_slider);
- let slider_h_op = cce_ui::layout::slider_height() + label_h_op;
- sec.widget_full(&mut state.status_controls.box_opacity_slider, slider_h_op, ctx);
- sec.spacing(8.0);
-
- // Blur slider
- state.status_controls.box_blur_slider.set_label(&format!("Background Blur: {}%", (state.status_controls.box_blur * 100.0).round() as i32));
- state.status_controls.box_blur_slider.set_value(state.status_controls.box_blur);
- let label_h_bl = cce_ui::widget::label_offset(&state.status_controls.box_blur_slider);
- let slider_h_bl = cce_ui::layout::slider_height() + label_h_bl;
- sec.widget_full(&mut state.status_controls.box_blur_slider, slider_h_bl, ctx);
- sec.spacing(8.0);
-
- // Reload button
- let yt_reload = sec.ay();
- let btn_w = cw - 24.0;
- let button_x = sec.left + 12.0;
- sec.button(
- "Reload Status Interface",
- button_x,
- yt_reload,
- btn_w,
- 32.0,
- [0.13, 0.18, 0.14, 1.0],
- [0.25, 0.30, 0.26, 1.0],
- [1.0, 1.0, 1.0, 1.0],
- crate::app::AppAction::Interface(InterfaceMessage::StatusReload),
- );
- sec.spacing(12.0);
- }
+ // Opacity slider
+ state.status_controls.box_opacity_slider.set_label(&format!("Background Opacity: {}%", (state.status_controls.box_opacity * 100.0).round() as i32));
+ state.status_controls.box_opacity_slider.set_value(state.status_controls.box_opacity);
+ let label_h_op = cce_ui::widget::label_offset(&state.status_controls.box_opacity_slider);
+ let slider_h_op = cce_ui::layout::slider_height() + label_h_op;
+ sec.widget_full(&mut state.status_controls.box_opacity_slider, slider_h_op, ctx);
+
+ // Blur slider
+ state.status_controls.box_blur_slider.set_label(&format!("Background Blur: {}%", (state.status_controls.box_blur * 100.0).round() as i32));
+ state.status_controls.box_blur_slider.set_value(state.status_controls.box_blur);
+ let label_h_bl = cce_ui::widget::label_offset(&state.status_controls.box_blur_slider);
+ let slider_h_bl = cce_ui::layout::slider_height() + label_h_bl;
+ sec.widget_full(&mut state.status_controls.box_blur_slider, slider_h_bl, ctx);
});
// 4. Controls Section
builder.add_section_with_width(&mut final_pc, cw, "Controls", false, |sec| {
- sec.spacing(8.0);
state.color_selectors[5].color = state.color_borders_color;
sec.widget_full(&mut state.color_selectors[5], 40.0, ctx);
- sec.spacing(12.0);
// Slider Section
sec.add_section("Slider", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[4].color = state.slider_track_color;
subsec.widget_full(&mut state.color_selectors[4], 40.0, ctx);
- subsec.spacing(8.0);
state.slider_height_spinbox.value = state.slider_height as i32;
subsec.widget_full(&mut state.slider_height_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// MenuBar Section
sec.add_section("MenuBar", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[8].color = state.paginator_sidebar_color;
subsec.widget_full(&mut state.color_selectors[8], 40.0, ctx);
- subsec.spacing(8.0);
state.color_selectors[10].color = state.menubar_tab_label_color;
subsec.widget_full(&mut state.color_selectors[10], 40.0, ctx);
state.menubar_font_selector.font_family = state.menubar_font.clone();
subsec.widget_full(&mut state.menubar_font_selector, 44.0, ctx);
- subsec.spacing(8.0);
state.menubar_opacity_spinbox.value = (state.menubar_opacity * 100.0).round() as i32;
subsec.widget_full(&mut state.menubar_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Toggle Section
sec.add_section("Toggle", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[11].color = state.toggle_enabled_color;
subsec.widget_full(&mut state.color_selectors[11], 40.0, ctx);
- subsec.spacing(8.0);
state.color_selectors[12].color = state.toggle_disabled_color;
subsec.widget_full(&mut state.color_selectors[12], 40.0, ctx);
- subsec.spacing(8.0);
state.toggle_height_spinbox.value = state.toggle_height as i32;
subsec.widget_full(&mut state.toggle_height_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.toggle_corner_radius_spinbox.value = state.toggle_corner_radius as i32;
subsec.widget_full(&mut state.toggle_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// Breadcrumb Section
sec.add_section("Breadcrumb", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[14].color = state.breadcrumb_bg_color;
subsec.widget_full(&mut state.color_selectors[14], 40.0, ctx);
- subsec.spacing(8.0);
state.breadcrumb_font_selector.font_family = state.breadcrumb_font.clone();
subsec.widget_full(&mut state.breadcrumb_font_selector, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Spinbox Section
sec.add_section("Spinbox", false, |subsec| {
- subsec.spacing(8.0);
state.spinbox_height_spinbox.value = state.spinbox_height as i32;
subsec.widget_full(&mut state.spinbox_height_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.spinbox_corner_radius_spinbox.value = state.spinbox_corner_radius as i32;
subsec.widget_full(&mut state.spinbox_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// ColorSelector Section
sec.add_section("ColorSelector", false, |subsec| {
- subsec.spacing(8.0);
state.color_selector_height_spinbox.value = state.color_selector_height as i32;
subsec.widget_full(&mut state.color_selector_height_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.color_selector_preview_corner_radius_spinbox.value = state.color_selector_preview_corner_radius as i32;
subsec.widget_full(&mut state.color_selector_preview_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(12.0);
state.color_selector_preview_margin_spinbox.value = state.color_selector_preview_margin as i32;
subsec.widget_full(&mut state.color_selector_preview_margin_spinbox, 44.0, ctx);
- subsec.spacing(12.0);
state.color_selector_corner_radius_spinbox.value = state.color_selector_corner_radius as i32;
subsec.widget_full(&mut state.color_selector_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.color_selector_font_selector.font_family = state.color_selector_font.clone();
subsec.widget_full(&mut state.color_selector_font_selector, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Textbox Section
sec.add_section("Textbox", false, |subsec| {
- subsec.spacing(8.0);
state.textbox_height_spinbox.value = state.textbox_height as i32;
subsec.widget_full(&mut state.textbox_height_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.textbox_corner_radius_spinbox.value = state.textbox_corner_radius as i32;
subsec.widget_full(&mut state.textbox_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// FontSelector Section
sec.add_section("FontSelector", false, |subsec| {
- subsec.spacing(8.0);
state.font_selector_height_spinbox.value = state.font_selector_height as i32;
subsec.widget_full(&mut state.font_selector_height_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.font_selector_corner_radius_spinbox.value = state.font_selector_corner_radius as i32;
subsec.widget_full(&mut state.font_selector_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Dropdown Section
sec.add_section("Dropdown", false, |subsec| {
- subsec.spacing(8.0);
state.dropdown_height_spinbox.value = state.dropdown_height as i32;
subsec.widget_full(&mut state.dropdown_height_spinbox, 44.0, ctx);
- subsec.spacing(4.0);
state.dropdown_corner_radius_spinbox.value = state.dropdown_corner_radius as i32;
subsec.widget_full(&mut state.dropdown_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Button Section
sec.add_section("Button", false, |subsec| {
- subsec.spacing(8.0);
state.button_corner_radius_spinbox.value = state.button_corner_radius as i32;
subsec.widget_full(&mut state.button_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// ButtonStrip Section
sec.add_section("ButtonStrip", false, |subsec| {
- subsec.spacing(8.0);
state.button_padding_spinbox.value = state.button_padding as i32;
subsec.widget_full(&mut state.button_padding_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.button_strip_spacing_spinbox.value = state.button_strip_spacing as i32;
subsec.widget_full(&mut state.button_strip_spacing_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Labels Section
sec.add_section("Labels", false, |subsec| {
- subsec.spacing(8.0);
state.label_margin_spinbox.value = state.label_margin as i32;
subsec.widget_full(&mut state.label_margin_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(8.0);
});
// 5. Indicators Section
builder.add_section_with_width(&mut final_pc, cw, "Indicators", false, |sec| {
- sec.spacing(8.0);
sec.add_section("Primary Highlight", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[9].color = state.primary_highlight_color;
subsec.widget_full(&mut state.color_selectors[9], 40.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(8.0);
});
// 5. Notification Section
builder.add_section_with_width(&mut final_pc, cw, "Notification", false, |sec| {
- sec.spacing(8.0);
state.color_selectors[16].color = state.notification_bg_color;
sec.widget_full(&mut state.color_selectors[16], 40.0, ctx);
- sec.spacing(8.0);
state.notification_opacity_spinbox.value = (state.notification_opacity * 100.0).round() as i32;
sec.widget_full(&mut state.notification_opacity_spinbox, 44.0, ctx);
- sec.spacing(8.0);
});
// 6. Surfaces Section
builder.add_section_with_width(&mut final_pc, cw, "Surfaces", sec_focused.get(6).copied().unwrap_or(false), |sec| {
- sec.spacing(12.0);
sec.add_section("Backplate", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[17].color = state.backplate_color;
subsec.widget_full(&mut state.color_selectors[17], 40.0, ctx);
- subsec.spacing(8.0);
state.backplate_corner_radius_spinbox.value = state.backplate_corner_radius as i32;
subsec.widget_full(&mut state.backplate_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Plate child section
sec.add_section("Plate", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[0].color = state.page_low_color;
subsec.widget_full(&mut state.color_selectors[0], 40.0, ctx);
- subsec.spacing(8.0);
state.plate_padding_spinbox.value = state.plate_padding as i32;
subsec.widget_full(&mut state.plate_padding_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.plate_opacity_spinbox.value = (state.plate_opacity * 100.0).round() as i32;
subsec.widget_full(&mut state.plate_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.plate_corner_radius_spinbox.value = state.plate_corner_radius as i32;
subsec.widget_full(&mut state.plate_corner_radius_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Popover Section
sec.add_section("Popover", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[15].color = state.popover_bg_color;
subsec.widget_full(&mut state.color_selectors[15], 40.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Desktop Section
sec.add_section("Desktop", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[6].color = state.desktop_background_color;
subsec.widget_full(&mut state.color_selectors[6], 40.0, ctx);
- subsec.spacing(8.0);
let grid_color_rgba = state.desktop_grid_color;
state.color_selectors[23].color = [grid_color_rgba[0], grid_color_rgba[1], grid_color_rgba[2]];
state.color_selectors[23].alpha = grid_color_rgba[3];
subsec.widget_full(&mut state.color_selectors[23], 40.0, ctx);
- subsec.spacing(8.0);
state.desktop_grid_scale_spinbox.value = state.desktop_grid_scale as i32;
subsec.widget_full(&mut state.desktop_grid_scale_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.desktop_line_width_spinbox.value = state.desktop_line_width as i32;
subsec.widget_full(&mut state.desktop_line_width_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
});
@@ -3168,38 +2802,29 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
// 7. Fonts Section
builder.add_section_with_width(&mut final_pc, cw, "Fonts", sec_focused.get(7).copied().unwrap_or(false), |sec| {
- sec.spacing(8.0);
// System Fonts Section
sec.add_section("System Fonts", false, |subsec| {
- subsec.spacing(8.0);
if !state.typeface_loaded {
subsec.text("Loading typefaces...", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(18.0);
} else {
// Sans-Serif
subsec.widget_full(&mut state.sans_box, 44.0, ctx);
- subsec.spacing(12.0);
// Serif
subsec.widget_full(&mut state.serif_box, 44.0, ctx);
- subsec.spacing(12.0);
// Monospace
subsec.widget_full(&mut state.mono_box, 44.0, ctx);
- subsec.spacing(8.0);
}
});
- sec.spacing(12.0);
// Program Fonts Section
sec.add_section("Program Fonts", false, |subsec| {
- subsec.spacing(8.0);
if !state.typeface_loaded {
subsec.text("Loading typefaces...", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(18.0);
} else {
// Window Borders
let start_y = subsec.ay();
@@ -3210,9 +2835,7 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
state.borders_size_box.set_row_rect(cols[1].0, cols[1].1);
cce_ui::layout::render_widget(subsec.pc, &mut state.borders_size_box, cols[1].0, start_y, cols[1].1, widget_h, ctx);
}
- subsec.spacing(widget_h);
subsec.widget_full(&mut state.borders_box, 44.0, ctx);
- subsec.spacing(16.0);
// Status Interface
let start_y = subsec.ay();
@@ -3223,9 +2846,7 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
state.status_size_box.set_row_rect(cols[1].0, cols[1].1);
cce_ui::layout::render_widget(subsec.pc, &mut state.status_size_box, cols[1].0, start_y, cols[1].1, widget_h, ctx);
}
- subsec.spacing(widget_h);
subsec.widget_full(&mut state.status_box, 44.0, ctx);
- subsec.spacing(16.0);
// Fuzzel
let start_y = subsec.ay();
@@ -3236,9 +2857,7 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
state.fuzzel_size_box.set_row_rect(cols[1].0, cols[1].1);
cce_ui::layout::render_widget(subsec.pc, &mut state.fuzzel_size_box, cols[1].0, start_y, cols[1].1, widget_h, ctx);
}
- subsec.spacing(widget_h);
subsec.widget_full(&mut state.fuzzel_box, 44.0, ctx);
- subsec.spacing(16.0);
// Terminal
let start_y = subsec.ay();
@@ -3249,270 +2868,164 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
state.terminal_size_box.set_row_rect(cols[1].0, cols[1].1);
cce_ui::layout::render_widget(subsec.pc, &mut state.terminal_size_box, cols[1].0, start_y, cols[1].1, widget_h, ctx);
}
- subsec.spacing(widget_h);
subsec.widget_full(&mut state.terminal_box, 44.0, ctx);
- subsec.spacing(8.0);
}
});
- sec.spacing(8.0);
});
builder.add_section_with_width(&mut final_pc, cw, "Containers", sec_focused.get(8).copied().unwrap_or(false), |sec| {
- sec.spacing(12.0);
// Page child section
sec.add_section("Page", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[18].color = state.page_color;
subsec.widget_full(&mut state.color_selectors[18], 40.0, ctx);
- subsec.spacing(8.0);
state.page_opacity_spinbox.value = (state.page_opacity * 100.0).round() as i32;
subsec.widget_full(&mut state.page_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Layer child section
sec.add_section("Layer", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[19].color = state.layer_color;
subsec.widget_full(&mut state.color_selectors[19], 40.0, ctx);
- subsec.spacing(8.0);
state.layer_opacity_spinbox.value = (state.layer_opacity * 100.0).round() as i32;
subsec.widget_full(&mut state.layer_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Section child section
sec.add_section("Section", false, |subsec| {
- subsec.spacing(8.0);
state.section_padding_spinbox.value = state.section_padding as i32;
subsec.widget_full(&mut state.section_padding_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.page_margin_spinbox.value = state.page_margin as i32;
subsec.widget_full(&mut state.page_margin_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.section_label_font_selector.font_family = state.section_label_font.clone();
subsec.widget_full(&mut state.section_label_font_selector, 44.0, ctx);
- subsec.spacing(12.0);
// Nested Section child section
subsec.add_section("Nested Section", false, |subsubsec| {
- subsubsec.spacing(8.0);
subsubsec.widget_full(&mut state.label_alignment_menu, 44.0, ctx);
- subsubsec.spacing(8.0);
state.label_offset_spinbox.value = state.nested_section_label_offset as i32;
subsubsec.widget_full(&mut state.label_offset_spinbox, 44.0, ctx);
- subsubsec.spacing(8.0);
state.nested_section_label_font_selector.font_family = state.nested_section_label_font.clone();
subsubsec.widget_full(&mut state.nested_section_label_font_selector, 44.0, ctx);
- subsubsec.spacing(8.0);
});
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// ScrollingList Section
sec.add_section("ScrollingList", false, |subsec| {
- subsec.spacing(8.0);
state.color_selectors[13].color = state.scrollinglist_bg_color;
subsec.widget_full(&mut state.color_selectors[13], 40.0, ctx);
- subsec.spacing(8.0);
let bg_rgba = state.scrollinglist_entry_bg_color;
state.color_selectors[20].color = [bg_rgba[0], bg_rgba[1], bg_rgba[2]];
state.color_selectors[20].alpha = bg_rgba[3];
subsec.widget_full(&mut state.color_selectors[20], 40.0, ctx);
- subsec.spacing(8.0);
let highlight_rgba = state.scrollinglist_entry_highlight_color;
state.color_selectors[21].color = [highlight_rgba[0], highlight_rgba[1], highlight_rgba[2]];
state.color_selectors[21].alpha = highlight_rgba[3];
subsec.widget_full(&mut state.color_selectors[21], 40.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
// Graph child section
sec.add_section("Graph", false, |subsec| {
- subsec.spacing(8.0);
state.graph_show_grid_toggle.set_toggled(state.graph_show_grid);
subsec.widget_full(&mut state.graph_show_grid_toggle, state.toggle_height as f32, ctx);
- subsec.spacing(8.0);
state.graph_snap_enabled_toggle.set_toggled(state.graph_snap_enabled);
subsec.widget_full(&mut state.graph_snap_enabled_toggle, state.toggle_height as f32, ctx);
- subsec.spacing(8.0);
state.graph_uniform_background_toggle.set_toggled(state.graph_uniform_background);
subsec.widget_full(&mut state.graph_uniform_background_toggle, state.toggle_height as f32, ctx);
- subsec.spacing(8.0);
state.graph_cell_opacity_spinbox.value = (state.graph_cell_opacity * 100.0).round() as i32;
subsec.widget_full(&mut state.graph_cell_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.graph_gap_opacity_spinbox.value = (state.graph_gap_opacity * 100.0).round() as i32;
subsec.widget_full(&mut state.graph_gap_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.graph_gap_width_spinbox.value = state.graph_gap_width as i32;
subsec.widget_full(&mut state.graph_gap_width_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
- sec.spacing(12.0);
});
// 10. Windows Section
builder.add_section_with_width(&mut final_pc, cw, "Windows", sec_focused.get(9).copied().unwrap_or(false), |sec| {
- sec.spacing(8.0);
-
- // 1. Current Layout Preview
- sec.add_section("Current Layout", false, |sec_cl| {
- sec_cl.spacing(8.0);
-
- let info = state.layout_status.as_ref().cloned().unwrap_or_default();
-
- let card_w = (sec_w - 24.0) / 2.0;
- let card_h = 135.0;
- let rx = sec_cl.left;
-
- for tag_idx in 0..4 {
- let col = tag_idx % 2;
- let row = tag_idx / 2;
- let tx = rx + 8.0 + col as f32 * (card_w + 8.0);
- let ty = sec_cl.ay() + row as f32 * (card_h + 8.0);
-
- let is_active = (info.active_tags & (1 << tag_idx)) != 0;
- let layout_idx = state.windows.tag_layout_menus.get(tag_idx).map(|m| m.selected).unwrap_or(0);
- let mode = match layout_idx {
- 1 => PreviewLayoutMode::Cascade,
- 2 => PreviewLayoutMode::Stack,
- 3 => PreviewLayoutMode::Grid,
- 4 => PreviewLayoutMode::LeftTiled,
- 5 => PreviewLayoutMode::RightTiled,
- 6 => PreviewLayoutMode::Equal,
- 7 => PreviewLayoutMode::Spiral,
- 8 => PreviewLayoutMode::Floating,
- _ => PreviewLayoutMode::Fullscreen,
- };
-
- let mut preview = LayoutPreview::new(mode)
- .with_active(is_active)
- .with_label(&format!("TAG {}", tag_idx + 1));
- render_widget(sec_cl.pc, &mut preview, tx, ty, card_w, card_h, ctx);
- }
-
- sec_cl.content_y += 2.0 * (card_h + 8.0) + 4.0;
- });
+
// 2. Fullscreen Section
sec.add_section("Fullscreen", false, |subsec| {
- subsec.spacing(8.0);
state.windows.spinboxes[0].set_label("Border Width");
subsec.widget_full(&mut state.windows.spinboxes[0], 44.0, ctx);
- subsec.spacing(8.0);
state.windows.fullscreen_opacity_spinbox.set_label("Backplate Opacity");
subsec.widget_full(&mut state.windows.fullscreen_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 3. Cascade Section
sec.add_section("Cascade", false, |subsec| {
- subsec.spacing(8.0);
state.windows.spinboxes[1].set_label("Border Width");
subsec.widget_full(&mut state.windows.spinboxes[1], 44.0, ctx);
- subsec.spacing(8.0);
state.windows.cascade_offset_spinbox.set_label("Offset");
subsec.widget_full(&mut state.windows.cascade_offset_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.edge_gap_spinbox.set_label("Edge Gap");
subsec.widget_full(&mut state.windows.edge_gap_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.top_gap_spinbox.set_label("Top Gap");
subsec.widget_full(&mut state.windows.top_gap_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.cascade_opacity_spinbox.set_label("Backplate Opacity");
subsec.widget_full(&mut state.windows.cascade_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 4. Grid Section
sec.add_section("Grid", false, |subsec| {
- subsec.spacing(8.0);
state.windows.spinboxes[2].set_label("Border Width");
subsec.widget_full(&mut state.windows.spinboxes[2], 44.0, ctx);
- subsec.spacing(8.0);
state.windows.grid_gap_spinbox.set_label("Gap");
subsec.widget_full(&mut state.windows.grid_gap_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.grid_opacity_spinbox.set_label("Backplate Opacity");
subsec.widget_full(&mut state.windows.grid_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 5. Floating Section
sec.add_section("Floating", false, |subsec| {
- subsec.spacing(8.0);
state.windows.spinboxes[3].set_label("Border Width");
subsec.widget_full(&mut state.windows.spinboxes[3], 44.0, ctx);
- subsec.spacing(8.0);
state.windows.floating_opacity_spinbox.set_label("Backplate Opacity");
subsec.widget_full(&mut state.windows.floating_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 6. Movement Section
sec.add_section("Movement", false, |subsec| {
- subsec.spacing(8.0);
state.windows.transition_duration_spinbox.set_label("Duration (ms)");
subsec.widget_full(&mut state.windows.transition_duration_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 7. Default Layouts Section
sec.add_section("Default Layouts", false, |subsec| {
- subsec.spacing(8.0);
for i in 0..4 {
subsec.widget_full(&mut state.windows.tag_layout_menus[i], 44.0, ctx);
- subsec.spacing(8.0);
}
});
// 8. Pinned Section
sec.add_section("Pinned", false, |subsec| {
- subsec.spacing(8.0);
subsec.widget_full(&mut state.windows.side_panel_behavior_menu, 44.0, ctx);
- subsec.spacing(8.0);
subsec.widget_full(&mut state.windows.side_panel_position_menu, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.side_panel_width_spinbox.set_label("Default Width");
subsec.widget_full(&mut state.windows.side_panel_width_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.side_panel_border_gap_spinbox.set_label("Border Gap");
subsec.widget_full(&mut state.windows.side_panel_border_gap_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.side_panel_border_opacity_spinbox.set_label("Border Opacity");
subsec.widget_full(&mut state.windows.side_panel_border_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
state.windows.pinned_opacity_spinbox.set_label("Backplate Opacity");
subsec.widget_full(&mut state.windows.pinned_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 8b. Popup Section
sec.add_section("Popup", false, |subsec| {
- subsec.spacing(8.0);
state.windows.popup_opacity_spinbox.set_label("Backplate Opacity");
subsec.widget_full(&mut state.windows.popup_opacity_spinbox, 44.0, ctx);
- subsec.spacing(8.0);
});
// 9. Effects Section
sec.add_section("Effects", false, |subsec| {
- subsec.spacing(8.0);
state.windows.blur_toggle.set_toggled(state.windows.blur_enabled);
subsec.widget_full(&mut state.windows.blur_toggle, cce_ui::layout::toggle_height(), ctx);
- subsec.spacing(8.0);
});
- sec.spacing(8.0);
});
final_pc
@@ -3639,38 +3152,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.status_padding_spinbox.value = padding as i32;
apply_status_padding(padding);
}
- InterfaceMessage::StatusRefreshed(new) => {
- let was_status_hovered = state.status_controls.label.hovered();
- let was_separators_hovered = state.status_controls.separators_toggle.hovered();
- let was_underline_hovered = state.status_controls.underline_toggle.hovered();
- let was_opacity_hovered = state.status_controls.box_opacity_slider.hovered();
- let was_blur_hovered = state.status_controls.box_blur_slider.hovered();
-
- state.status_controls.loaded = true;
- state.status_controls.font_size = new.font_size;
- state.status_padding = new.padding;
- state.status_controls.separators = new.separators;
- state.status_controls.underline = new.underline;
- state.status_controls.running = new.running;
- state.status_controls.box_opacity = new.bg_opacity;
- state.status_controls.box_blur = new.bg_blur;
-
- state.status_controls.label.set_hovered(was_status_hovered);
- state.status_controls.separators_toggle.set_hovered(was_separators_hovered);
- state.status_controls.underline_toggle.set_hovered(was_underline_hovered);
- state.status_controls.box_opacity_slider.set_hovered(was_opacity_hovered);
- state.status_controls.box_blur_slider.set_hovered(was_blur_hovered);
- }
- InterfaceMessage::StatusToggleSeparators => {
- state.status_controls.separators = !state.status_controls.separators;
- write_status_separators(state.status_controls.separators);
- status_interface_reload();
- }
- InterfaceMessage::StatusToggleUnderline => {
- state.status_controls.underline = !state.status_controls.underline;
- write_status_underline(state.status_controls.underline);
- status_interface_reload();
- }
InterfaceMessage::StatusSetPadding(val) => {
state.status_padding = val;
write_status_padding(val);
@@ -3686,9 +3167,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
write_status_box_blur(val);
status_interface_reload();
}
- InterfaceMessage::StatusReload => {
- status_interface_reload();
- }
InterfaceMessage::SetStatusModuleSpacing(spacing) => {
state.status_module_spacing = spacing;
state.status_module_spacing_spinbox.value = spacing as i32;
@@ -3759,6 +3237,15 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
apply_grid_min_col_width(width);
propagate_links(state, "grid_min_col_width", &width.to_string());
}
+ InterfaceMessage::SetLayoutGridGap(gap) => {
+ let gap = gap.min(200);
+ state.layout_grid_gap = gap;
+ state.layout_grid_gap_spinbox.value = gap as i32;
+ state.windows.grid_gap = gap;
+ state.windows.grid_gap_spinbox.value = gap as i32;
+ apply_layout_grid_gap(gap);
+ propagate_links(state, "grid_gap", &gap.to_string());
+ }
InterfaceMessage::SetSpinboxHeight(height) => {
state.spinbox_height = height;
apply_spinbox_height(height);
@@ -3934,7 +3421,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
}
InterfaceMessage::PickLowColor | InterfaceMessage::PickHighColor | InterfaceMessage::PickDisabledColor | InterfaceMessage::PickVisualGuides | InterfaceMessage::PickSliderTrackColor | InterfaceMessage::PickPageLowColor | InterfaceMessage::PickColorBordersColor | InterfaceMessage::PickNormalColor | InterfaceMessage::PickPaginatorSidebarColor | InterfaceMessage::PickPrimaryHighlightColor | InterfaceMessage::PickMenubarTabLabelColor | InterfaceMessage::PickToggleEnabledColor | InterfaceMessage::PickToggleDisabledColor | InterfaceMessage::PickScrollingListBgColor | InterfaceMessage::PickScrollingListEntryBgColor | InterfaceMessage::PickScrollingListEntryHighlightColor | InterfaceMessage::PickBreadcrumbBgColor | InterfaceMessage::PickPopoverBgColor | InterfaceMessage::PickNotificationBgColor | InterfaceMessage::PickWindowColor | InterfaceMessage::PickPageColor | InterfaceMessage::PickLayerColor => {}
InterfaceMessage::Refreshed(new) => {
- let layout_status = state.layout_status.clone();
let was_bp_hovered = state.button_padding_spinbox.hovered();
let was_bss_hovered = state.button_strip_spacing_spinbox.hovered();
let was_sp_hovered = state.section_padding_spinbox.hovered();
@@ -4000,7 +3486,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
let terminal_size_box = state.terminal_size_box.clone();
*state = new;
- state.layout_status = layout_status;
state.button_padding_spinbox.set_hovered(was_bp_hovered);
state.button_strip_spacing_spinbox.set_hovered(was_bss_hovered);
@@ -4109,9 +3594,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.fuzzel_size_box = new.fuzzel_size_box;
state.terminal_size_box = new.terminal_size_box;
}
- InterfaceMessage::LayoutStatusRefreshed(s) => {
- state.layout_status = Some(s);
- }
+
InterfaceMessage::SetSans(sans) => {
state.sans_serif = sans.clone();
state.sans_box.text = sans;
@@ -4362,6 +3845,12 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
write_terminal_size(val as u16);
}
InterfaceMessage::Windows(sub_msg) => {
+ if let WindowsMessage::SetGridGap(v) = sub_msg {
+ let val = v.min(200);
+ state.layout_grid_gap = val;
+ state.layout_grid_gap_spinbox.value = val as i32;
+ cce_ui::layout::set_grid_gap(val as f32);
+ }
update_windows(&mut state.windows, sub_msg);
}
}
@@ -5326,6 +4815,34 @@ mod tests {
let _ = fs::remove_file(path_str);
}
+ #[test]
+ fn test_read_write_layout_grid_gap() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_layout_grid_gap_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "{\"layout\": {\"gap\": 18, \"border_color\": \"#374673\"}}";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse grid_gap when missing (should return default 8)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "grid_gap", 8);
+ assert_eq!(val, 8);
+
+ // 3. Write grid_gap config
+ assert!(write_config_value_path(path_str, "grid_gap", "12"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("\"grid_gap\": 12"));
+
+ // 4. Parse grid_gap when present (should return written value 12)
+ let val2 = parse_u16_from(&updated, "grid_gap", 8);
+ assert_eq!(val2, 12);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
#[test]
fn test_read_write_color_selector_preview_corner_radius() {
let dir = std::env::temp_dir();
@@ -6055,24 +5572,6 @@ mod tests {
assert!(!cce_ui::widget::context_menu::is_visible());
}
- #[test]
- fn test_read_write_separators() {
- let dir = std::env::temp_dir();
- let path = dir.join("test_status_separators.json");
- let path_str = path.to_str().unwrap().to_string();
-
- let _ = fs::write(&path_str, "{\"layout\": {\"status_separators\": true, \"status_padding\": 8}}");
- TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
-
- let original = read_status_separators().unwrap_or(true);
- write_status_separators(!original);
- assert_eq!(read_status_separators(), Some(!original));
- write_status_separators(original);
- assert_eq!(read_status_separators(), Some(original));
-
- let _ = fs::remove_file(path);
- }
-
#[test]
fn test_read_write_padding() {
let dir = std::env::temp_dir();
@@ -6091,24 +5590,6 @@ mod tests {
let _ = fs::remove_file(path);
}
- #[test]
- fn test_read_write_underline() {
- let dir = std::env::temp_dir();
- let path = dir.join("test_status_underline.json");
- let path_str = path.to_str().unwrap().to_string();
-
- let _ = fs::write(&path_str, "{\"layout\": {\"status_underline\": true, \"status_padding\": 8}}");
- TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
-
- let original = read_status_underline().unwrap_or(true);
- write_status_underline(!original);
- assert_eq!(read_status_underline(), Some(!original));
- write_status_underline(original);
- assert_eq!(read_status_underline(), Some(original));
-
- let _ = fs::remove_file(path);
- }
-
#[test]
fn test_read_write_status_box_opacity() {
let dir = std::env::temp_dir();
@@ -6203,6 +5684,8 @@ impl crate::pages::AppPage for InterfaceState {
self.desktop_line_width_spinbox.set_parent(None, ctx);
self.grid_min_col_width_spinbox.clear_children(ctx);
self.grid_min_col_width_spinbox.set_parent(None, ctx);
+ self.layout_grid_gap_spinbox.clear_children(ctx);
+ self.layout_grid_gap_spinbox.set_parent(None, ctx);
self.spinbox_height_spinbox.clear_children(ctx);
self.spinbox_height_spinbox.set_parent(None, ctx);
self.spinbox_corner_radius_spinbox.clear_children(ctx);
@@ -6265,10 +5748,8 @@ impl crate::pages::AppPage for InterfaceState {
self.status_box_corner_radius_spinbox.set_parent(None, ctx);
self.status_padding_spinbox.clear_children(ctx);
self.status_padding_spinbox.set_parent(None, ctx);
- self.status_controls.separators_toggle.clear_children(ctx);
- self.status_controls.separators_toggle.set_parent(None, ctx);
- self.status_controls.underline_toggle.clear_children(ctx);
- self.status_controls.underline_toggle.set_parent(None, ctx);
+ self.status_module_spacing_spinbox.clear_children(ctx);
+ self.status_module_spacing_spinbox.set_parent(None, ctx);
self.status_controls.box_opacity_slider.clear_children(ctx);
self.status_controls.box_opacity_slider.set_parent(None, ctx);
self.status_controls.box_blur_slider.clear_children(ctx);
@@ -6368,6 +5849,7 @@ impl crate::pages::AppPage for InterfaceState {
cce_ui::widget::link_parent_child(&mut sec_containers[1], &mut self.color_selectors[1], ctx);
cce_ui::widget::link_parent_child(&mut sec_containers[1], &mut self.color_selectors[2], ctx);
cce_ui::widget::link_parent_child(&mut sec_containers[1], &mut self.grid_min_col_width_spinbox, ctx);
+ cce_ui::widget::link_parent_child(&mut sec_containers[1], &mut self.layout_grid_gap_spinbox, ctx);
// Section 2: Status
cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.color_selectors[7], ctx);
@@ -6375,8 +5857,7 @@ impl crate::pages::AppPage for InterfaceState {
cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.color_selectors[22], ctx);
cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_box_corner_radius_spinbox, ctx);
cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_padding_spinbox, ctx);
- cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_controls.separators_toggle, ctx);
- cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_controls.underline_toggle, ctx);
+ cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_module_spacing_spinbox, ctx);
cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_controls.box_opacity_slider, ctx);
cce_ui::widget::link_parent_child(&mut sec_containers[2], &mut self.status_controls.box_blur_slider, ctx);
@@ -6514,12 +5995,6 @@ impl crate::pages::AppPage for InterfaceState {
if self.status_module_spacing_spinbox.take_change() {
actions.push(AppAction::Interface(InterfaceMessage::SetStatusModuleSpacing(self.status_module_spacing_spinbox.value as u16)));
}
- if self.status_controls.separators_toggle.take_change() {
- actions.push(AppAction::Interface(InterfaceMessage::StatusToggleSeparators));
- }
- if self.status_controls.underline_toggle.take_change() {
- actions.push(AppAction::Interface(InterfaceMessage::StatusToggleUnderline));
- }
if self.status_controls.box_opacity_slider.take_change() {
actions.push(AppAction::Interface(InterfaceMessage::StatusSetBoxOpacity(self.status_controls.box_opacity_slider.value())));
}
@@ -6566,6 +6041,9 @@ impl crate::pages::AppPage for InterfaceState {
if self.grid_min_col_width_spinbox.take_change() {
actions.push(AppAction::Interface(InterfaceMessage::SetGridMinColWidth(self.grid_min_col_width_spinbox.value as u16)));
}
+ if self.layout_grid_gap_spinbox.take_change() {
+ actions.push(AppAction::Interface(InterfaceMessage::SetLayoutGridGap(self.layout_grid_gap_spinbox.value as u16)));
+ }
if self.spinbox_height_spinbox.take_change() {
actions.push(AppAction::Interface(InterfaceMessage::SetSpinboxHeight(self.spinbox_height_spinbox.value as u16)));
}
diff --git a/src/pages/network.rs b/src/pages/network.rs
index 79ba600..cf61de6 100644
--- a/src/pages/network.rs
+++ b/src/pages/network.rs
@@ -290,7 +290,6 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
if !state.loaded {
sec.text("Loading WiFi interfaces...", margin, 0.0, 12.0, TEXT_DIM);
- sec.spacing(12.0 + row_gap);
} else {
let wifi_btn_w = if sec_w < 200.0 { 40.0 } else { 60.0 };
let wifi_btn_x = margin;
@@ -298,7 +297,6 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
state.wifi_toggle.set_toggled(state.wifi_enabled);
state.wifi_toggle.set_label(if state.wifi_enabled { "ON" } else { "OFF" });
sec.widget(&mut state.wifi_toggle, wifi_btn_x, wifi_btn_w, 28.0, ctx);
- sec.spacing(row_gap);
if state.wifi_enabled {
let status_y = sec.ay();
@@ -379,10 +377,8 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
if !state.loaded {
sec.text("Loading Bluetooth status...", margin, 0.0, font_size, TEXT_DIM);
- sec.spacing(font_size + row_gap);
} else if !state.bt_installed {
sec.text("Bluetooth tools (bluez) not installed", margin, 0.0, font_size, TEXT_DIM);
- sec.spacing(font_size + row_gap);
let btn_w = if bt_sec_w < 200.0 { 100.0 } else { 120.0 };
let yt = sec.ay();
sec.button("Install Tools", sec.ax(margin), yt, btn_w, btn_h,
@@ -391,7 +387,6 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
sec.content_y = yt + btn_h + row_gap;
} else if !state.bt_service_active {
sec.text("Bluetooth service is stopped", margin, 0.0, font_size, TEXT_DIM);
- sec.spacing(font_size + row_gap);
let btn_w = if bt_sec_w < 200.0 { 100.0 } else { 120.0 };
let yt = sec.ay();
sec.button("Start Service", sec.ax(margin), yt, btn_w, btn_h,
@@ -417,7 +412,6 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
if state.bt_enabled {
let no_devices_msg = if bt_sec_w < 200.0 { "No paired devices" } else { "No paired devices found" };
sec.text(no_devices_msg, margin, 0.0, font_size, TEXT_DIM);
- sec.spacing(font_size + row_gap);
}
} else {
let item_h = 22.0;
diff --git a/src/pages/packages.rs b/src/pages/packages.rs
index ee6e7f3..80cb259 100644
--- a/src/pages/packages.rs
+++ b/src/pages/packages.rs
@@ -335,7 +335,6 @@ pub fn view(
let sec_w = sec.cw;
if !state.loaded {
sec.text("Loading package lists...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else {
// Tab header: Installed, Updates
let tab_w = (sec_w - 24.0 - 8.0) / 2.0;
@@ -467,12 +466,10 @@ pub fn view(
}
sec.content_y += list_box_h;
- sec.spacing(16.0);
sec.add_section("Package Info", false, |subsec| {
if state.loading_info {
subsec.text("Loading package details...", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(18.0);
} else if let Some(ref pkg_name) = state.selected_package {
if let Some(ref info_raw) = state.selected_package_info {
let mut parsed = parse_package_info(info_raw);
@@ -481,7 +478,6 @@ pub fn view(
}
subsec.text(&parsed.name, 12.0, 0.0, 13.0, WHITE);
- subsec.spacing(20.0);
let render_detail = |sub: &mut SectionContext<'_, PageContent>, key: &str, val: &str| {
sub.text(key, 12.0, 0.0, 11.0, TEXT_DIM);
@@ -493,10 +489,8 @@ pub fn view(
let lines = wrap_text(val, max_chars);
for line in &lines {
sub.text(line, val_start_x, 0.0, 11.0, TEXT_FG);
- sub.spacing(14.0);
}
if lines.is_empty() {
- sub.spacing(14.0);
}
};
@@ -518,14 +512,11 @@ pub fn view(
}
if !parsed.description.is_empty() {
subsec.separator();
- subsec.spacing(4.0);
render_detail(subsec, "Description:", &parsed.description);
}
if !parsed.required_by.is_empty() && parsed.required_by != "None" {
subsec.separator();
- subsec.spacing(4.0);
subsec.text("Required By:", 12.0, 0.0, 11.0, TEXT_DIM);
- subsec.spacing(14.0);
let reqs: Vec<&str> = parsed.required_by.split_whitespace().collect();
let cols_count = 3;
@@ -541,17 +532,14 @@ pub fn view(
subsec.button(pkg, x, btn_y, w, btn_h, TOGGLE_OFF, BTN_HOVER, TEXT_FG, action);
}
}
- subsec.spacing(btn_h + 6.0);
}
}
if !parsed.commands.is_empty() {
subsec.separator();
- subsec.spacing(4.0);
render_detail(subsec, "Commands:", &parsed.commands);
}
if state.active_tab == PackageTab::Installed {
- subsec.spacing(12.0);
let btn_h = 32.0;
let btn_y = subsec.ay();
let (btn_lbl, bg, hover, action) = if state.uninstalling {
@@ -563,15 +551,12 @@ pub fn view(
if let Some(&(x, w)) = cols.first() {
subsec.button(btn_lbl, x, btn_y, w, btn_h, bg, hover, WHITE, action);
}
- subsec.spacing(12.0);
}
} else {
subsec.text("No details available.", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(18.0);
}
} else {
subsec.text("Select a package to view details.", 12.0, 0.0, 12.0, TEXT_DIM);
- subsec.spacing(18.0);
}
});
}
@@ -581,17 +566,14 @@ pub fn view(
builder.add_section(&mut final_pc, "System Update", sec_focused.get(1).copied().unwrap_or(false), |sec2| {
if !state.loaded {
sec2.text("Loading update status...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec2.spacing(18.0);
} else {
// Display summaries
sec2.text("Installed Packages:", 12.0, 0.0, 12.0, TEXT_DIM);
sec2.text(&format!("{}", state.installed.len()), 150.0, 0.0, 12.0, TEXT_FG);
- sec2.spacing(18.0);
sec2.text("Available Updates:", 12.0, 0.0, 12.0, TEXT_DIM);
let updates_color = if state.updates.is_empty() { TEXT_FG } else { ACCENT };
sec2.text(&format!("{}", state.updates.len()), 150.0, 0.0, 12.0, updates_color);
- sec2.spacing(18.0);
let status_lbl = if state.updating {
"Updating..."
@@ -602,19 +584,15 @@ pub fn view(
};
sec2.text("Status:", 12.0, 0.0, 12.0, TEXT_DIM);
sec2.text(status_lbl, 150.0, 0.0, 12.0, if state.updating { ACCENT } else { TEXT_FG });
- sec2.spacing(24.0);
if let Some(ref res) = state.last_update_res {
match res {
Ok(_) => {
sec2.text("Last update succeeded!", 12.0, 0.0, 12.0, ACCENT);
- sec2.spacing(18.0);
}
Err(err) => {
sec2.text("Last update failed:", 12.0, 0.0, 12.0, RED);
- sec2.spacing(8.0);
sec2.text(err, 12.0, 0.0, 11.0, RED);
- sec2.spacing(18.0);
}
}
}
@@ -632,7 +610,6 @@ pub fn view(
if let Some(&(x, w)) = cols.first() {
sec2.button(btn_lbl, x, btn_y, w, btn_h, bg, hover, WHITE, action);
}
- sec2.spacing(12.0);
}
});
diff --git a/src/pages/processes.rs b/src/pages/processes.rs
index d1fc539..a470866 100644
--- a/src/pages/processes.rs
+++ b/src/pages/processes.rs
@@ -115,7 +115,6 @@ pub fn view(state: &mut ProcessesState, cx: f32, cy: f32, cw: f32, ch: f32, root
let rx = sec.left;
if !state.loaded {
sec.text("Loading processes...", 12.0, 0.0, 12.0, TEXT_FG);
- sec.spacing(10.0);
} else {
// Scrolling box configuration for process list
let list_box_x = rx + 12.0;
@@ -176,7 +175,6 @@ pub fn view(state: &mut ProcessesState, cx: f32, cy: f32, cw: f32, ch: f32, root
let sec_w = sec.cw;
if !state.services_loaded {
sec.text("Loading systemd services...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else {
// Tab header buttons: System Services, User Services
let tab_w = (sec_w - 24.0 - 8.0) / 2.0;
diff --git a/src/pages/storage.rs b/src/pages/storage.rs
index ac248ab..9eae334 100644
--- a/src/pages/storage.rs
+++ b/src/pages/storage.rs
@@ -176,7 +176,6 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
let sec_w = sec.cw;
if !state.loaded {
sec.text("Loading storage usage...", 12.0, 0.0, 12.0, TEXT_FG);
- sec.spacing(18.0);
} else {
let disk_pct = if state.disk_total > 0.0 {
state.disk_used / state.disk_total * 100.0
@@ -189,7 +188,6 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
&format!("{:.0} / {:.0} GiB ({:.0}%)", state.disk_used, state.disk_total, disk_pct),
100.0, 0.0, 12.0, TEXT_FG,
);
- sec.spacing(18.0);
let bar_w = sec_w - 24.0;
let yt = sec.ay();
@@ -205,7 +203,6 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
let sec_w = sec.cw;
if !state.loaded {
sec.text("Loading memory usage...", 12.0, 0.0, 12.0, TEXT_FG);
- sec.spacing(18.0);
} else {
let ram_pct = if state.ram_total > 0.0 {
state.ram_used / state.ram_total * 100.0
@@ -218,7 +215,6 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
&format!("{:.1} / {:.1} GiB ({:.0}%)", state.ram_used, state.ram_total, ram_pct),
100.0, 0.0, 12.0, TEXT_FG,
);
- sec.spacing(18.0);
let bar_w = sec_w - 24.0;
let yt = sec.ay();
@@ -233,40 +229,33 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
builder.add_section(&mut final_pc, "Full System Backup", false, |sec| {
if !state.backup_loaded {
sec.text("Loading backup state...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
} else {
// Status Row
sec.text("Backup Status", 12.0, 0.0, 12.0, LABEL_FG);
let status_text = if state.backup_in_progress { "Backing up..." } else { "Idle" };
let status_color = if state.backup_in_progress { GREEN } else { TEXT_FG };
sec.text(status_text, 120.0, 0.0, 12.0, status_color);
- sec.spacing(18.0);
// Last Backup Row
sec.text("Last Backup", 12.0, 0.0, 12.0, LABEL_FG);
sec.text(&state.last_backup_time, 120.0, 0.0, 12.0, TEXT_FG);
- sec.spacing(18.0);
// Backup Size Row
sec.text("Archive Size", 12.0, 0.0, 12.0, LABEL_FG);
sec.text(&state.backup_size, 120.0, 0.0, 12.0, TEXT_FG);
- sec.spacing(18.0);
// Target Directories Row
sec.text("Backup Targets", 12.0, 0.0, 12.0, LABEL_FG);
sec.text("Entire Filesystem (/) [Preserving attributes]", 120.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
// Destination Archive Row
sec.text("Destination", 12.0, 0.0, 12.0, LABEL_FG);
sec.text("USB Drive (/mnt/usb or /run/media/...)", 120.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(24.0);
// Error message if present
if let Some(ref err) = state.error_message {
sec.text("Error:", 12.0, 0.0, 12.0, RED);
sec.text(err, 60.0, 0.0, 11.0, RED);
- sec.spacing(18.0);
}
// Action Button
@@ -283,7 +272,6 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
if let Some(&(x, w)) = cols.first() {
sec.button(btn_label, x, yt, w, btn_h, bg, hover, WHITE, action.clone());
}
- sec.spacing(12.0);
}
});
diff --git a/src/pages/system_info.rs b/src/pages/system_info.rs
index ba28692..5e3af39 100644
--- a/src/pages/system_info.rs
+++ b/src/pages/system_info.rs
@@ -25,17 +25,6 @@ pub struct NotificationsConfig {
pub duration: i32,
}
-#[derive(Debug, Clone)]
-pub struct StatusData {
- pub font_size: u16,
- pub padding: u16,
- pub separators: bool,
- pub underline: bool,
- pub running: bool,
- pub bg_opacity: f32,
- pub bg_blur: f32,
-}
-
#[derive(Debug, Clone)]
pub struct SystemState {
pub hostname: String,
@@ -465,10 +454,8 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
builder.add_section(&mut final_pc, "System", false, |sec| {
if !state.loaded {
sec.text("Loading system information...", 12.0, 0.0, 14.0, TEXT_FG);
- sec.spacing(10.0);
} else {
sec.text(&format!("{} — Linux {}", state.hostname, state.kernel), 12.0, 0.0, 14.0, TEXT_FG);
- sec.spacing(10.0);
sec.text(&format!("Uptime: {}", state.uptime), 12.0, 0.0, 12.0, TEXT_DIM);
}
});
@@ -500,26 +487,21 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
_ => {}
}
}
- sec.spacing(12.0);
});
// ── 3. CPU Section ──
builder.add_section(&mut final_pc, "CPU", false, |sec| {
if !state.loaded {
sec.text("Loading CPU model and utilization...", 12.0, 0.0, 12.0, TEXT_FG);
- sec.spacing(10.0);
} else {
// CPU Info Label
sec.widget(&mut state.cpu_label, 12.0, sec.cw - 24.0, 26.0, ctx);
- sec.spacing(12.0);
// CPU Usage Label
sec.widget(&mut state.cpu_usage_label, 12.0, sec.cw - 24.0, 26.0, ctx);
- sec.spacing(12.0);
// CPU Temp Label
sec.widget(&mut state.cpu_temp_label, 12.0, sec.cw - 24.0, 26.0, ctx);
- sec.spacing(12.0);
}
});
@@ -527,10 +509,8 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
builder.add_section(&mut final_pc, "GPU", false, |sec_gpu| {
if !state.loaded {
sec_gpu.text("Loading GPU models...", 12.0, 0.0, 12.0, TEXT_FG);
- sec_gpu.spacing(10.0);
} else {
- for (i, gpu_lbl) in state.gpu_labels.iter_mut().enumerate() {
- if i > 0 { sec_gpu.spacing(12.0); }
+ for gpu_lbl in state.gpu_labels.iter_mut() {
sec_gpu.widget(gpu_lbl, 12.0, sec_gpu.cw - 24.0, 26.0, ctx);
}
}
@@ -541,10 +521,8 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
let rx = sec_gov.left;
if !state.loaded {
sec_gov.text("Loading CPU governor...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec_gov.spacing(18.0);
} else {
sec_gov.widget(&mut state.cpu_gov_menu, 12.0, sec_gov.cw - 24.0, 26.0, ctx);
- sec_gov.spacing(12.0);
let (info_title, info_lines) = if state.cpu_powersave {
(
@@ -568,7 +546,6 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
let info_h = 80.0;
let info_y = sec_gov.ay();
render_widget(sec_gov.pc, &mut info_box, rx + 12.0, info_y, sec_gov.cw - 24.0, info_h, ctx);
- sec_gov.spacing(info_h + 12.0);
}
});
@@ -577,10 +554,8 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
let rx = sec_gpow.left;
if !state.loaded {
sec_gpow.text("Loading GPU power status...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec_gpow.spacing(18.0);
} else {
sec_gpow.widget(&mut state.gpu_gov_menu, 12.0, sec_gpow.cw - 24.0, 26.0, ctx);
- sec_gpow.spacing(12.0);
let (info_title, info_lines) = if state.gpu_powersave {
(
@@ -604,7 +579,6 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
let info_h = 80.0;
let info_y = sec_gpow.ay();
render_widget(sec_gpow.pc, &mut info_box, rx + 12.0, info_y, sec_gpow.cw - 24.0, info_h, ctx);
- sec_gpow.spacing(info_h + 12.0);
}
});
@@ -612,7 +586,6 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
builder.add_section(&mut final_pc, "Battery", false, |sec_bat| {
if !state.loaded {
sec_bat.text("Loading battery status...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec_bat.spacing(18.0);
} else {
let bat = &state.battery;
let bat_icon = match bat.state.as_str() {
@@ -627,12 +600,10 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
let pct_str = format!("{} {:.0}%", bat_icon, bat.percentage);
sec_bat.text(&pct_str, 12.0, 0.0, 24.0, pct_color);
- sec_bat.spacing(30.0);
let state_str = format!("{} • {:.1}W • {:.1}/{:.1} Wh",
bat.state, bat.energy_rate, bat.energy, bat.energy_full);
sec_bat.text(&state_str, 12.0, 0.0, 12.0, TEXT_DIM);
- sec_bat.spacing(18.0);
let time_str = if bat.time_to_empty > 0 {
format!("Time remaining: {}", format_duration(bat.time_to_empty))
@@ -641,16 +612,13 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
} else { String::new() };
if !time_str.is_empty() {
sec_bat.text(&time_str, 12.0, 0.0, 12.0, TEXT_DIM);
- sec_bat.spacing(18.0);
}
let detail_str = format!("{} {}", bat.vendor, bat.model);
sec_bat.text(&detail_str, 12.0, 0.0, 11.0, TEXT_DIM);
- sec_bat.spacing(20.0);
let ac_str = if state.on_ac { "On AC Power" } else { "On Battery" };
sec_bat.text(ac_str, 12.0, 0.0, 14.0, TEXT_FG);
- sec_bat.spacing(20.0);
}
});
@@ -659,16 +627,13 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
let sec_w = sec2.cw;
state.notifications_enable_toggle.set_toggled(state.notifications_enable);
sec2.widget_full(&mut state.notifications_enable_toggle, cce_ui::layout::toggle_height(), ctx);
- sec2.spacing(8.0);
state.notifications_bell_toggle.set_toggled(state.notifications_bell);
sec2.widget_full(&mut state.notifications_bell_toggle, cce_ui::layout::toggle_height(), ctx);
- sec2.spacing(16.0);
state.notifications_duration_spinbox.value = state.notifications_duration;
state.notifications_duration_spinbox.set_label("Notification Duration");
sec2.widget(&mut state.notifications_duration_spinbox, 14.0, sec_w - 28.0, 44.0, ctx);
- sec2.spacing(16.0);
let btn_h = 32.0;
let btn_y = sec2.ay();
@@ -690,7 +655,6 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
AppAction::SystemInfo(SystemMessage::SendTestNotification),
);
}
- sec2.spacing(12.0);
});
diff --git a/src/watchers.rs b/src/watchers.rs
index 80bba2f..3f02252 100644
--- a/src/watchers.rs
+++ b/src/watchers.rs
@@ -13,7 +13,6 @@ pub struct Watchers {
pub rx_fingers: Receiver<Vec<Finger>>,
pub rx_processes: Receiver<processes::ProcessesState>,
pub rx_system: Receiver<system_info::SystemState>,
- pub rx_status: Receiver<interface::StatusData>,
pub rx_storage: Receiver<storage::StorageState>,
pub rx_notifications: Receiver<system_info::NotificationsConfig>,
pub rx_typeface: Receiver<interface::InterfaceState>,
@@ -21,7 +20,6 @@ pub struct Watchers {
pub rx_interface: Receiver<interface::InterfaceState>,
pub rx_accounts: Receiver<Vec<accounts::AccountInfo>>,
pub rx_packages: Receiver<packages::PackagesState>,
- pub rx_layout_status: Receiver<interface::LayoutStatusInfo>,
}
fn spawn_bg_active<T, F>(
@@ -157,7 +155,6 @@ pub fn spawn_all(
let rx_system = spawn_bg_active(current_page_shared.clone(), Page::System.index() as u8, 5, || system_info::fetch_system_state());
let rx_processes = spawn_bg_active(current_page_shared.clone(), Page::Processes.index() as u8, 3, || processes::fetch_processes_state());
- let rx_status = spawn_bg_active(current_page_shared.clone(), Page::Interface.index() as u8, 10, || interface::fetch_status_state());
let rx_storage = spawn_bg_active(current_page_shared.clone(), Page::Storage.index() as u8, 10, || storage::fetch_storage_state());
let rx_notifications = {
@@ -216,32 +213,6 @@ pub fn spawn_all(
rx
};
- let rx_layout_status = {
- let (tx, rx) = channel::<interface::LayoutStatusInfo>();
- let current_page_shared = current_page_shared.clone();
- tokio::spawn(async move {
- let mut last_fetch: Option<std::time::Instant> = None;
- loop {
- let current_page = current_page_shared.load(Ordering::SeqCst);
- if current_page == Page::Interface.index() as u8 {
- let should_fetch = match last_fetch {
- None => true,
- Some(t) => t.elapsed() >= std::time::Duration::from_millis(250),
- };
- if should_fetch {
- let val = tokio::task::spawn_blocking(|| interface::read_current_layout_status()).await;
- if let Ok(val) = val {
- if tx.send(val).is_err() { break; }
- }
- last_fetch = Some(std::time::Instant::now());
- }
- }
- tokio::time::sleep(std::time::Duration::from_millis(50)).await;
- }
- });
- rx
- };
-
let (tx_backup, rx_backup) = channel();
let rx_packages = spawn_bg_active(current_page_shared.clone(), Page::Packages.index() as u8, 30, || packages::fetch_packages_state());
let (tx_update, rx_update) = channel();
@@ -256,7 +227,6 @@ pub fn spawn_all(
rx_fingers,
rx_processes,
rx_system,
- rx_status,
rx_storage,
rx_notifications,
rx_typeface,
@@ -264,7 +234,6 @@ pub fn spawn_all(
rx_interface,
rx_accounts,
rx_packages,
- rx_layout_status,
},
tx_backup,
rx_backup,