system settings
git clone https://git.lucas.co/cce-system-interface.git
Refactor and adapt widgets to use UiContext and scale factor
Cargo.lock | 26 +-
Cargo.toml | 6 +-
Makefile | 2 +-
src/app.rs | 15 +-
src/main.rs | 2659 +++++++++++++++++++++++++++++++---------------
src/pages/accounts.rs | 26 +-
src/pages/audio.rs | 110 +-
src/pages/display.rs | 66 +-
src/pages/hardware.rs | 60 +-
src/pages/input.rs | 71 +-
src/pages/interface.rs | 1960 +++++++++++++++++++++++++---------
src/pages/layout.rs | 53 +-
src/pages/mod.rs | 11 +-
src/pages/network.rs | 6 +-
src/pages/packages.rs | 754 +++++++++++++
src/pages/services.rs | 124 +--
src/pages/storage.rs | 17 +-
src/pages/system_info.rs | 2 +-
18 files changed, 4303 insertions(+), 1665 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 66b1a38..8bdab3e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -311,19 +311,7 @@ dependencies = [
]
[[package]]
-name = "cfg-if"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
-
-[[package]]
-name = "cfg_aliases"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
-
-[[package]]
-name = "clear-system-interface"
+name = "cce-system-interface"
version = "0.1.0"
dependencies = [
"bytemuck",
@@ -345,6 +333,18 @@ dependencies = [
"zbus",
]
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
[[package]]
name = "clear-ui"
version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index 751958e..60599a2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "clear-system-interface"
+name = "cce-system-interface"
version = "0.1.0"
edition = "2021"
@@ -23,9 +23,9 @@ serde_json = "1"
reqwest = { version = "0.12", features = ["json"] }
[lib]
-name = "clear_system_interface"
+name = "cce_system_interface"
path = "src/lib.rs"
[[bin]]
path = "src/main.rs"
-name = "clear-system-interface"
+name = "cce-system-interface"
diff --git a/Makefile b/Makefile
index 4a2f426..d0c6cab 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ build:
install: build
mkdir -p ~/.local/bin
- install -m 755 target/release/clear-system-interface ~/.local/bin/clear-system-interface
+ install -m 755 target/release/cce-system-interface ~/.local/bin/cce-system-interface
run:
cargo run
diff --git a/src/app.rs b/src/app.rs
index 08ba843..c14bfa3 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -11,6 +11,7 @@ use crate::pages::storage;
use crate::pages::services;
use crate::pages::interface;
use crate::pages::accounts;
+use crate::pages::packages;
use crate::pages::Page;
pub struct AppState {
@@ -26,6 +27,7 @@ pub struct AppState {
pub services: services::ServicesState,
pub interface: interface::InterfaceState,
pub accounts: accounts::AccountsState,
+ pub packages: packages::PackagesState,
}
impl Default for AppState {
@@ -43,6 +45,7 @@ impl Default for AppState {
services: services::ServicesState::default(),
interface: interface::InterfaceState::default(),
accounts: accounts::AccountsState::default_mock(),
+ packages: packages::PackagesState::default(),
}
}
}
@@ -60,6 +63,7 @@ pub enum AppAction {
Services(services::ServicesMessage),
Interface(interface::InterfaceMessage),
Accounts(accounts::AccountsMessage),
+ Packages(packages::PackagesMessage),
}
@@ -161,17 +165,6 @@ impl<'a> SectionContextExt for clear_ui::layout::SectionContext<'a, PageContent>
}
}
-impl<'a> SectionContextExt for clear_ui::layout::SubsectionContext<'a, PageContent> {
- fn button(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32, bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4], action: AppAction) {
- self.pc.button(label, x, y, w, h, bg, hover_bg, label_color, action);
- self.content_y = self.content_y.max(y + h);
- }
-
- fn button_left(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32, bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4], action: AppAction) {
- self.pc.button_left(label, x, y, w, h, bg, hover_bg, label_color, action);
- self.content_y = self.content_y.max(y + h);
- }
-}
diff --git a/src/main.rs b/src/main.rs
index e80e393..c0b0c8c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,13 @@
use clear_ui::widget::{Finger, hover_animation, TextItem, Element};
use glyphon::{Attrs, Buffer, FontSystem, Metrics};
-use clear_system_interface::app::{AppAction, AppState, ContentButton, PageContent};
-use clear_system_interface::pages::{self, Page};
+use cce_system_interface::app::{AppAction, AppState, ContentButton, PageContent};
+use cce_system_interface::pages::{self, Page};
fn make_text_buffer(fs: &mut FontSystem, text: &str, size: f32) -> Buffer {
- let metrics = Metrics::new(size, size * 1.4);
+ let scale = clear_ui::scale::scale_factor();
+ let physical_size = size * scale;
+ let metrics = Metrics::new(physical_size, physical_size * 1.4);
let mut buf = Buffer::new(fs, metrics);
buf.set_text(fs, text, Attrs::new(), glyphon::Shaping::Advanced);
buf.shape_until_scroll(fs, true);
@@ -33,16 +35,31 @@ fn make_text_buffer_with_font(
serif_fallback: &str,
mono_fallback: &str,
) -> Buffer {
- let metrics = Metrics::new(size, size * 1.4);
+ let scale = clear_ui::scale::scale_factor();
+ let mut font_size = size;
+ let mut family_name = None;
+
+ if let Some(font_str) = font {
+ let (parsed_family, parsed_size) = clear_ui::layout::parse_font_string(font_str);
+ if let Some(ps) = parsed_size {
+ font_size = ps;
+ }
+ family_name = Some(parsed_family);
+ }
+
+ let physical_size = font_size * scale;
+ let metrics = Metrics::new(physical_size, physical_size * 1.4);
let mut buf = Buffer::new(fs, metrics);
let mut attrs = Attrs::new();
- let resolved_storage = font.and_then(|font_name| match font_name {
+
+ let resolved_storage = family_name.as_deref().and_then(|font_name| match font_name {
"monospace" if !mono_fallback.is_empty() => find_cased_family(fs, mono_fallback),
"sans-serif" if !sans_fallback.is_empty() => find_cased_family(fs, sans_fallback),
"serif" if !serif_fallback.is_empty() => find_cased_family(fs, serif_fallback),
_ => None,
});
- if let Some(font_name) = font {
+
+ if let Some(font_name) = family_name.as_deref() {
let family = match font_name {
"monospace" => {
if !mono_fallback.is_empty() {
@@ -81,6 +98,7 @@ fn make_text_buffer_with_font(
};
attrs = attrs.family(family);
}
+
buf.set_text(fs, text, attrs, glyphon::Shaping::Advanced);
buf.shape_until_scroll(fs, true);
buf
@@ -127,6 +145,9 @@ struct SystemInterface {
rx_accounts: std::sync::mpsc::Receiver<Vec<pages::accounts::AccountInfo>>,
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>,
+ tx_update: std::sync::mpsc::Sender<pages::packages::PackagesMessage>,
+ rx_update: std::sync::mpsc::Receiver<pages::packages::PackagesMessage>,
scale_factor: f64,
@@ -136,13 +157,19 @@ struct SystemInterface {
scroll_y: f32,
max_scroll_y: f32,
opacity_dragging: bool,
+ graph_opacity_dragging: bool,
+ audio_sink_dragging: Option<usize>,
+ audio_source_dragging: Option<usize>,
+ display_brightness_dragging: bool,
page_root_container: clear_ui::widget::Container,
page_sec_containers: Vec<clear_ui::widget::Container>,
paginator: clear_ui::widget::Paginator,
sans_serif_family: String,
serif_family: String,
monospace_family: String,
+ current_page_shared: std::sync::Arc<std::sync::atomic::AtomicU8>,
sender: calloop::channel::Sender<AppAction>,
+ ui_context: clear_ui::context::UiContext,
}
impl clear_ui::engine::Application for SystemInterface {
@@ -157,43 +184,77 @@ impl clear_ui::engine::Application for SystemInterface {
};
// ── Background refresh channels ──
- fn spawn_bg<T, F>(period_secs: u64, f: fn() -> F) -> std::sync::mpsc::Receiver<T>
+ let initial_page_idx = INITIAL_PAGE_INDEX.load(std::sync::atomic::Ordering::SeqCst);
+ let current_page_shared = std::sync::Arc::new(std::sync::atomic::AtomicU8::new(initial_page_idx as u8));
+
+ fn spawn_bg_active<T, F>(
+ current_page_shared: std::sync::Arc<std::sync::atomic::AtomicU8>,
+ target_page_idx: u8,
+ period_secs: u64,
+ f: fn() -> F,
+ ) -> std::sync::mpsc::Receiver<T>
where
T: Send + 'static,
F: std::future::Future<Output = T> + Send + 'static,
{
let (tx, rx) = std::sync::mpsc::channel::<T>();
tokio::spawn(async move {
+ let mut last_fetch: Option<std::time::Instant> = None;
loop {
- let val = f().await;
- if tx.send(val).is_err() { break; }
- tokio::time::sleep(std::time::Duration::from_secs(period_secs)).await;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == target_page_idx {
+ let should_fetch = match last_fetch {
+ None => true,
+ Some(t) => t.elapsed() >= std::time::Duration::from_secs(period_secs),
+ };
+ if should_fetch {
+ let val = f().await;
+ if tx.send(val).is_err() { break; }
+ last_fetch = Some(std::time::Instant::now());
+ }
+ }
+ tokio::time::sleep(std::time::Duration::from_millis(250)).await;
}
});
rx
}
- let rx_audio = spawn_bg(3, || pages::audio::fetch_audio_state());
- let rx_display = spawn_bg(10, || pages::display::fetch_display_state());
- let rx_network = spawn_bg(5, || pages::network::fetch_network_state());
+ let rx_audio = spawn_bg_active(current_page_shared.clone(), 1, 3, || pages::audio::fetch_audio_state());
+ let rx_display = spawn_bg_active(current_page_shared.clone(), 2, 10, || pages::display::fetch_display_state());
+ let rx_network = spawn_bg_active(current_page_shared.clone(), 8, 5, || pages::network::fetch_network_state());
let rx_layout = {
let (tx, rx) = std::sync::mpsc::channel::<pages::layout::LayoutState>();
+ let current_page_shared = current_page_shared.clone();
tokio::spawn(async move {
+ let mut last_fetch: Option<std::time::Instant> = None;
loop {
- let val = tokio::task::spawn_blocking(|| pages::layout::read_layout_config()).await;
- if let Ok(val) = val { if tx.send(val).is_err() { break; } }
- tokio::time::sleep(std::time::Duration::from_secs(30)).await;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == 6 { // Layout is index 6
+ let should_fetch = match last_fetch {
+ None => true,
+ Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
+ };
+ if should_fetch {
+ let val = tokio::task::spawn_blocking(|| pages::layout::read_layout_config()).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(250)).await;
}
});
rx
};
let rx_wm_events = {
let (tx, rx) = std::sync::mpsc::channel::<()>();
+ let current_page_shared = current_page_shared.clone();
tokio::spawn(async move {
let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".to_string());
- let windows_path = format!("/tmp/ccec-windows-{}", display);
- let tags_path = format!("/tmp/ccec-tags-{}", display);
- let title_path = format!("/tmp/ccec-title-{}", display);
+ let windows_path = format!("/tmp/cce-client-windows-{}", display);
+ let tags_path = format!("/tmp/cce-client-tags-{}", display);
+ let title_path = format!("/tmp/cce-client-title-{}", display);
let mut last_mod = std::time::SystemTime::UNIX_EPOCH;
@@ -202,17 +263,20 @@ impl clear_ui::engine::Application for SystemInterface {
};
loop {
- let mut changed = false;
- for p in &[&windows_path, &tags_path, &title_path] {
- if let Some(mtime) = check_mtime(p) {
- if mtime > last_mod {
- last_mod = mtime;
- changed = true;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == 6 { // Layout is index 6
+ let mut changed = false;
+ for p in &[&windows_path, &tags_path, &title_path] {
+ if let Some(mtime) = check_mtime(p) {
+ if mtime > last_mod {
+ last_mod = mtime;
+ changed = true;
+ }
}
}
- }
- if changed {
- if tx.send(()).is_err() { break; }
+ if changed {
+ if tx.send(()).is_err() { break; }
+ }
}
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
}
@@ -221,31 +285,52 @@ impl clear_ui::engine::Application for SystemInterface {
};
let rx_input = {
let (tx, rx) = std::sync::mpsc::channel::<pages::input::InputState>();
+ let current_page_shared = current_page_shared.clone();
tokio::spawn(async move {
+ let mut last_fetch: Option<std::time::Instant> = None;
loop {
- let val = tokio::task::spawn_blocking(|| pages::input::read_input_config()).await;
- if let Ok(val) = val { if tx.send(val).is_err() { break; } }
- tokio::time::sleep(std::time::Duration::from_secs(30)).await;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == 4 { // Input is index 4
+ let should_fetch = match last_fetch {
+ None => true,
+ Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
+ };
+ if should_fetch {
+ let val = tokio::task::spawn_blocking(|| pages::input::read_input_config()).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(250)).await;
}
});
rx
};
let rx_fingers = {
let (tx, rx) = std::sync::mpsc::channel::<Vec<Finger>>();
+ let current_page_shared = current_page_shared.clone();
tokio::spawn(async move {
let socket_path = match std::env::var("WAYLAND_DISPLAY") {
Ok(display) => format!("/tmp/clear-input-coords-{}.sock", display),
Err(_) => "/tmp/clear-input-coords.sock".to_string(),
};
loop {
- if let Ok(stream) = tokio::net::UnixStream::connect(&socket_path).await {
- use tokio::io::AsyncBufReadExt;
- let reader = tokio::io::BufReader::new(stream);
- let mut lines = reader.lines();
- while let Ok(Some(line)) = lines.next_line().await {
- if let Ok(fingers) = serde_json::from_str::<Vec<Finger>>(&line) {
- if tx.send(fingers).is_err() {
- return;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == 4 { // Input is index 4
+ if let Ok(stream) = tokio::net::UnixStream::connect(&socket_path).await {
+ use tokio::io::AsyncBufReadExt;
+ let reader = tokio::io::BufReader::new(stream);
+ let mut lines = reader.lines();
+ while let Ok(Some(line)) = lines.next_line().await {
+ if current_page_shared.load(std::sync::atomic::Ordering::SeqCst) != 4 {
+ break;
+ }
+ if let Ok(fingers) = serde_json::from_str::<Vec<Finger>>(&line) {
+ if tx.send(fingers).is_err() {
+ return;
+ }
}
}
}
@@ -255,36 +340,66 @@ impl clear_ui::engine::Application for SystemInterface {
});
rx
};
- let rx_system = spawn_bg(5, || pages::system_info::fetch_system_state());
- let rx_hardware = spawn_bg(3, || pages::hardware::fetch_hardware_state());
- let rx_status = spawn_bg(10, || pages::services::fetch_status_state());
- let rx_storage = spawn_bg(10, || pages::storage::fetch_storage_state());
+ let rx_system = spawn_bg_active(current_page_shared.clone(), 11, 5, || pages::system_info::fetch_system_state());
+ let rx_hardware = spawn_bg_active(current_page_shared.clone(), 3, 3, || pages::hardware::fetch_hardware_state());
+ let rx_status = spawn_bg_active(current_page_shared.clone(), 9, 10, || pages::services::fetch_status_state());
+ let rx_storage = spawn_bg_active(current_page_shared.clone(), 10, 10, || pages::storage::fetch_storage_state());
let rx_notifications = {
let (tx, rx) = std::sync::mpsc::channel::<pages::services::NotificationsConfig>();
+ let current_page_shared = current_page_shared.clone();
tokio::spawn(async move {
+ let mut last_fetch: Option<std::time::Instant> = None;
loop {
- let val = tokio::task::spawn_blocking(|| pages::services::read_notifications_config()).await;
- if let Ok(val) = val { if tx.send(val).is_err() { break; } }
- tokio::time::sleep(std::time::Duration::from_secs(30)).await;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == 9 { // Services is index 9
+ let should_fetch = match last_fetch {
+ None => true,
+ Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
+ };
+ if should_fetch {
+ let val = tokio::task::spawn_blocking(|| pages::services::read_notifications_config()).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(250)).await;
}
});
rx
};
- let rx_typeface = spawn_bg(30, || pages::interface::fetch_typeface_state());
- let rx_services = spawn_bg(3, || pages::services::fetch_services());
- let rx_accounts = spawn_bg(3, || pages::accounts::fetch_accounts());
+ let rx_typeface = spawn_bg_active(current_page_shared.clone(), 5, 30, || pages::interface::fetch_typeface_state());
+ let rx_services = spawn_bg_active(current_page_shared.clone(), 9, 3, || pages::services::fetch_services());
+ let rx_accounts = spawn_bg_active(current_page_shared.clone(), 0, 3, || pages::accounts::fetch_accounts());
let rx_interface = {
let (tx, rx) = std::sync::mpsc::channel::<pages::interface::InterfaceState>();
+ let current_page_shared = current_page_shared.clone();
tokio::spawn(async move {
+ let mut last_fetch: Option<std::time::Instant> = None;
loop {
- let val = tokio::task::spawn_blocking(|| pages::interface::read_interface_config()).await;
- if let Ok(val) = val { if tx.send(val).is_err() { break; } }
- tokio::time::sleep(std::time::Duration::from_secs(30)).await;
+ let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
+ if current_page == 5 { // Interface is index 5
+ let should_fetch = match last_fetch {
+ None => true,
+ Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
+ };
+ if should_fetch {
+ let val = tokio::task::spawn_blocking(|| pages::interface::read_interface_config()).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(250)).await;
}
});
rx
};
let (tx_backup, rx_backup) = std::sync::mpsc::channel();
+ let rx_packages = spawn_bg_active(current_page_shared.clone(), 7, 30, || pages::packages::fetch_packages_state());
+ let (tx_update, rx_update) = std::sync::mpsc::channel();
let (sans_family, serif_family, monospace_family, _, _, _, _, _) = pages::interface::read_preferred_fonts();
@@ -293,7 +408,6 @@ impl clear_ui::engine::Application for SystemInterface {
.with_tabs_rotated(true)
.with_sidebar_label("SYSTEM");
- let initial_page_idx = INITIAL_PAGE_INDEX.load(std::sync::atomic::Ordering::SeqCst);
let mut app_state = app;
app_state.current_page = Page::ALL[initial_page_idx];
@@ -328,6 +442,9 @@ impl clear_ui::engine::Application for SystemInterface {
rx_accounts,
tx_backup,
rx_backup,
+ rx_packages,
+ tx_update,
+ rx_update,
scale_factor: 1.0,
width: 820,
@@ -336,13 +453,19 @@ impl clear_ui::engine::Application for SystemInterface {
scroll_y: 0.0,
max_scroll_y: 0.0,
opacity_dragging: false,
+ graph_opacity_dragging: false,
+ audio_sink_dragging: None,
+ audio_source_dragging: None,
+ display_brightness_dragging: false,
page_root_container: clear_ui::widget::Container::new(),
page_sec_containers: Vec::new(),
paginator,
sans_serif_family: sans_family,
serif_family,
monospace_family,
+ current_page_shared,
sender,
+ ui_context: clear_ui::context::UiContext::new(),
};
this.rebuild_layout(820.0, 680.0);
this
@@ -350,12 +473,12 @@ impl clear_ui::engine::Application for SystemInterface {
fn settings(&self) -> clear_ui::engine::WindowSettings {
clear_ui::engine::WindowSettings {
- title: "Clear System Interface".to_string(),
- app_id: "clear-system-interface".to_string(),
+ title: "CCE System Interface".to_string(),
+ app_id: "cce-system-interface".to_string(),
width: 820,
height: 680,
fullscreen: false,
- min_size: Some((820, 680)),
+ min_size: Some((400, 680)),
}
}
@@ -438,14 +561,14 @@ impl clear_ui::engine::Application for SystemInterface {
impl SystemInterface {
-fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(f32, f32, f32, f32)>) {
+fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(f32, f32, f32, f32)>, ctx: &clear_ui::context::UiContext) {
if let Some(rect) = w.popover_rect() {
popovers.push(rect);
}
- for child_ptr in w.children() {
+ for child_ptr in w.children(ctx) {
unsafe {
if let Some(child) = child_ptr.as_ref() {
- Self::collect_popover_rects(child, popovers);
+ Self::collect_popover_rects(child, popovers, ctx);
}
}
}
@@ -472,7 +595,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
self.paginator.set_selected_page(page_idx);
let mut paginator_pc = PageContent::new();
- clear_ui::layout::render_widget(&mut paginator_pc, &mut self.paginator, 0.0, 0.0, sw / s, sh / s);
+ clear_ui::layout::render_widget(&mut paginator_pc, &mut self.paginator, 0.0, 0.0, sw / s, sh / s, &mut self.ui_context);
for (c, x, y, w, h) in &paginator_pc.rects {
widgets.push(AppWidget {
@@ -502,299 +625,411 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
// Page content in LOGICAL coordinates, then scale to physical
let mut pc = self.render_page_content(lcx, lcy, lcw, lch);
- clear_ui::layout::render_popovers(&mut pc);
// ── Rebuild Element Focus Hierarchy ──
- self.page_root_container.clear_children();
- self.page_root_container.set_parent(None);
+ self.page_root_container.clear_children(&mut self.ui_context);
+ self.page_root_container.set_parent(None, &mut self.ui_context);
self.page_sec_containers.clear();
// Clear all widgets' hierarchy links
- self.app.services.search_box.clear_children(); self.app.services.search_box.set_parent(None);
- self.app.accounts.email_box.clear_children(); self.app.accounts.email_box.set_parent(None);
- self.app.accounts.password_box.clear_children(); self.app.accounts.password_box.set_parent(None);
- self.app.accounts.imap_box.clear_children(); self.app.accounts.imap_box.set_parent(None);
- self.app.accounts.smtp_box.clear_children(); self.app.accounts.smtp_box.set_parent(None);
- self.app.accounts.oauth_client_id_box.clear_children(); self.app.accounts.oauth_client_id_box.set_parent(None);
- self.app.accounts.oauth_client_secret_box.clear_children(); self.app.accounts.oauth_client_secret_box.set_parent(None);
+ self.app.services.search_box.clear_children(&mut self.ui_context); self.app.services.search_box.set_parent(None, &mut self.ui_context);
+ self.app.packages.search_box.clear_children(&mut self.ui_context); self.app.packages.search_box.set_parent(None, &mut self.ui_context);
+ self.app.packages.installed_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.packages.installed_list_box.scroll_box.set_parent(None, &mut self.ui_context);
+ self.app.packages.updates_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.packages.updates_list_box.scroll_box.set_parent(None, &mut self.ui_context);
+ self.app.accounts.email_box.clear_children(&mut self.ui_context); self.app.accounts.email_box.set_parent(None, &mut self.ui_context);
+ self.app.accounts.password_box.clear_children(&mut self.ui_context); self.app.accounts.password_box.set_parent(None, &mut self.ui_context);
+ self.app.accounts.imap_box.clear_children(&mut self.ui_context); self.app.accounts.imap_box.set_parent(None, &mut self.ui_context);
+ self.app.accounts.smtp_box.clear_children(&mut self.ui_context); self.app.accounts.smtp_box.set_parent(None, &mut self.ui_context);
+ self.app.accounts.oauth_client_id_box.clear_children(&mut self.ui_context); self.app.accounts.oauth_client_id_box.set_parent(None, &mut self.ui_context);
+ self.app.accounts.oauth_client_secret_box.clear_children(&mut self.ui_context); self.app.accounts.oauth_client_secret_box.set_parent(None, &mut self.ui_context);
- self.app.services.list_box.scroll_box.clear_children(); self.app.services.list_box.scroll_box.set_parent(None);
+ self.app.services.list_box.scroll_box.clear_children(&mut self.ui_context); self.app.services.list_box.scroll_box.set_parent(None, &mut self.ui_context);
- self.app.hardware.cpu_list_box.scroll_box.clear_children(); self.app.hardware.cpu_list_box.scroll_box.set_parent(None);
+ self.app.hardware.cpu_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.hardware.cpu_list_box.scroll_box.set_parent(None, &mut self.ui_context);
- self.app.network.wifi_list_box.scroll_box.clear_children(); self.app.network.wifi_list_box.scroll_box.set_parent(None);
+ self.app.network.wifi_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.network.wifi_list_box.scroll_box.set_parent(None, &mut self.ui_context);
for sb in &mut self.app.layout.spinboxes {
- sb.clear_children();
- sb.set_parent(None);
+ sb.clear_children(&mut self.ui_context);
+ sb.set_parent(None, &mut self.ui_context);
}
- self.app.layout.cascade_offset_spinbox.clear_children(); self.app.layout.cascade_offset_spinbox.set_parent(None);
- self.app.layout.edge_gap_spinbox.clear_children(); self.app.layout.edge_gap_spinbox.set_parent(None);
- self.app.layout.top_gap_spinbox.clear_children(); self.app.layout.top_gap_spinbox.set_parent(None);
- self.app.layout.grid_gap_spinbox.clear_children(); self.app.layout.grid_gap_spinbox.set_parent(None);
- self.app.layout.transition_duration_spinbox.clear_children(); self.app.layout.transition_duration_spinbox.set_parent(None);
- self.app.layout.status_height_spinbox.clear_children(); self.app.layout.status_height_spinbox.set_parent(None);
+ self.app.layout.cascade_offset_spinbox.clear_children(&mut self.ui_context); self.app.layout.cascade_offset_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.layout.edge_gap_spinbox.clear_children(&mut self.ui_context); self.app.layout.edge_gap_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.layout.top_gap_spinbox.clear_children(&mut self.ui_context); self.app.layout.top_gap_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.layout.grid_gap_spinbox.clear_children(&mut self.ui_context); self.app.layout.grid_gap_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.layout.transition_duration_spinbox.clear_children(&mut self.ui_context); self.app.layout.transition_duration_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.layout.status_height_spinbox.clear_children(&mut self.ui_context); self.app.layout.status_height_spinbox.set_parent(None, &mut self.ui_context);
for cs in &mut self.app.interface.color_selectors {
- cs.clear_children();
- cs.set_parent(None);
- }
- self.app.interface.tab_margin_spinbox_x.clear_children();
- self.app.interface.tab_margin_spinbox_x.set_parent(None);
- self.app.interface.tab_margin_spinbox_y.clear_children();
- self.app.interface.tab_margin_spinbox_y.set_parent(None);
- self.app.interface.tab_padding_spinbox_x.clear_children();
- self.app.interface.tab_padding_spinbox_x.set_parent(None);
- self.app.interface.tab_padding_spinbox_y.clear_children();
- self.app.interface.tab_padding_spinbox_y.set_parent(None);
-
- self.app.interface.sans_box.clear_children(); self.app.interface.sans_box.set_parent(None);
- self.app.interface.serif_box.clear_children(); self.app.interface.serif_box.set_parent(None);
- self.app.interface.mono_box.clear_children(); self.app.interface.mono_box.set_parent(None);
- self.app.interface.borders_menu.clear_children(); self.app.interface.borders_menu.set_parent(None);
- self.app.interface.borders_box.clear_children(); self.app.interface.borders_box.set_parent(None);
- self.app.interface.status_menu.clear_children(); self.app.interface.status_menu.set_parent(None);
- self.app.interface.status_box.clear_children(); self.app.interface.status_box.set_parent(None);
- self.app.interface.fuzzel_menu.clear_children(); self.app.interface.fuzzel_menu.set_parent(None);
- self.app.interface.fuzzel_box.clear_children(); self.app.interface.fuzzel_box.set_parent(None);
- self.app.interface.terminal_menu.clear_children(); self.app.interface.terminal_menu.set_parent(None);
- self.app.interface.terminal_box.clear_children(); self.app.interface.terminal_box.set_parent(None);
- self.app.interface.paginator_menu.clear_children(); self.app.interface.paginator_menu.set_parent(None);
- self.app.interface.paginator_box.clear_children(); self.app.interface.paginator_box.set_parent(None);
- self.app.interface.search_box.clear_children(); self.app.interface.search_box.set_parent(None);
- self.app.interface.list_box.scroll_box.clear_children(); self.app.interface.list_box.scroll_box.set_parent(None);
-
- self.app.services.notifications_enable_toggle.clear_children(); self.app.services.notifications_enable_toggle.set_parent(None);
- self.app.services.notifications_bell_toggle.clear_children(); self.app.services.notifications_bell_toggle.set_parent(None);
- self.app.services.notifications_duration_spinbox.clear_children(); self.app.services.notifications_duration_spinbox.set_parent(None);
- self.app.services.notifications_opacity_slider.clear_children(); self.app.services.notifications_opacity_slider.set_parent(None);
-
- self.app.input.rate_spinbox.clear_children(); self.app.input.rate_spinbox.set_parent(None);
- self.app.input.delay_spinbox.clear_children(); self.app.input.delay_spinbox.set_parent(None);
- self.app.input.scroll_toggle.clear_children(); self.app.input.scroll_toggle.set_parent(None);
- self.app.input.scroll_friction_spinbox.clear_children(); self.app.input.scroll_friction_spinbox.set_parent(None);
- self.app.input.natural_toggle.clear_children(); self.app.input.natural_toggle.set_parent(None);
- self.app.input.scroll_speed_spinbox.clear_children(); self.app.input.scroll_speed_spinbox.set_parent(None);
- self.app.input.pointer_toggle.clear_children(); self.app.input.pointer_toggle.set_parent(None);
- self.app.input.pointer_friction_spinbox.clear_children(); self.app.input.pointer_friction_spinbox.set_parent(None);
- self.app.input.trackpad_toggle.clear_children(); self.app.input.trackpad_toggle.set_parent(None);
- self.app.input.trackpad_friction_spinbox.clear_children(); self.app.input.trackpad_friction_spinbox.set_parent(None);
- self.app.input.dwtp_toggle.clear_children(); self.app.input.dwtp_toggle.set_parent(None);
- self.app.input.trackpoint_accel_speed_spinbox.clear_children(); self.app.input.trackpoint_accel_speed_spinbox.set_parent(None);
- self.app.input.trackpoint_accel_profile_menu.clear_children(); self.app.input.trackpoint_accel_profile_menu.set_parent(None);
- self.app.input.cursor_theme_menu.clear_children(); self.app.input.cursor_theme_menu.set_parent(None);
- self.app.input.cursor_size_spinbox.clear_children(); self.app.input.cursor_size_spinbox.set_parent(None);
+ cs.clear_children(&mut self.ui_context);
+ cs.set_parent(None, &mut self.ui_context);
+ }
+ self.app.interface.tab_margin_spinbox_x.clear_children(&mut self.ui_context);
+ self.app.interface.tab_margin_spinbox_x.set_parent(None, &mut self.ui_context);
+ self.app.interface.tab_margin_spinbox_y.clear_children(&mut self.ui_context);
+ self.app.interface.tab_margin_spinbox_y.set_parent(None, &mut self.ui_context);
+ self.app.interface.tab_padding_spinbox_x.clear_children(&mut self.ui_context);
+ self.app.interface.tab_padding_spinbox_x.set_parent(None, &mut self.ui_context);
+ self.app.interface.tab_padding_spinbox_y.clear_children(&mut self.ui_context);
+ self.app.interface.tab_padding_spinbox_y.set_parent(None, &mut self.ui_context);
+ self.app.interface.section_padding_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.section_padding_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.label_alignment_menu.clear_children(&mut self.ui_context);
+ self.app.interface.label_alignment_menu.set_parent(None, &mut self.ui_context);
+ self.app.interface.label_offset_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.label_offset_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.label_margin_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.label_margin_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.plate_padding_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.plate_padding_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.graph_show_grid_toggle.clear_children(&mut self.ui_context);
+ self.app.interface.graph_show_grid_toggle.set_parent(None, &mut self.ui_context);
+ self.app.interface.graph_snap_enabled_toggle.clear_children(&mut self.ui_context);
+ self.app.interface.graph_snap_enabled_toggle.set_parent(None, &mut self.ui_context);
+ self.app.interface.graph_uniform_background_toggle.clear_children(&mut self.ui_context);
+ self.app.interface.graph_uniform_background_toggle.set_parent(None, &mut self.ui_context);
+ self.app.interface.graph_network_opacity_slider.clear_children(&mut self.ui_context);
+ self.app.interface.graph_network_opacity_slider.set_parent(None, &mut self.ui_context);
+ self.app.interface.page_margin_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.page_margin_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.grid_min_col_width_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.grid_min_col_width_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.spinbox_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.spinbox_height_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.toggle_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.toggle_height_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.color_selector_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.color_selector_height_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.color_selector_preview_corner_radius_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.color_selector_preview_corner_radius_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.color_selector_preview_margin_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.color_selector_preview_margin_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.textbox_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.textbox_height_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.slider_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.slider_height_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.color_selector_font_selector.clear_children(&mut self.ui_context);
+ self.app.interface.color_selector_font_selector.set_parent(None, &mut self.ui_context);
+ self.app.interface.menubar_font_selector.clear_children(&mut self.ui_context);
+ self.app.interface.menubar_font_selector.set_parent(None, &mut self.ui_context);
+ self.app.interface.section_label_font_selector.clear_children(&mut self.ui_context);
+ self.app.interface.section_label_font_selector.set_parent(None, &mut self.ui_context);
+ self.app.interface.nested_section_label_font_selector.clear_children(&mut self.ui_context);
+ self.app.interface.nested_section_label_font_selector.set_parent(None, &mut self.ui_context);
+ self.app.interface.font_selector_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.font_selector_height_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.interface.dropdown_height_spinbox.clear_children(&mut self.ui_context);
+ self.app.interface.dropdown_height_spinbox.set_parent(None, &mut self.ui_context);
+
+ self.app.interface.sans_box.clear_children(&mut self.ui_context); self.app.interface.sans_box.set_parent(None, &mut self.ui_context);
+ self.app.interface.serif_box.clear_children(&mut self.ui_context); self.app.interface.serif_box.set_parent(None, &mut self.ui_context);
+ self.app.interface.mono_box.clear_children(&mut self.ui_context); self.app.interface.mono_box.set_parent(None, &mut self.ui_context);
+ self.app.interface.borders_menu.clear_children(&mut self.ui_context); self.app.interface.borders_menu.set_parent(None, &mut self.ui_context);
+ self.app.interface.borders_box.clear_children(&mut self.ui_context); self.app.interface.borders_box.set_parent(None, &mut self.ui_context);
+ self.app.interface.status_menu.clear_children(&mut self.ui_context); self.app.interface.status_menu.set_parent(None, &mut self.ui_context);
+ self.app.interface.status_box.clear_children(&mut self.ui_context); self.app.interface.status_box.set_parent(None, &mut self.ui_context);
+ self.app.interface.fuzzel_menu.clear_children(&mut self.ui_context); self.app.interface.fuzzel_menu.set_parent(None, &mut self.ui_context);
+ self.app.interface.fuzzel_box.clear_children(&mut self.ui_context); self.app.interface.fuzzel_box.set_parent(None, &mut self.ui_context);
+ self.app.interface.terminal_menu.clear_children(&mut self.ui_context); self.app.interface.terminal_menu.set_parent(None, &mut self.ui_context);
+ self.app.interface.terminal_box.clear_children(&mut self.ui_context); self.app.interface.terminal_box.set_parent(None, &mut self.ui_context);
+
+
+ self.app.services.notifications_enable_toggle.clear_children(&mut self.ui_context); self.app.services.notifications_enable_toggle.set_parent(None, &mut self.ui_context);
+ self.app.services.notifications_bell_toggle.clear_children(&mut self.ui_context); self.app.services.notifications_bell_toggle.set_parent(None, &mut self.ui_context);
+ self.app.services.notifications_duration_spinbox.clear_children(&mut self.ui_context); self.app.services.notifications_duration_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.services.notifications_opacity_slider.clear_children(&mut self.ui_context); self.app.services.notifications_opacity_slider.set_parent(None, &mut self.ui_context);
+
+ self.app.input.rate_spinbox.clear_children(&mut self.ui_context); self.app.input.rate_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.delay_spinbox.clear_children(&mut self.ui_context); self.app.input.delay_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.scroll_toggle.clear_children(&mut self.ui_context); self.app.input.scroll_toggle.set_parent(None, &mut self.ui_context);
+ self.app.input.scroll_friction_spinbox.clear_children(&mut self.ui_context); self.app.input.scroll_friction_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.natural_toggle.clear_children(&mut self.ui_context); self.app.input.natural_toggle.set_parent(None, &mut self.ui_context);
+ self.app.input.scroll_speed_spinbox.clear_children(&mut self.ui_context); self.app.input.scroll_speed_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.pointer_toggle.clear_children(&mut self.ui_context); self.app.input.pointer_toggle.set_parent(None, &mut self.ui_context);
+ self.app.input.pointer_friction_spinbox.clear_children(&mut self.ui_context); self.app.input.pointer_friction_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.trackpad_toggle.clear_children(&mut self.ui_context); self.app.input.trackpad_toggle.set_parent(None, &mut self.ui_context);
+ self.app.input.trackpad_friction_spinbox.clear_children(&mut self.ui_context); self.app.input.trackpad_friction_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.dwtp_toggle.clear_children(&mut self.ui_context); self.app.input.dwtp_toggle.set_parent(None, &mut self.ui_context);
+ self.app.input.trackpoint_accel_speed_spinbox.clear_children(&mut self.ui_context); self.app.input.trackpoint_accel_speed_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.input.trackpoint_accel_profile_menu.clear_children(&mut self.ui_context); self.app.input.trackpoint_accel_profile_menu.set_parent(None, &mut self.ui_context);
+ self.app.input.cursor_theme_menu.clear_children(&mut self.ui_context); self.app.input.cursor_theme_menu.set_parent(None, &mut self.ui_context);
+ self.app.input.cursor_size_spinbox.clear_children(&mut self.ui_context); self.app.input.cursor_size_spinbox.set_parent(None, &mut self.ui_context);
for sb in &mut self.app.audio.sink_spinboxes {
- sb.clear_children();
- sb.set_parent(None);
+ sb.clear_children(&mut self.ui_context);
+ sb.set_parent(None, &mut self.ui_context);
}
for sb in &mut self.app.audio.source_spinboxes {
- sb.clear_children();
- sb.set_parent(None);
+ sb.clear_children(&mut self.ui_context);
+ sb.set_parent(None, &mut self.ui_context);
+ }
+ for slider in &mut self.app.audio.sink_sliders {
+ slider.clear_children(&mut self.ui_context);
+ slider.set_parent(None, &mut self.ui_context);
+ }
+ for slider in &mut self.app.audio.source_sliders {
+ slider.clear_children(&mut self.ui_context);
+ slider.set_parent(None, &mut self.ui_context);
}
- self.app.display.brightness_spinbox.clear_children(); self.app.display.brightness_spinbox.set_parent(None);
- self.app.services.status_separators_toggle.clear_children(); self.app.services.status_separators_toggle.set_parent(None);
- self.app.services.status_underline_toggle.clear_children(); self.app.services.status_underline_toggle.set_parent(None);
- self.app.services.status_padding_spinbox.clear_children(); self.app.services.status_padding_spinbox.set_parent(None);
+ self.app.display.brightness_spinbox.clear_children(&mut self.ui_context); self.app.display.brightness_spinbox.set_parent(None, &mut self.ui_context);
+ self.app.display.brightness_slider.clear_children(&mut self.ui_context); self.app.display.brightness_slider.set_parent(None, &mut self.ui_context);
+ self.app.services.status_separators_toggle.clear_children(&mut self.ui_context); self.app.services.status_separators_toggle.set_parent(None, &mut self.ui_context);
+ self.app.services.status_underline_toggle.clear_children(&mut self.ui_context); self.app.services.status_underline_toggle.set_parent(None, &mut self.ui_context);
+ self.app.services.status_padding_spinbox.clear_children(&mut self.ui_context); self.app.services.status_padding_spinbox.set_parent(None, &mut self.ui_context);
for menu in &mut self.app.layout.tag_layout_menus {
- menu.clear_children();
- menu.set_parent(None);
+ menu.clear_children(&mut self.ui_context);
+ menu.set_parent(None, &mut self.ui_context);
}
- self.app.layout.side_panel_behavior_menu.clear_children();
- self.app.layout.side_panel_behavior_menu.set_parent(None);
- self.app.layout.side_panel_width_spinbox.clear_children();
- self.app.layout.side_panel_width_spinbox.set_parent(None);
+ self.app.layout.side_panel_behavior_menu.clear_children(&mut self.ui_context);
+ self.app.layout.side_panel_behavior_menu.set_parent(None, &mut self.ui_context);
+ self.app.layout.side_panel_width_spinbox.clear_children(&mut self.ui_context);
+ self.app.layout.side_panel_width_spinbox.set_parent(None, &mut self.ui_context);
use clear_ui::widget::focus::link_parent_child;
match self.app.current_page {
Page::Accounts => {
if self.app.accounts.editing_oauth_creds {
- link_parent_child(&mut self.page_root_container, &mut self.app.accounts.oauth_client_id_box);
- link_parent_child(&mut self.page_root_container, &mut self.app.accounts.oauth_client_secret_box);
+ link_parent_child(&mut self.page_root_container, &mut self.app.accounts.oauth_client_id_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.accounts.oauth_client_secret_box, &mut self.ui_context);
} else {
- link_parent_child(&mut self.page_root_container, &mut self.app.accounts.email_box);
- link_parent_child(&mut self.page_root_container, &mut self.app.accounts.password_box);
- link_parent_child(&mut self.page_root_container, &mut self.app.accounts.imap_box);
- link_parent_child(&mut self.page_root_container, &mut self.app.accounts.smtp_box);
+ link_parent_child(&mut self.page_root_container, &mut self.app.accounts.email_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.accounts.password_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.accounts.imap_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.accounts.smtp_box, &mut self.ui_context);
}
}
Page::Services => {
self.page_sec_containers.resize_with(3, clear_ui::widget::Container::new);
for i in 0..3 {
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i]);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i], &mut self.ui_context);
}
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.services.search_box);
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.services.list_box.scroll_box);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.services.search_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.services.list_box.scroll_box, &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_enable_toggle);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_bell_toggle);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_duration_spinbox);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_opacity_slider);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_enable_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_bell_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_duration_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_opacity_slider, &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_separators_toggle);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_underline_toggle);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_padding_spinbox);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_separators_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_underline_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_padding_spinbox, &mut self.ui_context);
}
Page::Hardware => {
- link_parent_child(&mut self.page_root_container, &mut self.app.hardware.cpu_list_box.scroll_box);
- link_parent_child(&mut self.page_root_container, &mut self.app.hardware.cpu_gov_menu);
- link_parent_child(&mut self.page_root_container, &mut self.app.hardware.gpu_gov_menu);
+ link_parent_child(&mut self.page_root_container, &mut self.app.hardware.cpu_list_box.scroll_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.hardware.cpu_gov_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.hardware.gpu_gov_menu, &mut self.ui_context);
}
Page::Radios => {
- link_parent_child(&mut self.page_root_container, &mut self.app.network.wifi_list_box.scroll_box);
+ link_parent_child(&mut self.page_root_container, &mut self.app.network.wifi_list_box.scroll_box, &mut self.ui_context);
}
Page::Layout => {
self.page_sec_containers.resize_with(7, clear_ui::widget::Container::new);
for i in 0..7 {
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i]);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i], &mut self.ui_context);
}
// Fullscreen (Section 0)
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.layout.spinboxes[0]);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.layout.spinboxes[0], &mut self.ui_context);
// Cascade (Section 1)
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.spinboxes[1]);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.cascade_offset_spinbox);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.edge_gap_spinbox);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.top_gap_spinbox);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.spinboxes[1], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.cascade_offset_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.edge_gap_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.top_gap_spinbox, &mut self.ui_context);
// Grid (Section 2)
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.layout.spinboxes[2]);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.layout.grid_gap_spinbox);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.layout.spinboxes[2], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.layout.grid_gap_spinbox, &mut self.ui_context);
// Floating (Section 3)
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.layout.spinboxes[3]);
+ link_parent_child(&mut self.page_sec_containers[3], &mut self.app.layout.spinboxes[3], &mut self.ui_context);
// Movement (Section 4)
- link_parent_child(&mut self.page_sec_containers[4], &mut self.app.layout.transition_duration_spinbox);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.layout.transition_duration_spinbox, &mut self.ui_context);
// Default Layouts (Section 5)
for menu in &mut self.app.layout.tag_layout_menus {
- link_parent_child(&mut self.page_sec_containers[5], menu);
+ link_parent_child(&mut self.page_sec_containers[5], menu, &mut self.ui_context);
}
// Side Panel (Section 6)
- link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_behavior_menu);
- link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_width_spinbox);
+ link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_behavior_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_width_spinbox, &mut self.ui_context);
}
Page::Interface => {
- self.page_sec_containers.resize_with(10, clear_ui::widget::Container::new);
+ self.page_sec_containers.resize_with(5, clear_ui::widget::Container::new);
- for i in 0..10 {
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i]);
+ for i in 0..5 {
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i], &mut self.ui_context);
}
- // Section 0: Pages
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.color_selectors[0]);
+ // Section 0: Layout (parent of Plate, Sections, Grid Layout)
+ // (Layout widgets)
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.color_selectors[7], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.color_selectors[1], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.color_selectors[2], &mut self.ui_context);
+ // (Plate child widgets)
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.color_selectors[0], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.plate_padding_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_show_grid_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_snap_enabled_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_uniform_background_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.graph_network_opacity_slider, &mut self.ui_context);
+ // (Sections child widgets)
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.section_padding_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.page_margin_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.section_label_font_selector, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.label_alignment_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.label_offset_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.nested_section_label_font_selector, &mut self.ui_context);
+ // (Grid Layout child widgets)
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.grid_min_col_width_spinbox, &mut self.ui_context);
+
+ // Section 1: Status
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.interface.color_selectors[8], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.interface.color_selectors[3], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.interface.color_selectors[4], &mut self.ui_context);
+
+ // Section 2: Controls (parent of: Slider, MenuBar, Toggles, Spinbox, ColorSelector, Textbox, FontSelector)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[6], &mut self.ui_context);
+ // (Slider child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[5], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.slider_height_spinbox, &mut self.ui_context);
- // Section 1: Layout
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.interface.color_selectors[7]);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.interface.color_selectors[1]);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.interface.color_selectors[2]);
+ // (MenuBar child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[9], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[11], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.tab_margin_spinbox_x, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.tab_margin_spinbox_y, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.tab_padding_spinbox_x, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.tab_padding_spinbox_y, &mut self.ui_context);
- // Section 2: Status
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[8]);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[3]);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[4]);
+ // (Toggles child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[12], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selectors[13], &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.toggle_height_spinbox, &mut self.ui_context);
- // Section 3: Controls
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.interface.color_selectors[5]);
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.interface.color_selectors[6]);
+ // (Spinbox child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.spinbox_height_spinbox, &mut self.ui_context);
- // Section 4: Primary Highlight
- link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.color_selectors[10]);
+ // (ColorSelector child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selector_height_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selector_preview_corner_radius_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selector_preview_margin_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.color_selector_font_selector, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.menubar_font_selector, &mut self.ui_context);
- // Section 5: Paginator
- link_parent_child(&mut self.page_sec_containers[5], &mut self.app.interface.color_selectors[9]);
- link_parent_child(&mut self.page_sec_containers[5], &mut self.app.interface.color_selectors[11]);
- link_parent_child(&mut self.page_sec_containers[5], &mut self.app.interface.tab_margin_spinbox_x);
- link_parent_child(&mut self.page_sec_containers[5], &mut self.app.interface.tab_margin_spinbox_y);
- link_parent_child(&mut self.page_sec_containers[5], &mut self.app.interface.tab_padding_spinbox_x);
- link_parent_child(&mut self.page_sec_containers[5], &mut self.app.interface.tab_padding_spinbox_y);
+ // (Textbox child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.textbox_height_spinbox, &mut self.ui_context);
- // Section 6: Toggles
- link_parent_child(&mut self.page_sec_containers[6], &mut self.app.interface.color_selectors[12]);
- link_parent_child(&mut self.page_sec_containers[6], &mut self.app.interface.color_selectors[13]);
+ // (FontSelector child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.font_selector_height_spinbox, &mut self.ui_context);
- // Section 7: System Typefaces
- link_parent_child(&mut self.page_sec_containers[7], &mut self.app.interface.sans_box);
- link_parent_child(&mut self.page_sec_containers[7], &mut self.app.interface.serif_box);
- link_parent_child(&mut self.page_sec_containers[7], &mut self.app.interface.mono_box);
+ // (Dropdown child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.dropdown_height_spinbox, &mut self.ui_context);
- // Section 8: Program Typefaces
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.borders_menu);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.borders_box);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.status_menu);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.status_box);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.fuzzel_menu);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.fuzzel_box);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.terminal_menu);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.terminal_box);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.paginator_menu);
- link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.paginator_box);
+ // (Labels child widgets)
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.interface.label_margin_spinbox, &mut self.ui_context);
- // Section 9: Typefaces (List & Preview)
- link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.search_box);
- link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.list_box.scroll_box);
+ // Section 3: Indicators (parent of Primary Highlight)
+ link_parent_child(&mut self.page_sec_containers[3], &mut self.app.interface.color_selectors[10], &mut self.ui_context);
+
+ // Section 4: Fonts (parent of System Fonts and Program Fonts)
+ // (System Fonts)
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.sans_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.serif_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.mono_box, &mut self.ui_context);
+
+ // (Program Fonts)
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.borders_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.borders_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.status_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.status_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.fuzzel_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.fuzzel_box, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.terminal_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.interface.terminal_box, &mut self.ui_context);
}
Page::Input => {
self.page_sec_containers.resize_with(5, clear_ui::widget::Container::new);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[0]);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[1]);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[2]);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[3]);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[4]);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[0], &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[1], &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[2], &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[3], &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[4], &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.input.dwtp_toggle);
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.input.trackpoint_accel_speed_spinbox);
- link_parent_child(&mut self.page_sec_containers[0], &mut self.app.input.trackpoint_accel_profile_menu);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.input.dwtp_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.input.trackpoint_accel_speed_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.input.trackpoint_accel_profile_menu, &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.input.rate_spinbox);
- link_parent_child(&mut self.page_sec_containers[1], &mut self.app.input.delay_spinbox);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.input.rate_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[1], &mut self.app.input.delay_spinbox, &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.input.cursor_theme_menu);
- link_parent_child(&mut self.page_sec_containers[2], &mut self.app.input.cursor_size_spinbox);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.input.cursor_theme_menu, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[2], &mut self.app.input.cursor_size_spinbox, &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.scroll_toggle);
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.scroll_friction_spinbox);
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.natural_toggle);
- link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.scroll_speed_spinbox);
+ link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.scroll_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.scroll_friction_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.natural_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[3], &mut self.app.input.scroll_speed_spinbox, &mut self.ui_context);
- link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.pointer_toggle);
- link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.pointer_friction_spinbox);
- link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.trackpad_toggle);
- link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.trackpad_friction_spinbox);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.pointer_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.pointer_friction_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.trackpad_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[4], &mut self.app.input.trackpad_friction_spinbox, &mut self.ui_context);
}
Page::Audio => {
self.page_sec_containers.resize_with(2, clear_ui::widget::Container::new);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[0]);
- link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[1]);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[0], &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[1], &mut self.ui_context);
for sb in &mut self.app.audio.sink_spinboxes {
- link_parent_child(&mut self.page_sec_containers[0], sb);
+ link_parent_child(&mut self.page_sec_containers[0], sb, &mut self.ui_context);
}
for sb in &mut self.app.audio.source_spinboxes {
- link_parent_child(&mut self.page_sec_containers[1], sb);
+ link_parent_child(&mut self.page_sec_containers[1], sb, &mut self.ui_context);
+ }
+ for slider in &mut self.app.audio.sink_sliders {
+ link_parent_child(&mut self.page_sec_containers[0], slider, &mut self.ui_context);
+ }
+ for slider in &mut self.app.audio.source_sliders {
+ link_parent_child(&mut self.page_sec_containers[1], slider, &mut self.ui_context);
}
}
Page::Display => {
- link_parent_child(&mut self.page_root_container, &mut self.app.display.brightness_spinbox);
- link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_enable_toggle);
- link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_lock_screen_toggle);
- link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_timeout_spinbox);
- link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_style_menu);
+ link_parent_child(&mut self.page_root_container, &mut self.app.display.brightness_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.display.brightness_slider, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_enable_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_lock_screen_toggle, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_timeout_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_root_container, &mut self.app.display.screensaver_style_menu, &mut self.ui_context);
+ }
+ Page::Packages => {
+ self.page_sec_containers.resize_with(2, clear_ui::widget::Container::new);
+ for i in 0..2 {
+ link_parent_child(&mut self.page_root_container, &mut self.page_sec_containers[i], &mut self.ui_context);
+ }
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.packages.search_box, &mut self.ui_context);
+ match self.app.packages.active_tab {
+ pages::packages::PackageTab::Installed => {
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.packages.installed_list_box.scroll_box, &mut self.ui_context);
+ }
+ pages::packages::PackageTab::Updates => {
+ link_parent_child(&mut self.page_sec_containers[0], &mut self.app.packages.updates_list_box.scroll_box, &mut self.ui_context);
+ }
+ }
}
_ => {}
}
let mut popovers = Vec::new();
- Self::collect_popover_rects(&self.page_root_container, &mut popovers);
+ Self::collect_popover_rects(&self.page_root_container, &mut popovers, &self.ui_context);
if !popovers.is_empty() {
pc.texts.retain(|(text, size, tx, ty, _, _, _)| {
@@ -810,6 +1045,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
});
}
+ clear_ui::layout::render_popovers(&mut pc, &mut self.ui_context);
+
let mut max_y = 0.0f32;
for (_, _, y, _, h) in &pc.rects {
max_y = max_y.max(y + h);
@@ -833,6 +1070,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
});
}
for (t, size, x, y, tc, font_opt, bounds) in &pc.texts {
+ let shifted_bounds = bounds.map(|[bl, bt, br, bb]| {
+ [bl, bt - scroll_offset_y, br, bb - scroll_offset_y]
+ });
text_items.push(TextItem {
buffer: make_text_buffer_with_font(
&mut self.font_system,
@@ -847,7 +1087,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
color: glyphon::Color::rgb(
(tc[0] * 255.0) as u8, (tc[1] * 255.0) as u8, (tc[2] * 255.0) as u8,
),
- bounds: *bounds,
+ bounds: shifted_bounds,
});
}
for btn in &pc.buttons {
@@ -857,20 +1097,14 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
hovering: false,
});
let buf = make_text_buffer(&mut self.font_system, &btn.label, btn.label_size * s);
- let tw = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
+ let scale = clear_ui::scale::scale_factor();
+ let tw = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0) / scale;
let lh = btn.label_size * s * 1.4;
let mut left_align = btn.left_align;
// Auto-detect if inside a ScrollBox to apply left alignment by default
if !left_align && btn.w >= 60.0 {
- if self.app.current_page == Page::Interface {
- let sb = &self.app.interface.list_box;
- let (sb_x, sb_y, sb_w, sb_h) = sb.rect();
- if btn.x >= sb_x - 1.0 && btn.x + btn.w <= sb_x + sb_w + 1.0
- && btn.y >= sb_y - 1.0 && btn.y + btn.h <= sb_y + sb_h + 1.0 {
- left_align = true;
- }
- } else if self.app.current_page == Page::Hardware {
+ if self.app.current_page == Page::Hardware {
let sb = &self.app.hardware.cpu_list_box;
let (sb_x, sb_y, sb_w, sb_h) = sb.rect();
if btn.x >= sb_x - 1.0 && btn.x + btn.w <= sb_x + sb_w + 1.0
@@ -980,23 +1214,29 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
fn render_page_content(&mut self, cx: f32, cy: f32, cw: f32, ch: f32) -> PageContent {
use pages::*;
use clear_ui::layout::GridLayout;
- let mut layout = GridLayout::new(320.0, 20.0);
+ let margin = clear_ui::layout::page_margin();
+ let cx = cx + margin;
+ let cy = cy + margin;
+ let cw = (cw - 2.0 * margin).max(1.0);
+ let ch = (ch - 2.0 * margin).max(1.0);
+ let mut layout = GridLayout::new(260.0, 20.0);
let root_focused = clear_ui::widget::focus::is_focused(&self.page_root_container);
let sec_focused: Vec<bool> = self.page_sec_containers.iter()
.map(|c| clear_ui::widget::focus::is_focused(c))
.collect();
match self.app.current_page {
- Page::Accounts => accounts::view(&mut self.app.accounts, cx, cy, cw, ch, &mut layout),
- Page::Audio => audio::view(&mut self.app.audio, cx, cy, cw, ch, &sec_focused, &mut layout),
- Page::Display => display::view(&mut self.app.display, cx, cy, cw, ch, &mut layout),
- Page::Radios => network::view(&mut self.app.network, cx, cy, cw, ch, root_focused, &mut layout),
- Page::Layout => layout::view(&mut self.app.layout, cx, cy, cw, ch, &sec_focused, &mut layout),
- Page::Hardware => hardware::view(&mut self.app.hardware, cx, cy, cw, ch, root_focused, &mut layout),
- Page::Input => input::view(&mut self.app.input, cx, cy, cw, ch, &sec_focused, &mut layout),
- Page::System => system_info::view(&self.app.system_info, cx, cy, cw, ch, &mut layout),
- Page::Storage => storage::view(&self.app.storage, cx, cy, cw, ch, &mut layout),
- Page::Services => services::view(&mut self.app.services, cx, cy, cw, ch, &sec_focused, &mut layout),
- Page::Interface => interface::view(&mut self.app.interface, cx, cy, cw, ch, &sec_focused, &mut layout),
+ Page::Accounts => accounts::view(&mut self.app.accounts, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
+ Page::Audio => audio::view(&mut self.app.audio, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
+ Page::Display => display::view(&mut self.app.display, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
+ Page::Radios => network::view(&mut self.app.network, cx, cy, cw, ch, root_focused, &mut layout, &mut self.ui_context),
+ Page::Layout => layout::view(&mut self.app.layout, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
+ Page::Hardware => hardware::view(&mut self.app.hardware, cx, cy, cw, ch, root_focused, &mut layout, &mut self.ui_context),
+ Page::Input => input::view(&mut self.app.input, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
+ Page::System => system_info::view(&self.app.system_info, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
+ Page::Storage => storage::view(&self.app.storage, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
+ Page::Services => services::view(&mut self.app.services, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
+ Page::Interface => interface::view(&mut self.app.interface, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
+ Page::Packages => packages::view(&mut self.app.packages, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
}
}
@@ -1007,13 +1247,13 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
needs_redraw = true;
self.needs_rebuild = true;
}
- if self.paginator.tick(dt) {
+ if self.paginator.tick(dt, &mut self.ui_context) {
needs_redraw = true;
self.needs_rebuild = true;
}
if let Some(root_ptr) = self.get_page_root_widget() {
unsafe {
- if (*root_ptr).tick(dt) {
+ if (*root_ptr).tick(dt, &mut self.ui_context) {
needs_redraw = true;
self.needs_rebuild = true;
}
@@ -1024,7 +1264,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let mut color_changed = false;
let mut color_actions = Vec::new();
for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
- if cp.tick(dt) {
+ if cp.tick(dt, &mut self.ui_context) {
needs_redraw = true;
self.needs_rebuild = true;
}
@@ -1081,26 +1321,38 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
use pages::*;
while let Ok(s) = self.rx_audio.try_recv() {
audio::update(&mut self.app.audio, audio::AudioMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Audio {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_display.try_recv() {
display::update(&mut self.app.display, display::DisplayMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Display {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_network.try_recv() {
network::update(&mut self.app.network, network::NetworkMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Radios {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_layout.try_recv() {
layout::update(&mut self.app.layout, layout::LayoutMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Layout {
+ self.needs_rebuild = true;
+ }
}
while let Ok(_) = self.rx_wm_events.try_recv() {
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Layout {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_input.try_recv() {
input::update(&mut self.app.input, input::InputMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Input {
+ self.needs_rebuild = true;
+ }
}
let mut got_fingers = None;
while let Ok(s) = self.rx_fingers.try_recv() {
@@ -1108,50 +1360,84 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if let Some(fingers) = got_fingers {
input::update(&mut self.app.input, input::InputMessage::UpdateFingers(fingers));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Input {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_system.try_recv() {
system_info::update(&mut self.app.system_info, system_info::SystemMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::System {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_hardware.try_recv() {
hardware::update(&mut self.app.hardware, hardware::HardwareMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Hardware {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_status.try_recv() {
services::update(&mut self.app.services, services::ServicesMessage::StatusRefreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Services {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_storage.try_recv() {
storage::update(&mut self.app.storage, storage::StorageMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Storage {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_notifications.try_recv() {
services::update(&mut self.app.services, services::ServicesMessage::NotificationsRefreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Services {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_typeface.try_recv() {
self.sans_serif_family = s.sans_serif.clone();
self.serif_family = s.serif.clone();
self.monospace_family = s.monospace.clone();
interface::update(&mut self.app.interface, interface::InterfaceMessage::TypefaceRefreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Interface {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_services.try_recv() {
pages::services::update(&mut self.app.services, pages::services::ServicesMessage::Refreshed(s));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Services {
+ self.needs_rebuild = true;
+ }
}
while let Ok(s) = self.rx_interface.try_recv() {
interface::update(&mut self.app.interface, pages::interface::InterfaceMessage::Refreshed(s));
- self.needs_rebuild = true;
+ 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));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Accounts {
+ self.needs_rebuild = true;
+ }
}
while let Ok(m) = self.rx_backup.try_recv() {
self.handle_action(&AppAction::Storage(m));
- self.needs_rebuild = true;
+ if self.app.current_page == Page::Storage {
+ self.needs_rebuild = true;
+ }
+ }
+ while let Ok(s) = self.rx_packages.try_recv() {
+ pages::packages::update(&mut self.app.packages, pages::packages::PackagesMessage::Refreshed(s));
+ if self.app.current_page == Page::Packages {
+ self.needs_rebuild = true;
+ }
+ }
+ while let Ok(m) = self.rx_update.try_recv() {
+ self.handle_action(&AppAction::Packages(m));
+ if self.app.current_page == Page::Packages {
+ self.needs_rebuild = true;
+ }
}
}
@@ -1194,6 +1480,67 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
_ => pages::accounts::update(&mut self.app.accounts, m.clone()),
},
+ AppAction::Packages(m) => match m {
+ pages::packages::PackagesMessage::StartUpdate => {
+ pages::packages::update(&mut self.app.packages, pages::packages::PackagesMessage::StartUpdate);
+ let tx = self.tx_update.clone();
+ tokio::spawn(async move {
+ let res = pages::packages::run_update().await;
+ let _ = tx.send(pages::packages::PackagesMessage::UpdateFinished(res));
+ });
+ }
+ pages::packages::PackagesMessage::UpdateFinished(res) => {
+ pages::packages::update(&mut self.app.packages, m.clone());
+ if res.is_ok() {
+ let tx = self.tx_update.clone();
+ tokio::spawn(async move {
+ let new_state = pages::packages::fetch_packages_state().await;
+ let _ = tx.send(pages::packages::PackagesMessage::Refreshed(new_state));
+ });
+ }
+ }
+ pages::packages::PackagesMessage::SelectPackage(Some(ref name)) => {
+ let name_clone = name.clone();
+ let is_installed = self.app.packages.active_tab == pages::packages::PackageTab::Installed;
+ pages::packages::update(&mut self.app.packages, m.clone());
+ let tx = self.tx_update.clone();
+ tokio::spawn(async move {
+ let res = pages::packages::fetch_package_info(name_clone.clone(), is_installed).await;
+ let _ = tx.send(pages::packages::PackagesMessage::InfoFetched(name_clone, res));
+ });
+ }
+ pages::packages::PackagesMessage::SelectAndScrollPackage(ref name) => {
+ let name_clone = name.clone();
+ pages::packages::update(&mut self.app.packages, m.clone());
+ let tx = self.tx_update.clone();
+ tokio::spawn(async move {
+ let res = pages::packages::fetch_package_info(name_clone.clone(), true).await;
+ let _ = tx.send(pages::packages::PackagesMessage::InfoFetched(name_clone, res));
+ });
+ }
+ pages::packages::PackagesMessage::StartUninstall(ref name) => {
+ if !self.app.packages.uninstalling {
+ pages::packages::update(&mut self.app.packages, m.clone());
+ let name_clone = name.clone();
+ let tx = self.tx_update.clone();
+ tokio::spawn(async move {
+ let res = pages::packages::run_uninstall(name_clone).await;
+ let _ = tx.send(pages::packages::PackagesMessage::UninstallFinished(res));
+ });
+ }
+ }
+ pages::packages::PackagesMessage::UninstallFinished(res) => {
+ pages::packages::update(&mut self.app.packages, m.clone());
+ if res.is_ok() {
+ let tx = self.tx_update.clone();
+ tokio::spawn(async move {
+ let new_state = pages::packages::fetch_packages_state().await;
+ let _ = tx.send(pages::packages::PackagesMessage::Refreshed(new_state));
+ });
+ }
+ }
+ _ => pages::packages::update(&mut self.app.packages, m.clone()),
+ },
}
}
@@ -1217,7 +1564,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
clear_ui::widget::hover_animation::set_cursor_pos(lx, ly_no_scroll);
let mut changed = false;
if lx_no_scroll < self.sidebar_width {
- if self.paginator.cursor_moved(lx_no_scroll, ly_no_scroll) {
+ if self.paginator.cursor_moved(lx_no_scroll, ly_no_scroll, &mut self.ui_context) {
changed = true;
}
}
@@ -1232,239 +1579,390 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if self.app.current_page == Page::Layout {
for sb in &mut self.app.layout.spinboxes {
- if sb.cursor_moved(lx, ly) {
+ if sb.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
- if self.app.layout.cascade_offset_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.cascade_offset_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.layout.edge_gap_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.edge_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.layout.top_gap_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.top_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.layout.grid_gap_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.grid_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.layout.transition_duration_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.transition_duration_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.layout.status_height_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.status_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
for menu in &mut self.app.layout.tag_layout_menus {
- if menu.cursor_moved(lx, ly) {
+ if menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
- if self.app.layout.side_panel_behavior_menu.cursor_moved(lx, ly) {
+ if self.app.layout.side_panel_behavior_menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.layout.side_panel_width_spinbox.cursor_moved(lx, ly) {
+ if self.app.layout.side_panel_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
if self.app.current_page == Page::Interface {
for cp in &mut self.app.interface.color_selectors {
- if cp.cursor_moved(lx, ly) {
+ if cp.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
- if self.app.interface.tab_margin_spinbox_x.cursor_moved(lx, ly) {
+ if self.app.interface.tab_margin_spinbox_x.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.tab_margin_spinbox_y.cursor_moved(lx, ly) {
+ if self.app.interface.tab_margin_spinbox_y.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.tab_padding_spinbox_x.cursor_moved(lx, ly) {
+ if self.app.interface.tab_padding_spinbox_x.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.tab_padding_spinbox_y.cursor_moved(lx, ly) {
+ if self.app.interface.tab_padding_spinbox_y.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.sans_box.cursor_moved(lx, ly) {
+ if self.app.interface.section_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.serif_box.cursor_moved(lx, ly) {
+ if self.app.interface.label_alignment_menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.mono_box.cursor_moved(lx, ly) {
+ if self.app.interface.label_offset_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.borders_menu.cursor_moved(lx, ly) {
+ if self.app.interface.label_margin_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.borders_box.cursor_moved(lx, ly) {
+ if self.app.interface.plate_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.status_menu.cursor_moved(lx, ly) {
+ if self.app.interface.graph_show_grid_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.status_box.cursor_moved(lx, ly) {
+ if self.app.interface.graph_snap_enabled_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.fuzzel_menu.cursor_moved(lx, ly) {
+ if self.app.interface.graph_uniform_background_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.fuzzel_box.cursor_moved(lx, ly) {
+ if self.app.interface.graph_network_opacity_slider.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.terminal_menu.cursor_moved(lx, ly) {
+ if self.app.interface.page_margin_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.terminal_box.cursor_moved(lx, ly) {
+ if self.app.interface.grid_min_col_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.paginator_menu.cursor_moved(lx, ly) {
+ if self.app.interface.spinbox_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.paginator_box.cursor_moved(lx, ly) {
+ if self.app.interface.toggle_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.search_box.cursor_moved(lx, ly) {
+ if self.app.interface.color_selector_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.list_box.cursor_moved(lx, ly) {
+ if self.app.interface.color_selector_preview_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.borders_size_box.cursor_moved(lx, ly) {
+ if self.app.interface.color_selector_preview_margin_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.status_size_box.cursor_moved(lx, ly) {
+ if self.app.interface.color_selector_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.fuzzel_size_box.cursor_moved(lx, ly) {
+ if self.app.interface.menubar_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.terminal_size_box.cursor_moved(lx, ly) {
+ if self.app.interface.section_label_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.interface.paginator_size_box.cursor_moved(lx, ly) {
+ if self.app.interface.nested_section_label_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- let query = self.app.interface.search_box.text.to_lowercase();
- let matching_count = self.app.interface.all_fonts.iter()
- .filter(|f| f.to_lowercase().contains(&query))
- .count();
- for i in 0..matching_count.min(self.app.interface.font_buttons.len()) {
- if self.app.interface.font_buttons[i].cursor_moved(lx, ly) {
- changed = true;
- }
- if self.app.interface.copy_buttons[i].cursor_moved(lx, ly) {
- changed = true;
- }
+ if self.app.interface.textbox_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.slider_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.font_selector_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.dropdown_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.sans_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.serif_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.mono_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.borders_menu.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.borders_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.status_menu.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.status_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.fuzzel_menu.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.fuzzel_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.terminal_menu.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.terminal_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.borders_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.status_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.fuzzel_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.interface.terminal_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
}
}
if self.app.current_page == Page::Input {
- if self.app.input.rate_spinbox.cursor_moved(lx, ly) {
+ if self.app.input.rate_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.delay_spinbox.cursor_moved(lx, ly) {
+ if self.app.input.delay_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.tap_toggle.cursor_moved(lx, ly) {
+ if self.app.input.tap_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.scroll_toggle.cursor_moved(lx, ly) {
+ if self.app.input.scroll_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.scroll_friction_spinbox.cursor_moved(lx, ly) {
+ if self.app.input.scroll_friction_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.pointer_toggle.cursor_moved(lx, ly) {
+ if self.app.input.pointer_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.pointer_friction_spinbox.cursor_moved(lx, ly) {
+ if self.app.input.pointer_friction_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.trackpad_toggle.cursor_moved(lx, ly) {
+ if self.app.input.trackpad_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.trackpad_friction_spinbox.cursor_moved(lx, ly) {
+ if self.app.input.trackpad_friction_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.dwtp_toggle.cursor_moved(lx, ly) {
+ if self.app.input.dwtp_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.trackpoint_accel_speed_spinbox.cursor_moved(lx, ly) {
+ if self.app.input.trackpoint_accel_speed_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.input.trackpoint_accel_profile_menu.cursor_moved(lx, ly) {
+ if self.app.input.trackpoint_accel_profile_menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
if self.app.current_page == Page::Audio {
- for sb in &mut self.app.audio.sink_spinboxes {
- if sb.cursor_moved(lx, ly) {
- changed = true;
+ if let Some(idx) = self.audio_sink_dragging {
+ if idx < self.app.audio.sink_sliders.len() {
+ if self.app.audio.sink_sliders[idx].drag_update(lx, ly) {
+ changed = true;
+ let val = self.app.audio.sink_sliders[idx].value();
+ if idx < self.app.audio.sink_spinboxes.len() {
+ self.app.audio.sink_spinboxes[idx].value = (val * 100.0).round() as i32;
+ }
+ if idx < self.app.audio.sinks.len() {
+ let id = self.app.audio.sinks[idx].id;
+ self.handle_action(&AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, val)));
+ }
+ }
}
- }
- for sb in &mut self.app.audio.source_spinboxes {
- if sb.cursor_moved(lx, ly) {
- changed = true;
+ } else if let Some(idx) = self.audio_source_dragging {
+ if idx < self.app.audio.source_sliders.len() {
+ if self.app.audio.source_sliders[idx].drag_update(lx, ly) {
+ changed = true;
+ let val = self.app.audio.source_sliders[idx].value();
+ if idx < self.app.audio.source_spinboxes.len() {
+ self.app.audio.source_spinboxes[idx].value = (val * 100.0).round() as i32;
+ }
+ if idx < self.app.audio.sources.len() {
+ let id = self.app.audio.sources[idx].id;
+ self.handle_action(&AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, val)));
+ }
+ }
+ }
+ } else {
+ for sb in &mut self.app.audio.sink_spinboxes {
+ if sb.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ }
+ for sb in &mut self.app.audio.source_spinboxes {
+ if sb.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ }
+ for slider in &mut self.app.audio.sink_sliders {
+ if slider.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ }
+ for slider in &mut self.app.audio.source_sliders {
+ if slider.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
}
}
}
if self.app.current_page == Page::Display {
- if self.app.display.brightness_spinbox.cursor_moved(lx, ly) {
- changed = true;
+ if self.display_brightness_dragging {
+ if self.app.display.brightness_slider.drag_update(lx, ly) {
+ changed = true;
+ let val = self.app.display.brightness_slider.value();
+ let pct = (val * 100.0).round() as u32;
+ self.app.display.brightness_spinbox.value = pct as i32;
+ self.handle_action(&AppAction::Display(pages::display::DisplayMessage::BrightnessSet(pct)));
+ }
+ } else {
+ if self.app.display.brightness_slider.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.display.brightness_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
}
- if self.app.display.night_light_label.cursor_moved(lx, ly) {
+ if self.app.display.night_light_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
for out in &mut self.app.display.outputs {
- if out.name_label.cursor_moved(lx, ly) {
+ if out.name_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if out.resolution_label.cursor_moved(lx, ly) {
+ if out.resolution_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
if let Some(ref mut scale_lbl) = out.scale_label {
- if scale_lbl.cursor_moved(lx, ly) {
+ if scale_lbl.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
}
- if self.app.display.screensaver_enable_toggle.cursor_moved(lx, ly) {
+ if self.app.display.screensaver_enable_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.display.screensaver_lock_screen_toggle.cursor_moved(lx, ly) {
+ if self.app.display.screensaver_lock_screen_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.display.screensaver_timeout_spinbox.cursor_moved(lx, ly) {
+ if self.app.display.screensaver_timeout_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.display.screensaver_style_menu.cursor_moved(lx, ly) {
+ if self.app.display.screensaver_style_menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
if self.app.current_page == Page::Hardware {
- if self.app.hardware.cpu_label.cursor_moved(lx, ly) {
+ if self.app.hardware.cpu_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.hardware.cpu_usage_label.cursor_moved(lx, ly) {
+ if self.app.hardware.cpu_usage_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.hardware.cpu_temp_label.cursor_moved(lx, ly) {
+ if self.app.hardware.cpu_temp_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
for gpu_lbl in &mut self.app.hardware.gpu_labels {
- if gpu_lbl.cursor_moved(lx, ly) {
+ if gpu_lbl.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
- if self.app.hardware.cpu_list_box.cursor_moved(lx, ly) {
+ if self.app.hardware.cpu_list_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ if self.app.hardware.cpu_gov_menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.hardware.cpu_gov_menu.cursor_moved(lx, ly) {
+ if self.app.hardware.gpu_gov_menu.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.hardware.gpu_gov_menu.cursor_moved(lx, ly) {
+ }
+
+ if self.app.current_page == Page::Packages {
+ let pkgs = &mut self.app.packages;
+ if pkgs.search_box.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
+ match pkgs.active_tab {
+ pages::packages::PackageTab::Installed => {
+ if pkgs.installed_list_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ let query = if pkgs.search_box.editing {
+ pkgs.search_box.edit_buffer.to_lowercase()
+ } else {
+ pkgs.search_box.text.to_lowercase()
+ };
+ let matching = pkgs.installed.iter()
+ .filter(|p| p.name.to_lowercase().contains(&query) || p.version.to_lowercase().contains(&query))
+ .count();
+ for i in 0..matching.min(pkgs.installed_items.len()) {
+ if pkgs.installed_items[i].cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ }
+ }
+ pages::packages::PackageTab::Updates => {
+ if pkgs.updates_list_box.cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ let query = if pkgs.search_box.editing {
+ pkgs.search_box.edit_buffer.to_lowercase()
+ } else {
+ pkgs.search_box.text.to_lowercase()
+ };
+ let matching = pkgs.updates.iter()
+ .filter(|p| p.name.to_lowercase().contains(&query))
+ .count();
+ for i in 0..matching.min(pkgs.updates_items.len()) {
+ if pkgs.updates_items[i].cursor_moved(lx, ly, &mut self.ui_context) {
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if self.app.current_page == Page::Interface {
+ if self.graph_opacity_dragging {
+ if self.app.interface.graph_network_opacity_slider.drag_update(lx, ly) {
+ changed = true;
+ }
+ }
}
if self.app.current_page == Page::Services {
@@ -1473,10 +1971,10 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
changed = true;
}
} else {
- if self.app.services.search_box.cursor_moved(lx, ly) {
+ if self.app.services.search_box.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.list_box.cursor_moved(lx, ly) {
+ if self.app.services.list_box.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
let query = if self.app.services.search_box.editing {
@@ -1489,48 +1987,45 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
.filter(|s| s.name.to_lowercase().contains(&query) || s.description.to_lowercase().contains(&query))
.count();
for i in 0..matching_count.min(self.app.services.service_items.len()) {
- if self.app.services.service_items[i].cursor_moved(lx, ly) {
+ if self.app.services.service_items[i].cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
- if self.app.services.notifications_enable_toggle.cursor_moved(lx, ly) {
+ if self.app.services.notifications_enable_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.notifications_bell_toggle.cursor_moved(lx, ly) {
+ if self.app.services.notifications_bell_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.notifications_duration_spinbox.cursor_moved(lx, ly) {
+ if self.app.services.notifications_duration_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.notifications_opacity_slider.cursor_moved(lx, ly) {
+ if self.app.services.notifications_opacity_slider.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.status_label.cursor_moved(lx, ly) {
+ if self.app.services.status_label.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.status_size_label.cursor_moved(lx, ly) {
+ if self.app.services.status_separators_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.status_separators_toggle.cursor_moved(lx, ly) {
+ if self.app.services.status_underline_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
- if self.app.services.status_underline_toggle.cursor_moved(lx, ly) {
- changed = true;
- }
- if self.app.services.status_padding_spinbox.cursor_moved(lx, ly) {
+ if self.app.services.status_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
changed = true;
}
}
}
if self.app.current_page == Page::Accounts {
if self.app.accounts.editing_oauth_creds {
- if self.app.accounts.oauth_client_id_box.cursor_moved(lx, ly) { changed = true; }
- if self.app.accounts.oauth_client_secret_box.cursor_moved(lx, ly) { changed = true; }
+ if self.app.accounts.oauth_client_id_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
+ if self.app.accounts.oauth_client_secret_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
} else {
- if self.app.accounts.email_box.cursor_moved(lx, ly) { changed = true; }
- if self.app.accounts.password_box.cursor_moved(lx, ly) { changed = true; }
- if self.app.accounts.imap_box.cursor_moved(lx, ly) { changed = true; }
- if self.app.accounts.smtp_box.cursor_moved(lx, ly) { changed = true; }
+ if self.app.accounts.email_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
+ if self.app.accounts.password_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
+ if self.app.accounts.imap_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
+ if self.app.accounts.smtp_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
}
}
if changed { self.needs_rebuild = true; }
@@ -1550,13 +2045,14 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if lx_no_scroll < self.sidebar_width {
- if self.paginator.mouse_input(button, state, lx_no_scroll, ly_no_scroll) {
+ if self.paginator.mouse_input(button, state, lx_no_scroll, ly_no_scroll, &mut self.ui_context) {
if self.paginator.take_click() {
let idx = self.paginator.selected_page();
if idx < Page::ALL.len() {
clear_ui::widget::focus::clear_focus();
let new_page = Page::ALL[idx];
self.app.current_page = new_page;
+ self.current_page_shared.store(idx as u8, std::sync::atomic::Ordering::SeqCst);
self.scroll_y = 0.0;
pages::interface::write_config_value("last_page", &format!("\"{}\"", new_page.label().to_lowercase()));
}
@@ -1568,6 +2064,40 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if button != clear_ui::widget::MouseButton::Left && button != clear_ui::widget::MouseButton::Right { return false; }
if button == clear_ui::widget::MouseButton::Left && state == clear_ui::widget::ElementState::Released {
+ if self.app.current_page == Page::Audio {
+ let mut ended = false;
+ if let Some(idx) = self.audio_sink_dragging {
+ if idx < self.app.audio.sink_sliders.len() {
+ self.app.audio.sink_sliders[idx].drag_end();
+ }
+ self.audio_sink_dragging = None;
+ ended = true;
+ }
+ if let Some(idx) = self.audio_source_dragging {
+ if idx < self.app.audio.source_sliders.len() {
+ self.app.audio.source_sliders[idx].drag_end();
+ }
+ self.audio_source_dragging = None;
+ ended = true;
+ }
+ if ended {
+ self.needs_rebuild = true;
+ }
+ }
+ if self.app.current_page == Page::Display {
+ if self.display_brightness_dragging {
+ self.app.display.brightness_slider.drag_end();
+ self.display_brightness_dragging = false;
+ self.needs_rebuild = true;
+ }
+ }
+ if self.app.current_page == Page::Interface {
+ if self.graph_opacity_dragging {
+ self.app.interface.graph_network_opacity_slider.drag_end();
+ self.graph_opacity_dragging = false;
+ self.needs_rebuild = true;
+ }
+ }
let (px, py) = (self.cursor_x, self.cursor_y);
for btn in &self.page_buttons.clone() {
if px >= btn.x && px <= btn.x + btn.w && py >= btn.y && py <= btn.y + btn.h {
@@ -1587,106 +2117,144 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
Page::Accounts => {
let accs = &mut self.app.accounts;
if accs.editing_oauth_creds {
- if accs.oauth_client_id_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if accs.oauth_client_secret_box.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if accs.oauth_client_id_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if accs.oauth_client_secret_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
} else {
- if accs.email_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if accs.password_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if accs.imap_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if accs.smtp_box.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if accs.email_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if accs.password_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if accs.imap_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if accs.smtp_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
}
Page::Layout => {
for sb in &mut self.app.layout.spinboxes {
- if sb.hit_test(lx, ly) { clicked_any_focusable = true; }
- }
- if self.app.layout.cascade_offset_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.layout.edge_gap_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.layout.top_gap_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.layout.grid_gap_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.layout.transition_duration_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.layout.status_height_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ }
+ if self.app.layout.cascade_offset_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.layout.edge_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.layout.top_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.layout.grid_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.layout.transition_duration_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.layout.status_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
for menu in &mut self.app.layout.tag_layout_menus {
- if menu.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
- if self.app.layout.side_panel_behavior_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.layout.side_panel_width_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if self.app.layout.side_panel_behavior_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.layout.side_panel_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
Page::Interface => {
for cp in &mut self.app.interface.color_selectors {
- if cp.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if cp.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
- if self.app.interface.tab_margin_spinbox_x.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.interface.tab_margin_spinbox_y.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.interface.tab_padding_spinbox_x.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.interface.tab_padding_spinbox_y.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if self.app.interface.tab_margin_spinbox_x.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.tab_margin_spinbox_y.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.tab_padding_spinbox_x.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.tab_padding_spinbox_y.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.section_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.label_alignment_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.label_offset_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.label_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.plate_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.graph_show_grid_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.graph_snap_enabled_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.graph_uniform_background_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.graph_network_opacity_slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.page_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.grid_min_col_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.spinbox_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.toggle_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.color_selector_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.color_selector_preview_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.color_selector_preview_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.color_selector_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.menubar_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.section_label_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.nested_section_label_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.textbox_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.slider_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.font_selector_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.interface.dropdown_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
let tf = &mut self.app.interface;
- if tf.sans_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.serif_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.mono_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.borders_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.borders_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.status_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.status_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.fuzzel_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.fuzzel_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.terminal_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.terminal_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.paginator_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.paginator_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.search_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if tf.list_box.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if tf.sans_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.serif_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.mono_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.borders_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.borders_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.status_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.status_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.fuzzel_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.fuzzel_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.terminal_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if tf.terminal_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
Page::Input => {
- if self.app.input.rate_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.input.delay_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.input.scroll_friction_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.input.pointer_friction_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.input.trackpad_friction_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.input.trackpoint_accel_speed_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.input.trackpoint_accel_profile_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if self.app.input.rate_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.input.delay_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.input.scroll_friction_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.input.pointer_friction_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.input.trackpad_friction_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.input.trackpoint_accel_speed_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.input.trackpoint_accel_profile_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
Page::Audio => {
for sb in &mut self.app.audio.sink_spinboxes {
- if sb.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
for sb in &mut self.app.audio.source_spinboxes {
- if sb.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ }
+ for slider in &mut self.app.audio.sink_sliders {
+ if slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ }
+ for slider in &mut self.app.audio.source_sliders {
+ if slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
}
Page::Display => {
- if self.app.display.brightness_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.display.night_light_label.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if self.app.display.brightness_slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.display.brightness_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.display.night_light_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
for out in &mut self.app.display.outputs {
- if out.name_label.hit_test(lx, ly) { clicked_any_focusable = true; }
- if out.resolution_label.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if out.name_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if out.resolution_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
if let Some(ref mut scale_lbl) = out.scale_label {
- if scale_lbl.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if scale_lbl.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
}
- if self.app.display.screensaver_timeout_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if self.app.display.screensaver_style_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if self.app.display.screensaver_timeout_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if self.app.display.screensaver_style_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
Page::Services => {
let srv = &mut self.app.services;
- if srv.search_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if srv.list_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if srv.notifications_duration_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
- if srv.notifications_opacity_slider.hit_test(lx, ly) { clicked_any_focusable = true; }
- if srv.status_label.hit_test(lx, ly) { clicked_any_focusable = true; }
- if srv.status_size_label.hit_test(lx, ly) { clicked_any_focusable = true; }
- if srv.status_padding_spinbox.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if srv.search_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if srv.list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if srv.notifications_duration_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if srv.notifications_opacity_slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if srv.status_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if srv.status_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ }
+ Page::Packages => {
+ let pkgs = &mut self.app.packages;
+ if pkgs.search_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ match pkgs.active_tab {
+ pages::packages::PackageTab::Installed => {
+ if pkgs.installed_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ }
+ pages::packages::PackageTab::Updates => {
+ if pkgs.updates_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ }
+ }
}
Page::Hardware => {
let hw = &mut self.app.hardware;
- if hw.cpu_list_box.hit_test(lx, ly) { clicked_any_focusable = true; }
- if hw.cpu_gov_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
- if hw.gpu_gov_menu.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if hw.cpu_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if hw.cpu_gov_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+ if hw.gpu_gov_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
Page::Radios => {
let net = &mut self.app.network;
- if net.wifi_list_box.hit_test(lx, ly) { clicked_any_focusable = true; }
+ if net.wifi_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
}
_ => {}
}
@@ -1698,9 +2266,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Layout {
for (i, sb) in self.app.layout.spinboxes.iter_mut().enumerate() {
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetWidth(
pages::layout::WidthParam::ALL[i],
@@ -1710,49 +2278,49 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
}
let sb = &mut self.app.layout.cascade_offset_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetCascadeOffset(sb.value as u16)
));
}
let sb = &mut self.app.layout.edge_gap_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetEdgeGap(sb.value as u16)
));
}
let sb = &mut self.app.layout.top_gap_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetTopGap(sb.value as u16)
));
}
let sb = &mut self.app.layout.grid_gap_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetGridGap(sb.value as u16)
));
}
let sb = &mut self.app.layout.transition_duration_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetTransitionDuration(sb.value as u16)
));
}
let sb = &mut self.app.layout.status_height_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetStatusHeight(sb.value as u16)
));
@@ -1760,8 +2328,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if self.app.current_page == Page::Layout {
for (idx, menu) in self.app.layout.tag_layout_menus.iter_mut().enumerate() {
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -1769,17 +2337,17 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
}
let menu = &mut self.app.layout.side_panel_behavior_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBehavior(menu.selected)));
}
let sb = &mut self.app.layout.side_panel_width_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetSidePanelWidth(sb.value as u16)
));
@@ -1788,8 +2356,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Interface {
for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
let old = cp.color;
- if !cp.hit_test(lx, ly) { cp.unfocus(); }
- cp.mouse_input(button, state, lx, ly);
+ if !cp.hit_test(lx, ly, &self.ui_context) { cp.unfocus(); }
+ cp.mouse_input(button, state, lx, ly, &mut self.ui_context);
if cp.take_click() {
actions.push(AppAction::Interface(match i {
0 => pages::interface::InterfaceMessage::PickPageLowColor,
@@ -1830,136 +2398,267 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
}
let sb = &mut self.app.interface.tab_margin_spinbox_x;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTabMarginX(sb.value as u16)));
}
let sb = &mut self.app.interface.tab_margin_spinbox_y;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTabMarginY(sb.value as u16)));
}
let sb = &mut self.app.interface.tab_padding_spinbox_x;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTabPaddingX(sb.value as u16)));
}
let sb = &mut self.app.interface.tab_padding_spinbox_y;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTabPaddingY(sb.value as u16)));
}
- }
+ let sb = &mut self.app.interface.section_padding_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionPadding(sb.value as u16)));
+ }
+ let menu = &mut self.app.interface.label_alignment_menu;
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelAlignment(menu.selected)));
+ }
+ let sb = &mut self.app.interface.label_offset_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelOffset(sb.value as i16)));
+ }
+ let sb = &mut self.app.interface.label_margin_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLabelMargin(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.plate_padding_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlatePadding(sb.value as u16)));
+ }
+ let toggle = &mut self.app.interface.graph_show_grid_toggle;
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
+ if toggle.take_click() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphShowGrid(toggle.toggled())));
+ }
+ let toggle = &mut self.app.interface.graph_snap_enabled_toggle;
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
+ if toggle.take_click() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphSnapEnabled(toggle.toggled())));
+ }
+ let toggle = &mut self.app.interface.graph_uniform_background_toggle;
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
+ if toggle.take_click() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphUniformBackground(toggle.toggled())));
+ }
+ let slider = &mut self.app.interface.graph_network_opacity_slider;
+ if button == clear_ui::widget::MouseButton::Left {
+ if state == clear_ui::widget::ElementState::Pressed {
+ if slider.hit_test(lx, ly, &self.ui_context) {
+ slider.drag_begin(lx, ly);
+ self.graph_opacity_dragging = true;
+ self.needs_rebuild = true;
+ }
+ } else if state == clear_ui::widget::ElementState::Released {
+ if self.graph_opacity_dragging {
+ self.graph_opacity_dragging = false;
+ slider.drag_end();
+ let val = slider.value();
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphOpacity(val)));
+ self.needs_rebuild = true;
+ }
+ }
+ }
+ let sb = &mut self.app.interface.page_margin_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.grid_min_col_width_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGridMinColWidth(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.spinbox_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxHeight(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.toggle_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleHeight(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.color_selector_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorHeight(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.color_selector_preview_corner_radius_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewCornerRadius(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.color_selector_preview_margin_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewMargin(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.textbox_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxHeight(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.slider_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSliderHeight(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.font_selector_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorHeight(sb.value as u16)));
+ }
+ let sb = &mut self.app.interface.dropdown_height_spinbox;
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
+ let old = sb.value;
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(sb.value as u16)));
+ }
+ }
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Input {
let sb = &mut self.app.input.rate_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
}
let sb = &mut self.app.input.delay_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
}
let sb = &mut self.app.input.scroll_friction_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollFriction));
}
let sb = &mut self.app.input.scroll_speed_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollSpeed));
}
let sb = &mut self.app.input.pointer_friction_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyPointerFriction));
}
let sb = &mut self.app.input.trackpad_friction_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpadFriction));
}
let sb = &mut self.app.input.trackpoint_accel_speed_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelSpeed));
}
let sb = &mut self.app.input.cursor_size_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorSize));
}
}
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Services {
let sb = &mut self.app.services.notifications_duration_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Services(pages::services::ServicesMessage::SetNotificationsDuration(sb.value)));
}
let sb2 = &mut self.app.services.status_padding_spinbox;
- if !sb2.hit_test(lx, ly) { sb2.unfocus(); }
+ if !sb2.hit_test(lx, ly, &self.ui_context) { sb2.unfocus(); }
let old2 = sb2.value;
- if sb2.mouse_input(button, state, lx, ly) && sb2.value != old2 {
+ if sb2.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb2.value != old2 {
actions.push(AppAction::Services(pages::services::ServicesMessage::StatusSetPadding(sb2.value as u16)));
}
}
if self.app.current_page == Page::Input {
let toggle = &mut self.app.input.tap_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Input(pages::input::InputMessage::ToggleTapToClick));
}
let toggle = &mut self.app.input.scroll_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialScroll));
}
let toggle = &mut self.app.input.natural_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Input(pages::input::InputMessage::ToggleNaturalScroll));
}
let toggle = &mut self.app.input.pointer_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialPointer));
}
let toggle = &mut self.app.input.trackpad_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialTrackpad));
}
let toggle = &mut self.app.input.dwtp_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Input(pages::input::InputMessage::ToggleDwtp));
}
let menu = &mut self.app.input.trackpoint_accel_profile_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelProfile(menu.selected)));
}
let menu = &mut self.app.input.cursor_theme_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -1968,19 +2667,19 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if self.app.current_page == Page::Services {
let toggle = &mut self.app.services.notifications_enable_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Services(pages::services::ServicesMessage::ToggleNotificationsEnable));
}
let toggle = &mut self.app.services.notifications_bell_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Services(pages::services::ServicesMessage::ToggleNotificationsBell));
}
let slider = &mut self.app.services.notifications_opacity_slider;
if button == clear_ui::widget::MouseButton::Left {
if state == clear_ui::widget::ElementState::Pressed {
- if slider.hit_test(lx, ly) {
+ if slider.hit_test(lx, ly, &self.ui_context) {
slider.drag_begin(lx, ly);
self.opacity_dragging = true;
self.needs_rebuild = true;
@@ -1997,40 +2696,36 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if state == clear_ui::widget::ElementState::Pressed {
let lbl1 = &mut self.app.services.status_label;
- if !lbl1.hit_test(lx, ly) { lbl1.unfocus(); }
- lbl1.mouse_input(button, state, lx, ly);
-
- let lbl2 = &mut self.app.services.status_size_label;
- if !lbl2.hit_test(lx, ly) { lbl2.unfocus(); }
- lbl2.mouse_input(button, state, lx, ly);
+ if !lbl1.hit_test(lx, ly, &self.ui_context) { lbl1.unfocus(); }
+ lbl1.mouse_input(button, state, lx, ly, &mut self.ui_context);
}
let toggle = &mut self.app.services.status_separators_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Services(pages::services::ServicesMessage::StatusToggleSeparators));
}
let toggle2 = &mut self.app.services.status_underline_toggle;
- toggle2.mouse_input(button, state, lx, ly);
+ toggle2.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle2.take_click() {
actions.push(AppAction::Services(pages::services::ServicesMessage::StatusToggleUnderline));
}
}
if self.app.current_page == Page::Display {
let toggle = &mut self.app.display.screensaver_enable_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverEnable));
}
let toggle = &mut self.app.display.screensaver_lock_screen_toggle;
- toggle.mouse_input(button, state, lx, ly);
+ toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
if toggle.take_click() {
actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverLockScreen));
}
let menu = &mut self.app.display.screensaver_style_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2039,8 +2734,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if self.app.current_page == Page::Hardware {
let menu = &mut self.app.hardware.cpu_gov_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2052,8 +2747,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let menu = &mut self.app.hardware.gpu_gov_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2066,53 +2761,77 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Audio {
+ if button == clear_ui::widget::MouseButton::Left {
+ for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
+ if slider.hit_test(lx, ly, &self.ui_context) {
+ slider.drag_begin(lx, ly);
+ self.audio_sink_dragging = Some(i);
+ self.needs_rebuild = true;
+ }
+ }
+ for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
+ if slider.hit_test(lx, ly, &self.ui_context) {
+ slider.drag_begin(lx, ly);
+ self.audio_source_dragging = Some(i);
+ self.needs_rebuild = true;
+ }
+ }
+ }
for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
let id = self.app.audio.sinks[i].id;
actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
}
}
for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
let id = self.app.audio.sources[i].id;
actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
}
}
}
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Display {
+ if button == clear_ui::widget::MouseButton::Left {
+ let slider = &mut self.app.display.brightness_slider;
+ if slider.hit_test(lx, ly, &self.ui_context) {
+ slider.drag_begin(lx, ly);
+ self.display_brightness_dragging = true;
+ self.needs_rebuild = true;
+ }
+ }
let sb = &mut self.app.display.brightness_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(sb.value as u32)));
}
let lbl = &mut self.app.display.night_light_label;
- if !lbl.hit_test(lx, ly) { lbl.unfocus(); }
- lbl.mouse_input(button, state, lx, ly);
+ if !lbl.hit_test(lx, ly, &self.ui_context) { lbl.unfocus(); }
+ lbl.mouse_input(button, state, lx, ly, &mut self.ui_context);
for out in &mut self.app.display.outputs {
let lbl = &mut out.name_label;
- if !lbl.hit_test(lx, ly) { lbl.unfocus(); }
- lbl.mouse_input(button, state, lx, ly);
+ if !lbl.hit_test(lx, ly, &self.ui_context) { lbl.unfocus(); }
+ lbl.mouse_input(button, state, lx, ly, &mut self.ui_context);
let lbl2 = &mut out.resolution_label;
- if !lbl2.hit_test(lx, ly) { lbl2.unfocus(); }
- lbl2.mouse_input(button, state, lx, ly);
+ if !lbl2.hit_test(lx, ly, &self.ui_context) { lbl2.unfocus(); }
+ lbl2.mouse_input(button, state, lx, ly, &mut self.ui_context);
if let Some(ref mut scale_lbl) = out.scale_label {
- if !scale_lbl.hit_test(lx, ly) { scale_lbl.unfocus(); }
- scale_lbl.mouse_input(button, state, lx, ly);
+ if !scale_lbl.hit_test(lx, ly, &self.ui_context) { scale_lbl.unfocus(); }
+ scale_lbl.mouse_input(button, state, lx, ly, &mut self.ui_context);
}
}
let sb = &mut self.app.display.screensaver_timeout_spinbox;
- if !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old = sb.value;
- if sb.mouse_input(button, state, lx, ly) && sb.value != old {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(sb.value)));
}
}
@@ -2120,20 +2839,20 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if self.app.current_page == Page::Accounts {
if self.app.accounts.editing_oauth_creds {
let tb = &mut self.app.accounts.oauth_client_id_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
let tb = &mut self.app.accounts.oauth_client_secret_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
} else {
let tb = &mut self.app.accounts.email_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2157,28 +2876,28 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.accounts.password_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
let tb = &mut self.app.accounts.imap_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
let tb = &mut self.app.accounts.smtp_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
}
}
if self.app.current_page == Page::Interface {
let tb = &mut self.app.interface.sans_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2186,8 +2905,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.serif_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2195,8 +2914,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.mono_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2204,8 +2923,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let menu = &mut self.app.interface.borders_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2213,8 +2932,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.borders_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2222,8 +2941,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let menu = &mut self.app.interface.status_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2231,8 +2950,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.status_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2240,8 +2959,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let menu = &mut self.app.interface.fuzzel_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2249,8 +2968,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.fuzzel_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
@@ -2258,8 +2977,8 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let menu = &mut self.app.interface.terminal_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
+ if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
@@ -2267,45 +2986,58 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.terminal_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminal(tb.text.clone())));
}
- let menu = &mut self.app.interface.paginator_menu;
- if state == clear_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly) { menu.unfocus(); }
- if menu.mouse_input(button, state, lx, ly) {
+
+
+
+
+ let fs = &mut self.app.interface.color_selector_font_selector;
+ if state == clear_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
+ if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
- if state == clear_ui::widget::ElementState::Pressed && menu.take_change() {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPaginatorMenu(menu.selected)));
+ if fs.take_change() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorFont(fs.font_family.clone())));
}
- let tb = &mut self.app.interface.paginator_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ let fs = &mut self.app.interface.menubar_font_selector;
+ if state == clear_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
+ if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
- if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPaginator(tb.text.clone())));
+ if fs.take_change() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarFont(fs.font_family.clone())));
}
- let tb = &mut self.app.interface.search_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ let fs = &mut self.app.interface.section_label_font_selector;
+ if state == clear_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
+ if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
- if state == clear_ui::widget::ElementState::Pressed && tb.take_change() {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSearch(tb.text.clone())));
+ if fs.take_change() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionLabelFont(fs.font_family.clone())));
+ }
+
+ let fs = &mut self.app.interface.nested_section_label_font_selector;
+ if state == clear_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
+ if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ if fs.take_change() {
+ actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelFont(fs.font_family.clone())));
}
let sb = &mut self.app.interface.borders_size_box;
- if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old_val = sb.value;
- if sb.mouse_input(button, state, lx, ly) {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if sb.value != old_val {
@@ -2313,9 +3045,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.status_size_box;
- if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old_val = sb.value;
- if sb.mouse_input(button, state, lx, ly) {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if sb.value != old_val {
@@ -2323,9 +3055,9 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.fuzzel_size_box;
- if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old_val = sb.value;
- if sb.mouse_input(button, state, lx, ly) {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if sb.value != old_val {
@@ -2333,77 +3065,27 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.terminal_size_box;
- if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly) { sb.unfocus(); }
+ if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
let old_val = sb.value;
- if sb.mouse_input(button, state, lx, ly) {
+ if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
if sb.value != old_val {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalSize(sb.value)));
}
- let sb = &mut self.app.interface.paginator_size_box;
- if state == clear_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly) { sb.unfocus(); }
- let old_val = sb.value;
- if sb.mouse_input(button, state, lx, ly) {
- self.needs_rebuild = true;
- }
- if sb.value != old_val {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPaginatorSize(sb.value)));
- }
- let tf = &mut self.app.interface;
- let query = tf.search_box.text.to_lowercase();
- let matching_fonts: Vec<String> = tf.all_fonts.iter()
- .filter(|font| font.to_lowercase().contains(&query))
- .cloned()
- .collect();
- let mut clicked_idx = None;
- let mut is_copy = false;
- for (i, btn) in tf.font_buttons.iter_mut().enumerate() {
- if btn.mouse_input(button, state, lx, ly) {
- self.needs_rebuild = true;
- }
- if btn.take_click() {
- clicked_idx = Some(i);
- is_copy = false;
- }
- }
- for (i, btn) in tf.copy_buttons.iter_mut().enumerate() {
- if btn.mouse_input(button, state, lx, ly) {
- self.needs_rebuild = true;
- }
- if btn.take_click() {
- clicked_idx = Some(i);
- is_copy = true;
- }
- }
-
- if let Some(idx) = clicked_idx {
- if let Some(font_name) = matching_fonts.get(idx) {
- let action = if is_copy {
- AppAction::Interface(pages::interface::InterfaceMessage::CopyFontName(font_name.clone()))
- } else {
- AppAction::Interface(pages::interface::InterfaceMessage::SelectFont(font_name.clone()))
- };
- actions.push(action);
- }
- }
-
- if tf.list_box.mouse_input(button, state, lx, ly) {
- self.needs_rebuild = true;
- }
}
if self.app.current_page == Page::Services {
let tb = &mut self.app.services.search_box;
- if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly) { tb.unfocus(); }
- if tb.mouse_input(button, state, lx, ly) {
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
let srv = &mut self.app.services;
- if srv.list_box.mouse_input(button, state, lx, ly) {
+ if srv.list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
let query = if srv.search_box.editing {
@@ -2416,20 +3098,78 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
.filter(|s| s.name.to_lowercase().contains(&query) || s.description.to_lowercase().contains(&query))
.count();
for i in 0..matching_count.min(srv.service_items.len()) {
- if srv.service_items[i].mouse_input(button, state, lx, ly) {
+ if srv.service_items[i].mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
}
}
+ if self.app.current_page == Page::Packages {
+ let pkgs = &mut self.app.packages;
+ let tb = &mut pkgs.search_box;
+ if state == clear_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) {
+ tb.unfocus();
+ }
+ if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ match pkgs.active_tab {
+ pages::packages::PackageTab::Installed => {
+ if pkgs.installed_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ let query = if pkgs.search_box.editing {
+ pkgs.search_box.edit_buffer.to_lowercase()
+ } else {
+ pkgs.search_box.text.to_lowercase()
+ };
+ let filtered: Vec<&pages::packages::PackageInfo> = pkgs.installed.iter()
+ .filter(|p| p.name.to_lowercase().contains(&query) || p.version.to_lowercase().contains(&query))
+ .collect();
+ let matching = filtered.len();
+ for i in 0..matching.min(pkgs.installed_items.len()) {
+ if pkgs.installed_items[i].mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ if pkgs.installed_items[i].take_click() {
+ let pkg_name = filtered[i].name.clone();
+ actions.push(AppAction::Packages(pages::packages::PackagesMessage::SelectPackage(Some(pkg_name))));
+ }
+ }
+ }
+ pages::packages::PackageTab::Updates => {
+ if pkgs.updates_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ let query = if pkgs.search_box.editing {
+ pkgs.search_box.edit_buffer.to_lowercase()
+ } else {
+ pkgs.search_box.text.to_lowercase()
+ };
+ let filtered: Vec<&pages::packages::UpdateInfo> = pkgs.updates.iter()
+ .filter(|p| p.name.to_lowercase().contains(&query))
+ .collect();
+ let matching = filtered.len();
+ for i in 0..matching.min(pkgs.updates_items.len()) {
+ if pkgs.updates_items[i].mouse_input(button, state, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ }
+ if pkgs.updates_items[i].take_click() {
+ let pkg_name = filtered[i].name.clone();
+ actions.push(AppAction::Packages(pages::packages::PackagesMessage::SelectPackage(Some(pkg_name))));
+ }
+ }
+ }
+ }
+ }
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Hardware {
let hw = &mut self.app.hardware;
- if hw.cpu_list_box.mouse_input(button, state, lx, ly) {
+ if hw.cpu_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
}
if state == clear_ui::widget::ElementState::Pressed && self.app.current_page == Page::Radios {
let net = &mut self.app.network;
- if net.wifi_list_box.mouse_input(button, state, lx, ly) {
+ if net.wifi_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
}
}
@@ -2456,35 +3196,148 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if self.app.current_page == Page::Input {
let input = &self.app.input;
- if input.is_over_trackpad(lx, ly) {
+ if input.is_over_trackpad(lx, ly, &self.ui_context) {
return true;
}
}
-
- if self.app.current_page == Page::Interface {
- let tf = &mut self.app.interface;
- if tf.list_box.mouse_wheel(delta, lx, ly) {
+ if self.app.current_page == Page::Audio {
+ let mut actions = Vec::new();
+ for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
+ let old = sb.value;
+ if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ if sb.value != old {
+ let id = self.app.audio.sinks[i].id;
+ actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
+ }
+ }
+ }
+ for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
+ let old = sb.value;
+ if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ if sb.value != old {
+ let id = self.app.audio.sources[i].id;
+ actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
+ }
+ }
+ }
+ for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
+ let old = slider.value();
+ if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ let new_val = slider.value();
+ if new_val != old {
+ let id = self.app.audio.sinks[i].id;
+ if i < self.app.audio.sink_spinboxes.len() {
+ self.app.audio.sink_spinboxes[i].value = (new_val * 100.0).round() as i32;
+ }
+ actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, new_val)));
+ }
+ }
+ }
+ for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
+ let old = slider.value();
+ if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ let new_val = slider.value();
+ if new_val != old {
+ let id = self.app.audio.sources[i].id;
+ if i < self.app.audio.source_spinboxes.len() {
+ self.app.audio.source_spinboxes[i].value = (new_val * 100.0).round() as i32;
+ }
+ actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, new_val)));
+ }
+ }
+ }
+ for a in &actions {
+ self.handle_action(a);
+ }
+ if !actions.is_empty() {
self.needs_rebuild = true;
return true;
}
}
+
+ if self.app.current_page == Page::Display {
+ let mut actions = Vec::new();
+ let slider = &mut self.app.display.brightness_slider;
+ let old_val = slider.value();
+ if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ let new_val = slider.value();
+ if new_val != old_val {
+ let pct = (new_val * 100.0).round() as u32;
+ self.app.display.brightness_spinbox.value = pct as i32;
+ actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(pct)));
+ }
+ }
+ let sb = &mut self.app.display.brightness_spinbox;
+ let old = sb.value;
+ if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ if sb.value != old {
+ actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(sb.value as u32)));
+ }
+ }
+ let sb2 = &mut self.app.display.screensaver_timeout_spinbox;
+ let old2 = sb2.value;
+ if sb2.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ if sb2.value != old2 {
+ actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(sb2.value)));
+ }
+ }
+ for a in &actions {
+ self.handle_action(a);
+ }
+ if !actions.is_empty() {
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+
+
+ if self.app.current_page == Page::Interface {
+ let slider = &mut self.app.interface.graph_network_opacity_slider;
+ let old_val = slider.value();
+ if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ let new_val = slider.value();
+ if new_val != old_val {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetGraphOpacity(new_val)));
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+ }
+
if self.app.current_page == Page::Services {
let srv = &mut self.app.services;
- if srv.list_box.mouse_wheel(delta, lx, ly) {
+ if srv.list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
}
+ if self.app.current_page == Page::Packages {
+ let pkgs = &mut self.app.packages;
+ match pkgs.active_tab {
+ pages::packages::PackageTab::Installed => {
+ if pkgs.installed_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+ pages::packages::PackageTab::Updates => {
+ if pkgs.updates_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+ }
+ }
if self.app.current_page == Page::Hardware {
let hw = &mut self.app.hardware;
- if hw.cpu_list_box.mouse_wheel(delta, lx, ly) {
+ if hw.cpu_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
}
if self.app.current_page == Page::Radios {
let net = &mut self.app.network;
- if net.wifi_list_box.mouse_wheel(delta, lx, ly) {
+ if net.wifi_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
@@ -2504,7 +3357,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
} else {
let lx = px / s;
let ly = py / s;
- if self.paginator.mouse_wheel(delta, lx, ly) {
+ if self.paginator.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
@@ -2558,7 +3411,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let mut actions = Vec::new();
for (i, sb) in self.app.layout.spinboxes.iter_mut().enumerate() {
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetWidth(
@@ -2572,7 +3425,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.cascade_offset_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetCascadeOffset(sb.value as u16)
@@ -2582,7 +3435,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.edge_gap_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetEdgeGap(sb.value as u16)
@@ -2592,7 +3445,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.top_gap_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetTopGap(sb.value as u16)
@@ -2602,7 +3455,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.grid_gap_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetGridGap(sb.value as u16)
@@ -2612,7 +3465,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.transition_duration_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetTransitionDuration(sb.value as u16)
@@ -2622,7 +3475,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.status_height_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetStatusHeight(sb.value as u16)
@@ -2633,7 +3486,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let (menu_changed, old_selected, new_selected) = {
let menu = &mut self.app.layout.side_panel_behavior_menu;
let old = menu.selected;
- let changed = menu.keyboard_input(event);
+ let changed = menu.keyboard_input(event, &mut self.ui_context);
(changed, old, menu.selected)
};
if menu_changed {
@@ -2644,7 +3497,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.layout.side_panel_width_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
actions.push(AppAction::Layout(
pages::layout::LayoutMessage::SetSidePanelWidth(sb.value as u16)
@@ -2665,7 +3518,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let mut actions = Vec::new();
for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
let old = cp.color;
- if cp.keyboard_input(event) {
+ if cp.keyboard_input(event, &mut self.ui_context) {
if cp.color != old {
actions.push(AppAction::Interface(match i {
0 => pages::interface::InterfaceMessage::SetPageLowColor(cp.color),
@@ -2697,7 +3550,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.tab_margin_spinbox_x;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTabMarginX(new_val as u16)));
@@ -2707,7 +3560,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.tab_margin_spinbox_y;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTabMarginY(new_val as u16)));
@@ -2717,7 +3570,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.tab_padding_spinbox_x;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTabPaddingX(new_val as u16)));
@@ -2727,7 +3580,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.interface.tab_padding_spinbox_y;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTabPaddingY(new_val as u16)));
@@ -2735,109 +3588,178 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
self.needs_rebuild = true;
return true;
}
-
- if event.state == clear_ui::widget::ElementState::Pressed {
- let is_down = match (&event.logical_key, event.ctrl) {
- (clear_ui::widget::Key::Character(c), true) if c == "n" || c == "N" => true,
- (clear_ui::widget::Key::Named(clear_ui::widget::NamedKey::ArrowDown), false) => true,
- _ => false,
- };
- let is_up = match (&event.logical_key, event.ctrl) {
- (clear_ui::widget::Key::Character(c), true) if c == "p" || c == "P" => true,
- (clear_ui::widget::Key::Named(clear_ui::widget::NamedKey::ArrowUp), false) => true,
- _ => false,
- };
- if is_down && clear_ui::widget::focus::is_focused(&self.app.interface.list_box.scroll_box) {
- let next_idx_font_scroll = {
- let tf = &self.app.interface;
- let query = tf.search_box.text.to_lowercase();
- let matching_fonts: Vec<&String> = tf.all_fonts.iter()
- .filter(|font| font.to_lowercase().contains(&query))
- .collect();
- if !matching_fonts.is_empty() {
- let current_idx = tf.selected_font.as_ref()
- .and_then(|f| matching_fonts.iter().position(|&x| x == f));
- let next_idx = match current_idx {
- Some(idx) => (idx + 1).min(matching_fonts.len() - 1),
- None => 0,
- };
- let font = matching_fonts[next_idx].clone();
-
- // Compute scroll
- let btn_h = 24.0;
- let btn_gap = 4.0;
- let item_height_full = btn_h + btn_gap;
- let item_y = next_idx as f32 * item_height_full;
- let list_box_h = 320.0;
-
- let mut scroll_y = tf.list_box.scroll_y();
- if item_y < scroll_y {
- scroll_y = item_y;
- } else if item_y + btn_h > scroll_y + list_box_h {
- scroll_y = item_y + btn_h - list_box_h;
- }
- Some((font, scroll_y))
- } else {
- None
- }
- };
-
- if let Some((font, scroll_y)) = next_idx_font_scroll {
- self.app.interface.list_box.set_scroll_y(scroll_y);
- self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SelectFont(font)));
- self.needs_rebuild = true;
- return true;
- }
- } else if is_up && clear_ui::widget::focus::is_focused(&self.app.interface.list_box.scroll_box) {
- let next_idx_font_scroll = {
- let tf = &self.app.interface;
- let query = tf.search_box.text.to_lowercase();
- let matching_fonts: Vec<&String> = tf.all_fonts.iter()
- .filter(|font| font.to_lowercase().contains(&query))
- .collect();
- if !matching_fonts.is_empty() {
- let current_idx = tf.selected_font.as_ref()
- .and_then(|f| matching_fonts.iter().position(|&x| x == f));
- let next_idx = match current_idx {
- Some(idx) => idx.saturating_sub(1),
- None => 0,
- };
- let font = matching_fonts[next_idx].clone();
-
- // Compute scroll
- let btn_h = 24.0;
- let btn_gap = 4.0;
- let item_height_full = btn_h + btn_gap;
- let item_y = next_idx as f32 * item_height_full;
- let list_box_h = 320.0;
-
- let mut scroll_y = tf.list_box.scroll_y();
- if item_y < scroll_y {
- scroll_y = item_y;
- } else if item_y + btn_h > scroll_y + list_box_h {
- scroll_y = item_y + btn_h - list_box_h;
- }
- Some((font, scroll_y))
- } else {
- None
- }
- };
-
- if let Some((font, scroll_y)) = next_idx_font_scroll {
- self.app.interface.list_box.set_scroll_y(scroll_y);
- self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SelectFont(font)));
- self.needs_rebuild = true;
- return true;
- }
+ let sb = &mut self.app.interface.section_padding_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSectionPadding(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let (menu_changed, old_selected, new_selected) = {
+ let menu = &mut self.app.interface.label_alignment_menu;
+ let old = menu.selected;
+ let changed = menu.keyboard_input(event, &mut self.ui_context);
+ (changed, old, menu.selected)
+ };
+ if menu_changed {
+ if new_selected != old_selected {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelAlignment(new_selected)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.label_offset_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelOffset(new_val as i16)));
}
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.label_margin_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetLabelMargin(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.plate_padding_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPlatePadding(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.page_margin_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.grid_min_col_width_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetGridMinColWidth(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.spinbox_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.toggle_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetToggleHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.color_selector_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.color_selector_preview_corner_radius_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewCornerRadius(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.color_selector_preview_margin_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewMargin(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.textbox_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.slider_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSliderHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.font_selector_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
+ let sb = &mut self.app.interface.dropdown_height_spinbox;
+ let old = sb.value;
+ if sb.keyboard_input(event, &mut self.ui_context) {
+ let new_val = sb.value;
+ if new_val != old {
+ self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(new_val as u16)));
+ }
+ self.needs_rebuild = true;
+ return true;
}
+
+
let mut actions = Vec::new();
let mut consumed = false;
let tf = &mut self.app.interface;
let tb = &mut tf.sans_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSans(tb.text.clone())));
}
@@ -2845,7 +3767,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.serif_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSerif(tb.text.clone())));
}
@@ -2853,7 +3775,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.mono_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMono(tb.text.clone())));
}
@@ -2861,7 +3783,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.borders_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBorders(tb.text.clone())));
}
@@ -2869,7 +3791,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.status_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatus(tb.text.clone())));
}
@@ -2877,7 +3799,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.fuzzel_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzel(tb.text.clone())));
}
@@ -2885,58 +3807,42 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let tb = &mut self.app.interface.terminal_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
if tb.take_change() {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminal(tb.text.clone())));
}
consumed = true;
}
- let tb = &mut self.app.interface.paginator_box;
- if tb.keyboard_input(event) {
- if tb.take_change() {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPaginator(tb.text.clone())));
- }
- consumed = true;
- }
- let tb = &mut self.app.interface.search_box;
- if tb.keyboard_input(event) {
- if tb.take_change() {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSearch(tb.text.clone())));
- }
- consumed = true;
- }
+
+
let sb = &mut self.app.interface.borders_size_box;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersSize(sb.value)));
consumed = true;
}
let sb = &mut self.app.interface.status_size_box;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusSize(sb.value)));
consumed = true;
}
let sb = &mut self.app.interface.fuzzel_size_box;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzelSize(sb.value)));
consumed = true;
}
let sb = &mut self.app.interface.terminal_size_box;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalSize(sb.value)));
consumed = true;
}
- let sb = &mut self.app.interface.paginator_size_box;
- if sb.keyboard_input(event) {
- actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPaginatorSize(sb.value)));
- consumed = true;
- }
+
for a in &actions {
self.handle_action(a);
@@ -2949,7 +3855,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if self.app.current_page == Page::Services {
let sb = &mut self.app.services.notifications_duration_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Services(pages::services::ServicesMessage::SetNotificationsDuration(new_val)));
@@ -2959,7 +3865,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.services.status_padding_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Services(pages::services::ServicesMessage::StatusSetPadding(new_val as u16)));
@@ -2969,42 +3875,42 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
}
if self.app.current_page == Page::Input {
- if self.app.input.rate_spinbox.keyboard_input(event) {
+ if self.app.input.rate_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyRepeat));
self.needs_rebuild = true;
return true;
}
- if self.app.input.delay_spinbox.keyboard_input(event) {
+ if self.app.input.delay_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyRepeat));
self.needs_rebuild = true;
return true;
}
- if self.app.input.scroll_friction_spinbox.keyboard_input(event) {
+ if self.app.input.scroll_friction_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyScrollFriction));
self.needs_rebuild = true;
return true;
}
- if self.app.input.scroll_speed_spinbox.keyboard_input(event) {
+ if self.app.input.scroll_speed_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyScrollSpeed));
self.needs_rebuild = true;
return true;
}
- if self.app.input.pointer_friction_spinbox.keyboard_input(event) {
+ if self.app.input.pointer_friction_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyPointerFriction));
self.needs_rebuild = true;
return true;
}
- if self.app.input.trackpad_friction_spinbox.keyboard_input(event) {
+ if self.app.input.trackpad_friction_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyTrackpadFriction));
self.needs_rebuild = true;
return true;
}
- if self.app.input.trackpoint_accel_speed_spinbox.keyboard_input(event) {
+ if self.app.input.trackpoint_accel_speed_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelSpeed));
self.needs_rebuild = true;
return true;
}
- if self.app.input.cursor_size_spinbox.keyboard_input(event) {
+ if self.app.input.cursor_size_spinbox.keyboard_input(event, &mut self.ui_context) {
self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyCursorSize));
self.needs_rebuild = true;
return true;
@@ -3014,12 +3920,12 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let mut consumed = false;
if self.app.accounts.editing_oauth_creds {
let tb = &mut self.app.accounts.oauth_client_id_box;
- if tb.keyboard_input(event) { consumed = true; }
+ if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
let tb = &mut self.app.accounts.oauth_client_secret_box;
- if tb.keyboard_input(event) { consumed = true; }
+ if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
} else {
let tb = &mut self.app.accounts.email_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
consumed = true;
let email_val = tb.edit_buffer.trim().to_lowercase();
if email_val.ends_with("@gmail.com") {
@@ -3040,11 +3946,11 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
}
let tb = &mut self.app.accounts.password_box;
- if tb.keyboard_input(event) { consumed = true; }
+ if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
let tb = &mut self.app.accounts.imap_box;
- if tb.keyboard_input(event) { consumed = true; }
+ if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
let tb = &mut self.app.accounts.smtp_box;
- if tb.keyboard_input(event) { consumed = true; }
+ if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
}
if consumed {
@@ -3056,7 +3962,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let mut actions = Vec::new();
for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
let id = self.app.audio.sinks[i].id;
actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
@@ -3065,13 +3971,39 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
if sb.value != old {
let id = self.app.audio.sources[i].id;
actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
}
}
}
+ for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
+ let old = slider.value();
+ if slider.keyboard_input(event, &mut self.ui_context) {
+ let new_val = slider.value();
+ if new_val != old {
+ let id = self.app.audio.sinks[i].id;
+ if i < self.app.audio.sink_spinboxes.len() {
+ self.app.audio.sink_spinboxes[i].value = (new_val * 100.0).round() as i32;
+ }
+ actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, new_val)));
+ }
+ }
+ }
+ for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
+ let old = slider.value();
+ if slider.keyboard_input(event, &mut self.ui_context) {
+ let new_val = slider.value();
+ if new_val != old {
+ let id = self.app.audio.sources[i].id;
+ if i < self.app.audio.source_spinboxes.len() {
+ self.app.audio.source_spinboxes[i].value = (new_val * 100.0).round() as i32;
+ }
+ actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, new_val)));
+ }
+ }
+ }
for a in &actions {
self.handle_action(a);
}
@@ -3081,9 +4013,21 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
}
if self.app.current_page == Page::Display {
+ let slider = &mut self.app.display.brightness_slider;
+ let old_slider = slider.value();
+ if slider.keyboard_input(event, &mut self.ui_context) {
+ let new_slider = slider.value();
+ if new_slider != old_slider {
+ let pct = (new_slider * 100.0).round() as u32;
+ self.app.display.brightness_spinbox.value = pct as i32;
+ self.handle_action(&AppAction::Display(pages::display::DisplayMessage::BrightnessSet(pct)));
+ }
+ self.needs_rebuild = true;
+ return true;
+ }
let sb = &mut self.app.display.brightness_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Display(pages::display::DisplayMessage::BrightnessSet(new_val as u32)));
@@ -3093,7 +4037,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
let sb = &mut self.app.display.screensaver_timeout_spinbox;
let old = sb.value;
- if sb.keyboard_input(event) {
+ if sb.keyboard_input(event, &mut self.ui_context) {
let new_val = sb.value;
if new_val != old {
self.handle_action(&AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(new_val)));
@@ -3104,7 +4048,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let (menu_changed, old_selected, new_selected) = {
let menu = &mut self.app.display.screensaver_style_menu;
let old = menu.selected;
- let changed = menu.keyboard_input(event);
+ let changed = menu.keyboard_input(event, &mut self.ui_context);
(changed, old, menu.selected)
};
if menu_changed {
@@ -3119,12 +4063,35 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
if self.app.current_page == Page::Services {
let srv = &mut self.app.services;
- if srv.list_box.keyboard_input(event) {
+ if srv.list_box.keyboard_input(event, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
let tb = &mut srv.search_box;
- if tb.keyboard_input(event) {
+ if tb.keyboard_input(event, &mut self.ui_context) {
+ tb.take_change();
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+ if self.app.current_page == Page::Packages {
+ let pkgs = &mut self.app.packages;
+ match pkgs.active_tab {
+ pages::packages::PackageTab::Installed => {
+ if pkgs.installed_list_box.keyboard_input(event, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+ pages::packages::PackageTab::Updates => {
+ if pkgs.updates_list_box.keyboard_input(event, &mut self.ui_context) {
+ self.needs_rebuild = true;
+ return true;
+ }
+ }
+ }
+ let tb = &mut pkgs.search_box;
+ if tb.keyboard_input(event, &mut self.ui_context) {
tb.take_change();
self.needs_rebuild = true;
return true;
@@ -3132,14 +4099,14 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if self.app.current_page == Page::Hardware {
let hw = &mut self.app.hardware;
- if hw.cpu_list_box.keyboard_input(event) {
+ if hw.cpu_list_box.keyboard_input(event, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
let (cpu_changed, old_cpu, new_cpu) = {
let menu = &mut hw.cpu_gov_menu;
let old = menu.selected;
- let changed = menu.keyboard_input(event);
+ let changed = menu.keyboard_input(event, &mut self.ui_context);
(changed, old, menu.selected)
};
if cpu_changed {
@@ -3156,7 +4123,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
let (gpu_changed, old_gpu, new_gpu) = {
let menu = &mut hw.gpu_gov_menu;
let old = menu.selected;
- let changed = menu.keyboard_input(event);
+ let changed = menu.keyboard_input(event, &mut self.ui_context);
(changed, old, menu.selected)
};
if gpu_changed {
@@ -3173,7 +4140,7 @@ fn collect_popover_rects(w: &dyn clear_ui::widget::Element, popovers: &mut Vec<(
}
if self.app.current_page == Page::Radios {
let net = &mut self.app.network;
- if net.wifi_list_box.keyboard_input(event) {
+ if net.wifi_list_box.keyboard_input(event, &mut self.ui_context) {
self.needs_rebuild = true;
return true;
}
@@ -3190,7 +4157,7 @@ fn main() {
let mut initial_page = Page::ALL[0];
// Try to load last_page from config
- let config_path = "/home/lsgalante/.config/ccec/config.toml";
+ let config_path = "/home/lsgalante/.config/cce/config.toml";
if let Ok(content) = std::fs::read_to_string(config_path) {
for line in content.lines() {
let trimmed = line.trim();
diff --git a/src/pages/accounts.rs b/src/pages/accounts.rs
index 1e75bce..d65b476 100644
--- a/src/pages/accounts.rs
+++ b/src/pages/accounts.rs
@@ -83,7 +83,7 @@ pub enum AccountsMessage {
}
pub fn get_accounts_path() -> std::path::PathBuf {
- let p = std::path::PathBuf::from("/home/lsgalante/.config/ccec");
+ let p = std::path::PathBuf::from("/home/lsgalante/.config/cce");
if !p.exists() {
let _ = std::fs::create_dir_all(&p);
#[cfg(unix)]
@@ -155,7 +155,7 @@ pub struct GoogleClientConfig {
}
pub fn load_google_client_config() -> GoogleClientConfig {
- let p = std::path::PathBuf::from("/home/lsgalante/.config/ccec/google_client.json");
+ let p = std::path::PathBuf::from("/home/lsgalante/.config/cce/google_client.json");
if p.exists() {
if let Ok(content) = std::fs::read_to_string(&p) {
if let Ok(config) = serde_json::from_str::<GoogleClientConfig>(&content) {
@@ -303,7 +303,7 @@ pub async fn exchange_code_for_tokens(code: String, sender: calloop::channel::Se
const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(2);
@@ -316,7 +316,7 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
} else {
let row_h = 28.0;
let row_gap = 8.0;
- let item_w = sec_w - 40.0;
+ 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);
@@ -411,7 +411,7 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
// ── Modify Accounts Section ──
builder.add_section(&mut final_pc, "Modify Accounts", false, |sec_modify| {
- let item_w = sec_w - 40.0;
+ let item_w = sec_modify.cw - 2.0 * (sec_modify.padding() + 12.0);
let row_h = 28.0;
let rx = sec_modify.left;
@@ -428,22 +428,22 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
// 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);
+ 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);
+ 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);
+ 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);
+ sec_modify.widget(&mut state.smtp_box, 12.0, item_w, widget_h, ctx);
sec_modify.spacing(field_gap);
let helper_w = (item_w - 8.0) / 2.0;
@@ -508,12 +508,12 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
// 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);
+ 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);
+ 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 - 8.0) / 2.0;
@@ -565,7 +565,7 @@ pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, layou
"Click to Login (Browser)",
sec_modify.ax(12.0),
sec_modify.ay(),
- 200.0,
+ item_w,
row_h,
[0.15, 0.15, 0.25, 1.0],
[0.25, 0.25, 0.35, 1.0],
@@ -722,7 +722,7 @@ pub fn update(state: &mut AccountsState, msg: AccountsMessage) {
client_id,
client_secret,
};
- let p = std::path::PathBuf::from("/home/lsgalante/.config/ccec/google_client.json");
+ let p = std::path::PathBuf::from("/home/lsgalante/.config/cce/google_client.json");
if let Some(parent) = p.parent() {
let _ = std::fs::create_dir_all(parent);
}
diff --git a/src/pages/audio.rs b/src/pages/audio.rs
index 7f49f26..475db53 100644
--- a/src/pages/audio.rs
+++ b/src/pages/audio.rs
@@ -1,6 +1,6 @@
use crate::app::{AppAction, PageContent, SectionContextExt};
use clear_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
-use clear_ui::widget::{Spinbox, Element};
+use clear_ui::widget::{Spinbox, Slider, Element};
#[derive(Debug, Clone)]
pub struct AudioSink {
@@ -27,6 +27,8 @@ pub struct AudioState {
pub sources: Vec<AudioSource>,
pub sink_spinboxes: Vec<Spinbox>,
pub source_spinboxes: Vec<Spinbox>,
+ pub sink_sliders: Vec<Slider>,
+ pub source_sliders: Vec<Slider>,
}
#[derive(Debug, Clone)]
@@ -118,7 +120,15 @@ pub async fn fetch_audio_state() -> AudioState {
let connected = drm_connected_ports();
let sinks = fetch_sinks(&connected).await;
let sources = fetch_sources(&connected).await;
- AudioState { loaded: true, sinks, sources, sink_spinboxes: Vec::new(), source_spinboxes: Vec::new() }
+ AudioState {
+ loaded: true,
+ sinks,
+ sources,
+ sink_spinboxes: Vec::new(),
+ source_spinboxes: Vec::new(),
+ sink_sliders: Vec::new(),
+ source_sliders: Vec::new(),
+ }
}
async fn fetch_sinks(connected_ports: &[String]) -> Vec<AudioSink> {
@@ -207,7 +217,7 @@ const FILL_BAR: [f32; 4] = [0.30, 0.50, 0.32, 1.0];
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.33, 0.33, 1.0];
-pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(2);
@@ -224,30 +234,32 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
if state.loaded {
for (idx, sink) in state.sinks.iter().enumerate() {
- let label = if !sink.active {
- format!("{} (inactive)", sink.name)
- } else if sink.muted {
- format!("{} {:.0}% (muted)", sink.name, sink.volume * 100.0)
+ if !sink.active {
+ let label = format!("{} (inactive)", sink.name);
+ let lc = if sink.muted { RED } else { TEXT_FG };
+ sec.text(&label, 14.0, 0.0, 13.0, lc);
+ sec.spacing(18.0);
} else {
- format!("{} {:.0}%", sink.name, sink.volume * 100.0)
- };
- let lc = if sink.muted { RED } else { TEXT_FG };
- sec.text(&label, 14.0, 0.0, 13.0, lc);
- sec.spacing(18.0);
+ let label = if sink.muted {
+ format!("{} {:.0}% (muted)", sink.name, sink.volume * 100.0)
+ } else {
+ format!("{} {:.0}%", sink.name, sink.volume * 100.0)
+ };
+ state.sink_sliders[idx].set_label(&label);
- if sink.active {
let bar_w = sec_w - 100.0;
let bar_x = 14.0;
let yt = sec.ay();
- let usage_bar_x = sec.ax(bar_x);
- let mut usage_bar = clear_ui::widget::UsageBar::new(sink.volume)
- .with_colors(FILL_BAR, BLANK_BAR);
- render_widget(sec.pc, &mut usage_bar, usage_bar_x, yt, bar_w, 8.0);
- sec.text(&format!("{:.0}%", sink.volume * 100.0), bar_x + bar_w + 8.0, -2.0, 11.0, TEXT_DIM);
-
- let row_y = sec.ay() + 12.0;
+ state.sink_sliders[idx].set_value(sink.volume);
+ let slider_x = sec.ax(bar_x);
+
+ let label_h = clear_ui::widget::label_offset(&state.sink_sliders[idx]);
+ let slider_h = clear_ui::layout::slider_height() + label_h;
+ render_widget(sec.pc, &mut state.sink_sliders[idx], slider_x, yt, bar_w, slider_h, ctx);
+
+ let row_y = sec.ay() + slider_h + 8.0;
let sb_w = 100.0;
- let sb_h = 26.0;
+ let sb_h = clear_ui::layout::spinbox_height();
let mute_w = 60.0;
let gap = 8.0;
@@ -255,7 +267,7 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
state.sink_spinboxes[idx].value = (sink.volume * 100.0).round() as i32;
state.sink_spinboxes[idx].set_row_rect(row_rect_x, sec_w - 16.0);
let sb_x = sec.ax(bar_x);
- render_widget(sec.pc, &mut state.sink_spinboxes[idx], sb_x, row_y, sb_w, sb_h);
+ render_widget(sec.pc, &mut state.sink_spinboxes[idx], sb_x, row_y, sb_w, sb_h, ctx);
let mute_label = if sink.muted { "Unmute" } else { "Mute" };
let mute_col = if sink.muted { MUTED_BG } else { BTN_INACTIVE };
@@ -264,9 +276,7 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
mute_col, BTN_HOVER, WHITE,
AppAction::Audio(AudioMessage::SinkMute(sink.id)));
- sec.content_y += 12.0 + sb_h + 6.0;
- } else {
- sec.content_y += 6.0;
+ sec.content_y += slider_h + 8.0 + sb_h + 6.0;
}
}
}
@@ -284,30 +294,32 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
if state.loaded {
for (idx, src) in state.sources.iter().enumerate() {
- let label = if !src.active {
- format!("{} (inactive)", src.name)
- } else if src.muted {
- format!("{} {:.0}% (muted)", src.name, src.volume * 100.0)
+ if !src.active {
+ let label = format!("{} (inactive)", src.name);
+ let lc = if src.muted { RED } else { TEXT_FG };
+ sec.text(&label, 14.0, 0.0, 13.0, lc);
+ sec.spacing(18.0);
} else {
- format!("{} {:.0}%", src.name, src.volume * 100.0)
- };
- let lc = if src.muted { RED } else { TEXT_FG };
- sec.text(&label, 14.0, 0.0, 13.0, lc);
- sec.spacing(18.0);
+ let label = if src.muted {
+ format!("{} {:.0}% (muted)", src.name, src.volume * 100.0)
+ } else {
+ format!("{} {:.0}%", src.name, src.volume * 100.0)
+ };
+ state.source_sliders[idx].set_label(&label);
- if src.active {
let bar_w = sec_w - 100.0;
let bar_x = 14.0;
let yt = sec.ay();
- let usage_bar_x = sec.ax(bar_x);
- let mut usage_bar = clear_ui::widget::UsageBar::new(src.volume)
- .with_colors(FILL_BAR, BLANK_BAR);
- render_widget(sec.pc, &mut usage_bar, usage_bar_x, yt, bar_w, 8.0);
- sec.text(&format!("{:.0}%", src.volume * 100.0), bar_x + bar_w + 8.0, -2.0, 11.0, TEXT_DIM);
-
- let row_y = sec.ay() + 12.0;
+ state.source_sliders[idx].set_value(src.volume);
+ let slider_x = sec.ax(bar_x);
+
+ let label_h = clear_ui::widget::label_offset(&state.source_sliders[idx]);
+ let slider_h = clear_ui::layout::slider_height() + label_h;
+ render_widget(sec.pc, &mut state.source_sliders[idx], slider_x, yt, bar_w, slider_h, ctx);
+
+ let row_y = sec.ay() + slider_h + 8.0;
let sb_w = 100.0;
- let sb_h = 26.0;
+ let sb_h = clear_ui::layout::spinbox_height();
let mute_w = 60.0;
let gap = 8.0;
@@ -315,7 +327,7 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
state.source_spinboxes[idx].value = (src.volume * 100.0).round() as i32;
state.source_spinboxes[idx].set_row_rect(row_rect_x, sec_w - 16.0);
let sb_x = sec.ax(bar_x);
- render_widget(sec.pc, &mut state.source_spinboxes[idx], sb_x, row_y, sb_w, sb_h);
+ render_widget(sec.pc, &mut state.source_spinboxes[idx], sb_x, row_y, sb_w, sb_h, ctx);
let mute_label = if src.muted { "Unmute" } else { "Mute" };
let mute_col = if src.muted { MUTED_BG } else { BTN_INACTIVE };
@@ -324,9 +336,7 @@ pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focu
mute_col, BTN_HOVER, WHITE,
AppAction::Audio(AudioMessage::SourceMute(src.id)));
- sec.content_y += 12.0 + sb_h + 6.0;
- } else {
- sec.content_y += 6.0;
+ sec.content_y += slider_h + 8.0 + sb_h + 6.0;
}
}
}
@@ -342,6 +352,8 @@ pub fn update(state: &mut AudioState, msg: AudioMessage) {
*state = new;
state.sink_spinboxes.resize_with(state.sinks.len(), || Spinbox::new(50, 0, 100, 1));
state.source_spinboxes.resize_with(state.sources.len(), || Spinbox::new(50, 0, 100, 1));
+ state.sink_sliders.resize_with(state.sinks.len(), || Slider::new().with_range(0.0, 1.0).with_scroll(true));
+ state.source_sliders.resize_with(state.sources.len(), || Slider::new().with_range(0.0, 1.0).with_scroll(true));
}
AudioMessage::SinkVolume(id, vol) => {
if let Some(sink) = state.sinks.iter_mut().find(|s| s.id == id) {
@@ -378,8 +390,8 @@ mod tests {
#[test]
fn test_view_layout_grid() {
let mut state = AudioState::default();
- let mut layout = GridLayout::new(320.0, 20.0);
- let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false], &mut layout);
+ let mut layout = GridLayout::new(260.0, 20.0);
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false], &mut layout, &mut clear_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
}
}
diff --git a/src/pages/display.rs b/src/pages/display.rs
index d572001..1cd4054 100644
--- a/src/pages/display.rs
+++ b/src/pages/display.rs
@@ -1,8 +1,8 @@
use crate::app::{PageContent, SectionContextExt};
use clear_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
-use clear_ui::widget::{Spinbox, Label, Element, Toggle, Dropdown};
+use clear_ui::widget::{Spinbox, Label, Element, Toggle, Dropdown, Slider};
-const CONFIG_PATH: &str = "/home/lsgalante/.config/ccec/config.toml";
+const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
#[derive(Debug, Clone)]
pub struct DisplayOutput {
@@ -51,6 +51,7 @@ pub struct DisplayState {
pub max_brightness: f32,
pub outputs: Vec<DisplayOutput>,
pub night_light: bool,
+ pub brightness_slider: Slider,
pub brightness_spinbox: Spinbox,
pub night_light_label: Label,
// screensaver fields:
@@ -72,6 +73,7 @@ impl Default for DisplayState {
max_brightness: 0.0,
outputs: Vec::new(),
night_light: false,
+ brightness_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true),
brightness_spinbox: Spinbox::new(50, 0, 100, 5).with_unit("%"),
night_light_label: Label::new("Night Light: OFF").with_font_size(13.0).with_color([0xd4, 0xd4, 0xd4]),
screensaver_enable: true,
@@ -274,6 +276,7 @@ pub async fn fetch_display_state() -> DisplayState {
DisplayState {
loaded: true,
brightness, max_brightness, outputs, night_light,
+ brightness_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(pct.max(1) as f32 / 100.0),
brightness_spinbox: Spinbox::new(pct.max(1), 1, 100, 5).with_unit("%"),
night_light_label: Label::new(if night_light { "Night Light: ON" } else { "Night Light: OFF" })
.with_font_size(13.0)
@@ -378,7 +381,7 @@ const BTN_BG: [f32; 4] = [0.20, 0.40, 0.65, 1.0];
const BTN_HOVER: [f32; 4] = [0.28, 0.50, 0.78, 1.0];
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
-pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(4);
@@ -393,24 +396,18 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
(state.brightness / state.max_brightness * 100.0).round() as i32
} else { 0 };
- let bar_w = sec_w - 100.0;
+ let pad = sec.padding();
+ let bar_w = sec.cw - 2.0 * pad - 12.0 - 45.0;
let yt = sec.ay();
- let usage_bar_x = sec.ax(12.0);
- let mut usage_bar = clear_ui::widget::UsageBar::new(bright_pct as f32 / 100.0)
- .with_colors(FILL_BAR, BLANK_BAR);
- render_widget(sec.pc, &mut usage_bar, usage_bar_x, yt, bar_w, 8.0);
- sec.text(&format!("{}%", bright_pct), 16.0 + bar_w, -2.0, 11.0, TEXT_DIM);
- sec.spacing(14.0);
+ state.brightness_slider.set_value(bright_pct as f32 / 100.0);
+ let slider_x = sec.ax(12.0);
+ render_widget(sec.pc, &mut state.brightness_slider, slider_x, yt, bar_w, clear_ui::layout::slider_height(), ctx);
+ sec.text(&format!("{}%", bright_pct), 12.0 + bar_w + 8.0, 7.0, 11.0, TEXT_DIM);
+ sec.spacing(34.0);
- let yt = sec.ay();
- let sb_w = 100.0;
- let sb_h = 26.0;
state.brightness_spinbox.value = bright_pct;
- let row_rect_x = sec.ax(8.0);
- state.brightness_spinbox.set_row_rect(row_rect_x, sec_w - 16.0);
- let sb_x = sec.ax(12.0);
- render_widget(sec.pc, &mut state.brightness_spinbox, sb_x, yt, sb_w, sb_h);
- sec.spacing(sb_h + 12.0);
+ sec.widget_full(&mut state.brightness_spinbox, clear_ui::layout::spinbox_height(), ctx);
+ sec.spacing(12.0);
}
});
@@ -422,7 +419,7 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
} 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);
+ sec.widget(&mut state.night_light_label, 12.0, sec_w - 24.0, 20.0, ctx);
sec.spacing(8.0);
}
});
@@ -434,10 +431,10 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
sec.spacing(18.0);
} else {
for out in &mut state.outputs {
- sec.add_subsection(&out.name, false, |subsec| {
- subsec.widget(&mut out.resolution_label, 12.0, 240.0, 20.0);
+ sec.add_section(&out.name, false, |subsec| {
+ subsec.widget(&mut out.resolution_label, 12.0, 240.0, 20.0, ctx);
if let Some(ref mut scale_lbl) = out.scale_label {
- subsec.widget(scale_lbl, 12.0, 240.0, 20.0);
+ subsec.widget(scale_lbl, 12.0, 240.0, 20.0, ctx);
}
});
}
@@ -446,34 +443,30 @@ pub fn view(state: &mut DisplayState, cx: f32, cy: f32, cw: f32, ch: f32, layout
// ── Screensaver Settings ──
builder.add_section(&mut final_pc, "Screensaver Settings", false, |sec| {
- let toggle_w = 48.0;
- let toggle_h = 24.0;
-
state.screensaver_enable_toggle.set_toggled(state.screensaver_enable);
- sec.widget(&mut state.screensaver_enable_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.screensaver_enable_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(8.0);
state.screensaver_lock_screen_toggle.set_toggled(state.screensaver_lock_screen);
- sec.widget(&mut state.screensaver_lock_screen_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.screensaver_lock_screen_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(16.0);
- state.screensaver_timeout_spinbox.value = state.screensaver_timeout;
- sec.widget(&mut state.screensaver_timeout_spinbox, 14.0, 200.0, 26.0);
+ state.screensaver_timeout_spinbox.value = state.screensaver_timeout;
+ sec.widget_full(&mut state.screensaver_timeout_spinbox, clear_ui::layout::spinbox_height(), ctx);
sec.spacing(16.0);
- sec.widget(&mut state.screensaver_style_menu, 14.0, 200.0, 26.0);
+ sec.widget_full(&mut state.screensaver_style_menu, clear_ui::layout::dropdown_height(), ctx);
sec.spacing(24.0);
- let btn_w = 160.0;
let btn_h = 32.0;
let btn_y = sec.ay();
let cols = sec.row_layout(1, 0.0);
- if let Some(&(x, _)) = cols.first() {
+ if let Some(&(x, w)) = cols.first() {
sec.button(
"Preview Screensaver",
x,
btn_y,
- btn_w,
+ w,
btn_h,
BTN_BG,
BTN_HOVER,
@@ -506,9 +499,11 @@ pub fn update(state: &mut DisplayState, msg: DisplayMessage) {
let lock_hover = state.screensaver_lock_screen_toggle.hovered();
let timeout_hover = state.screensaver_timeout_spinbox.hovered();
let style_hover = state.screensaver_style_menu.hovered();
+ let brightness_slider_hover = state.brightness_slider.hovered();
*state = new;
state.night_light_label.set_hovered(was_nl_hovered);
+ state.brightness_slider.set_hovered(brightness_slider_hover);
state.screensaver_enable_toggle.set_hovered(enable_hover);
state.screensaver_lock_screen_toggle.set_hovered(lock_hover);
@@ -530,6 +525,7 @@ pub fn update(state: &mut DisplayState, msg: DisplayMessage) {
state.brightness = pct as f32 / 100.0 * state.max_brightness;
spawn_brightness(pct);
state.brightness_spinbox.value = pct as i32;
+ state.brightness_slider.set_value(pct as f32 / 100.0);
}
DisplayMessage::ToggleScreensaverEnable => {
state.screensaver_enable = !state.screensaver_enable;
@@ -583,8 +579,8 @@ mod tests {
#[test]
fn test_view_layout_grid() {
let mut state = DisplayState::default();
- let mut layout = clear_ui::layout::GridLayout::new(320.0, 20.0);
- let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &mut layout);
+ let mut layout = clear_ui::layout::GridLayout::new(260.0, 20.0);
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &mut layout, &mut clear_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
}
}
diff --git a/src/pages/hardware.rs b/src/pages/hardware.rs
index 7145765..e4ba86b 100644
--- a/src/pages/hardware.rs
+++ b/src/pages/hardware.rs
@@ -128,14 +128,14 @@ fn format_duration(secs: i64) -> String {
fn spawn_cpu_power(powersave: bool) {
let script = if powersave { "cpu-powersave-on" } else { "cpu-powersave-off" };
let _ = tokio::process::Command::new("pkexec")
- .arg(format!("/home/lsgalante/.local/share/clear-system-interface/helpers/{}", script))
+ .arg(format!("/home/lsgalante/.local/share/cce-system-interface/helpers/{}", script))
.spawn();
}
fn spawn_gpu_power(powersave: bool) {
let script = if powersave { "gpu-powersave-on" } else { "gpu-powersave-off" };
let _ = tokio::process::Command::new("pkexec")
- .arg(format!("/home/lsgalante/.local/share/clear-system-interface/helpers/{}", script))
+ .arg(format!("/home/lsgalante/.local/share/cce-system-interface/helpers/{}", script))
.spawn();
}
@@ -243,17 +243,18 @@ async fn read_nvidia_gpu_temp() -> Option<f32> {
}
pub async fn fetch_hardware_state() -> HardwareState {
- let (cpu_model, cpu_cores) = {
- let lscpu = tokio::process::Command::new("lscpu")
- .output().await.ok()
+ static CPU_INFO: std::sync::OnceLock<(String, u32)> = std::sync::OnceLock::new();
+ let (cpu_model, cpu_cores) = CPU_INFO.get_or_init(|| {
+ let output = std::process::Command::new("lscpu")
+ .output().ok()
.map(|o| String::from_utf8_lossy(&o.stdout).to_string())
.unwrap_or_default();
- let model = lscpu.lines()
+ let model = output.lines()
.find(|l| l.contains("Model name"))
.and_then(|l| l.split(':').nth(1))
.map(|s| s.trim().to_string())
.unwrap_or_default();
- let cores = lscpu.lines()
+ let cores = output.lines()
.find(|l| l.contains("CPU(s)"))
.and_then(|l| {
let rest = l.split(':').nth(1).unwrap_or("").trim();
@@ -261,7 +262,7 @@ pub async fn fetch_hardware_state() -> HardwareState {
})
.unwrap_or(0);
(model, cores)
- };
+ }).clone();
let cpu_usage = {
let read_stat = || -> Option<(u64, u64)> {
@@ -283,19 +284,23 @@ pub async fn fetch_hardware_state() -> HardwareState {
} else { 0.0 }
} as f32;
- let mut gpus = Vec::new();
- if let Some(o) = tokio::process::Command::new("lspci").output().await.ok() {
- for line in String::from_utf8_lossy(&o.stdout).lines() {
- if line.contains("VGA") || line.contains("3D") {
- if let Some(name) = line.split(':').nth(2) {
- let trimmed = name.trim().to_string();
- if !trimmed.is_empty() {
- gpus.push(trimmed);
+ static GPUS_INFO: std::sync::OnceLock<Vec<String>> = std::sync::OnceLock::new();
+ let gpus = GPUS_INFO.get_or_init(|| {
+ let mut list = Vec::new();
+ if let Some(o) = std::process::Command::new("lspci").output().ok() {
+ for line in String::from_utf8_lossy(&o.stdout).lines() {
+ if line.contains("VGA") || line.contains("3D") {
+ if let Some(name) = line.split(':').nth(2) {
+ let trimmed = name.trim().to_string();
+ if !trimmed.is_empty() {
+ list.push(trimmed);
+ }
}
}
}
}
- }
+ list
+ }).clone();
let processes = {
let mut list = Vec::new();
@@ -373,7 +378,7 @@ const ACCENT: [f32; 4] = [0.36, 0.56, 0.38, 1.0];
const RED: [f32; 4] = [1.0, 0.33, 0.33, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.73, 0.20, 1.0];
-pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(5);
@@ -386,15 +391,15 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
sec.spacing(10.0);
} else {
// CPU Info Label
- sec.widget(&mut state.cpu_label, 12.0, sec.cw - 24.0, 26.0);
+ 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);
+ 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);
+ sec.widget(&mut state.cpu_temp_label, 12.0, sec.cw - 24.0, 26.0, ctx);
sec.spacing(12.0);
// Scrolling box configuration for process list
@@ -404,7 +409,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
let list_box_h = 220.0;
// Render the standardized ScrollBox widget
- render_widget(sec.pc, &mut state.cpu_list_box, list_box_x, list_box_y, list_box_w, list_box_h);
+ render_widget(sec.pc, &mut state.cpu_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
// Header for process list columns (drawn static on top of the ScrollBox background)
let header_h = 22.0;
@@ -457,7 +462,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
} else {
for (i, gpu_lbl) in state.gpu_labels.iter_mut().enumerate() {
if i > 0 { sec_gpu.spacing(12.0); }
- sec_gpu.widget(gpu_lbl, 12.0, sec_gpu.cw - 24.0, 26.0);
+ sec_gpu.widget(gpu_lbl, 12.0, sec_gpu.cw - 24.0, 26.0, ctx);
}
}
});
@@ -504,6 +509,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
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);
}
});
@@ -514,7 +520,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
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);
+ 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 {
@@ -538,7 +544,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
let mut info_box = InfoBox::new(info_title, info_lines);
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);
+ 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);
}
});
@@ -550,7 +556,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
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);
+ 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 {
@@ -574,7 +580,7 @@ pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_
let mut info_box = InfoBox::new(info_title, info_lines);
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);
+ 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);
}
});
diff --git a/src/pages/input.rs b/src/pages/input.rs
index aa21d65..16855fe 100644
--- a/src/pages/input.rs
+++ b/src/pages/input.rs
@@ -5,12 +5,12 @@ use crate::app::PageContent;
use clear_ui::layout::{PageLayoutBuilder, LayoutStrategy};
use clear_ui::widget::{Spinbox, Toggle, Trackpad, Dropdown, Finger, Element};
-const CONFIG_PATH: &str = "/home/lsgalante/.config/ccec/config.toml";
+const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
fn get_socket_path() -> String {
match std::env::var("WAYLAND_DISPLAY") {
- Ok(display) => format!("/tmp/ccec-{}.sock", display),
- Err(_) => "/tmp/ccec.sock".to_string(),
+ Ok(display) => format!("/tmp/cce-client-{}.sock", display),
+ Err(_) => "/tmp/cce-client.sock".to_string(),
}
}
@@ -154,8 +154,8 @@ impl Default for InputState {
}
impl InputState {
- pub fn is_over_trackpad(&self, lx: f32, ly: f32) -> bool {
- self.trackpad.hit_test(lx, ly)
+ pub fn is_over_trackpad(&self, lx: f32, ly: f32, ctx: &clear_ui::context::UiContext) -> bool {
+ self.trackpad.hit_test(lx, ly, ctx)
}
}
@@ -389,95 +389,87 @@ fn apply_repeat_config(rate: u16, delay: u16) {
const TEXT_FG: [f32; 4] = [0.83, 0.83, 0.83, 1.0];
const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-pub fn view(state: &mut InputState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut InputState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(7);
// ── Touchpad ──
builder.add_section(&mut final_pc, "Touchpad", false, |sec| {
- let toggle_w = 48.0;
- let toggle_h = 42.0;
state.tap_toggle.set_toggled(state.tap_to_click);
- sec.widget(&mut state.tap_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.tap_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(8.0);
// Built-in trackpad visualizer widget
let pad_w = 280.0;
let pad_h = 158.0;
state.trackpad.set_fingers(state.fingers.clone());
- sec.widget(&mut state.trackpad, 14.0, pad_w, pad_h);
+ sec.widget(&mut state.trackpad, 14.0, pad_w, pad_h, ctx);
sec.spacing(12.0);
});
// ── Trackpoint ──
builder.add_section(&mut final_pc, "Trackpoint", sec_focused.first().copied().unwrap_or(false), |sec| {
- let toggle_w = 48.0;
- let toggle_h = 42.0;
state.dwtp_toggle.set_toggled(state.dwtp);
- sec.widget(&mut state.dwtp_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.dwtp_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(12.0);
- sec.widget(&mut state.trackpoint_accel_speed_spinbox, 14.0, 200.0, 44.0);
+ sec.widget_full(&mut state.trackpoint_accel_speed_spinbox, 44.0, ctx);
sec.spacing(12.0);
- sec.widget(&mut state.trackpoint_accel_profile_menu, 14.0, 200.0, 44.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(&mut state.rate_spinbox, 14.0, 200.0, 44.0);
+ sec.widget_full(&mut state.rate_spinbox, 44.0, ctx);
sec.spacing(8.0);
- sec.widget(&mut state.delay_spinbox, 14.0, 200.0, 44.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(&mut state.cursor_theme_menu, 14.0, 200.0, 44.0);
+ sec.widget_full(&mut state.cursor_theme_menu, 44.0, ctx);
sec.spacing(12.0);
- sec.widget(&mut state.cursor_size_spinbox, 14.0, 200.0, 44.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| {
- let toggle_w = 48.0;
- let toggle_h = 42.0;
state.scroll_toggle.set_toggled(state.inertial_scroll);
- sec.widget(&mut state.scroll_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.scroll_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(12.0);
- sec.widget(&mut state.scroll_friction_spinbox, 14.0, 200.0, 44.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(&mut state.natural_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.natural_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(12.0);
- sec.widget(&mut state.scroll_speed_spinbox, 14.0, 200.0, 44.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| {
- let toggle_w = 48.0;
- let toggle_h = 42.0;
state.pointer_toggle.set_toggled(state.inertial_pointer);
- sec.widget(&mut state.pointer_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.pointer_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(12.0);
- sec.widget(&mut state.pointer_friction_spinbox, 14.0, 200.0, 44.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(&mut state.trackpad_toggle, 14.0, toggle_w, toggle_h);
+ sec.widget_full(&mut state.trackpad_toggle, clear_ui::layout::toggle_height(), ctx);
sec.spacing(12.0);
- sec.widget(&mut state.trackpad_friction_spinbox, 14.0, 200.0, 44.0);
+ sec.widget_full(&mut state.trackpad_friction_spinbox, 44.0, ctx);
sec.spacing(8.0);
});
@@ -610,19 +602,20 @@ mod tests {
fn test_is_over_trackpad() {
let mut state = InputState::default();
state.trackpad.set_rect(100.0, 200.0, 300.0, 150.0);
+ let ctx = clear_ui::context::UiContext::new();
// Inside
- assert!(state.is_over_trackpad(150.0, 250.0));
- assert!(state.is_over_trackpad(100.0, 200.0));
- assert!(state.is_over_trackpad(400.0, 350.0));
+ assert!(state.is_over_trackpad(150.0, 250.0, &ctx));
+ assert!(state.is_over_trackpad(100.0, 200.0, &ctx));
+ assert!(state.is_over_trackpad(400.0, 350.0, &ctx));
// Outside X
- assert!(!state.is_over_trackpad(99.0, 250.0));
- assert!(!state.is_over_trackpad(401.0, 250.0));
+ assert!(!state.is_over_trackpad(99.0, 250.0, &ctx));
+ assert!(!state.is_over_trackpad(401.0, 250.0, &ctx));
// Outside Y
- assert!(!state.is_over_trackpad(150.0, 199.0));
- assert!(!state.is_over_trackpad(150.0, 351.0));
+ assert!(!state.is_over_trackpad(150.0, 199.0, &ctx));
+ assert!(!state.is_over_trackpad(150.0, 351.0, &ctx));
}
#[test]
@@ -640,7 +633,7 @@ mod tests {
fn test_view_layout_grid() {
let mut state = InputState::default();
let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
- let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false, false, false, false], &mut layout);
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false, false, false, false], &mut layout, &mut clear_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
}
}
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index f418194..0aadfd0 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -3,15 +3,15 @@ use std::io::Write;
use crate::app::PageContent;
use clear_ui::layout::{PageLayoutBuilder, LayoutStrategy};
use clear_ui::widget::{
- ColorSelector, Spinbox, Element, ScrollingList, Dropdown, TextBox, Button, InfoBox, FontPreview, InteractiveListItem
+ ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle, Slider
};
-const CONFIG_PATH: &str = "/home/lsgalante/.config/ccec/config.toml";
+const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
fn get_socket_path() -> String {
match std::env::var("WAYLAND_DISPLAY") {
- Ok(display) => format!("/tmp/ccec-{}.sock", display),
- Err(_) => "/tmp/ccec.sock".to_string(),
+ Ok(display) => format!("/tmp/cce-client-{}.sock", display),
+ Err(_) => "/tmp/cce-client.sock".to_string(),
}
}
@@ -40,6 +40,38 @@ pub struct InterfaceState {
pub paginator_tab_padding_y: u16,
pub tab_padding_spinbox_x: Spinbox,
pub tab_padding_spinbox_y: Spinbox,
+ pub section_padding: u16,
+ pub section_padding_spinbox: Spinbox,
+ pub plate_padding: u16,
+ pub plate_padding_spinbox: Spinbox,
+ pub page_margin: u16,
+ pub page_margin_spinbox: Spinbox,
+ pub grid_min_col_width: u16,
+ pub grid_min_col_width_spinbox: Spinbox,
+ pub spinbox_height: u16,
+ pub spinbox_height_spinbox: Spinbox,
+ pub toggle_height: u16,
+ pub toggle_height_spinbox: Spinbox,
+ pub color_selector_height: u16,
+ pub color_selector_height_spinbox: Spinbox,
+ pub color_selector_preview_corner_radius: u16,
+ pub color_selector_preview_corner_radius_spinbox: Spinbox,
+ pub color_selector_preview_margin: u16,
+ pub color_selector_preview_margin_spinbox: Spinbox,
+ pub textbox_height: u16,
+ pub textbox_height_spinbox: Spinbox,
+ pub slider_height: u16,
+ pub slider_height_spinbox: Spinbox,
+ pub font_selector_height: u16,
+ pub font_selector_height_spinbox: Spinbox,
+ pub dropdown_height: u16,
+ pub dropdown_height_spinbox: Spinbox,
+ pub nested_section_label_alignment: u8,
+ pub label_alignment_menu: Dropdown,
+ pub nested_section_label_offset: i16,
+ pub label_offset_spinbox: Spinbox,
+ pub label_margin: u16,
+ pub label_margin_spinbox: Spinbox,
// Typeface state fields
pub typeface_loaded: bool,
pub sans_serif: String,
@@ -59,22 +91,31 @@ pub struct InterfaceState {
pub status_box: TextBox,
pub fuzzel_box: TextBox,
pub terminal_box: TextBox,
- pub paginator_box: TextBox,
- pub search_box: TextBox,
- pub selected_font: Option<String>,
- pub list_box: ScrollingList,
pub borders_menu: Dropdown,
pub status_menu: Dropdown,
pub fuzzel_menu: Dropdown,
pub terminal_menu: Dropdown,
- pub paginator_menu: Dropdown,
pub borders_size_box: Spinbox,
pub status_size_box: Spinbox,
pub fuzzel_size_box: Spinbox,
pub terminal_size_box: Spinbox,
- pub paginator_size_box: Spinbox,
- pub font_buttons: Vec<InteractiveListItem>,
- pub copy_buttons: Vec<Button>,
+ pub color_selector_font: String,
+ pub color_selector_font_selector: FontSelector,
+ pub menubar_font: String,
+ pub menubar_font_selector: FontSelector,
+ pub section_label_font: String,
+ pub section_label_font_selector: FontSelector,
+ pub nested_section_label_font: String,
+ pub nested_section_label_font_selector: FontSelector,
+ // Graph configuration fields
+ pub graph_show_grid: bool,
+ pub graph_show_grid_toggle: Toggle,
+ pub graph_snap_enabled: bool,
+ pub graph_snap_enabled_toggle: Toggle,
+ pub graph_uniform_background: bool,
+ pub graph_uniform_background_toggle: Toggle,
+ pub graph_network_opacity: f32,
+ pub graph_network_opacity_slider: Slider,
}
impl Default for InterfaceState {
@@ -95,7 +136,7 @@ impl Default for InterfaceState {
toggle_enabled_color: [104, 217, 165],
toggle_disabled_color: [135, 135, 148],
color_selectors: vec![
- ColorSelector::new([71, 71, 81]).with_label("Low Color"), // 0: Pages - Low Color
+ ColorSelector::new([71, 71, 81]).with_label("Low Color"), // 0: Plate - Low Color
ColorSelector::new([0x3e, 0x3e, 0x3e]).with_label("High Color"), // 1: Layout - High Color
ColorSelector::new([0xff, 0x8c, 0x00]).with_label("Visual Guides"), // 2: Layout - Visual Guides
ColorSelector::new([0x55, 0x55, 0x55]).with_label("Disabled"), // 3: Status - Disabled
@@ -118,6 +159,41 @@ impl Default for InterfaceState {
paginator_tab_padding_y: 14,
tab_padding_spinbox_x: Spinbox::new(10, 0, 100, 1).with_label("Tab Padding X").with_unit("px"),
tab_padding_spinbox_y: Spinbox::new(14, 0, 100, 1).with_label("Tab Padding Y").with_unit("px"),
+ section_padding: 8,
+ section_padding_spinbox: Spinbox::new(8, 0, 100, 1).with_label("Padding").with_unit("px"),
+ plate_padding: 20,
+ plate_padding_spinbox: Spinbox::new(20, 0, 100, 1).with_label("Padding").with_unit("px"),
+ page_margin: 20,
+ page_margin_spinbox: Spinbox::new(20, 0, 100, 1).with_label("Page Margin").with_unit("px"),
+ grid_min_col_width: 260,
+ grid_min_col_width_spinbox: Spinbox::new(260, 100, 1000, 10).with_label("Minimum Width").with_unit("px"),
+ spinbox_height: 26,
+ spinbox_height_spinbox: Spinbox::new(26, 10, 100, 1).with_label("Height").with_unit("px"),
+ toggle_height: 44,
+ toggle_height_spinbox: Spinbox::new(44, 10, 100, 1).with_label("Height").with_unit("px"),
+ color_selector_height: 22,
+ color_selector_height_spinbox: Spinbox::new(22, 10, 100, 1).with_label("Height").with_unit("px"),
+ color_selector_preview_corner_radius: 4,
+ color_selector_preview_corner_radius_spinbox: Spinbox::new(4, 0, 50, 1).with_label("Preview Corner Radius").with_unit("px"),
+ color_selector_preview_margin: 0,
+ color_selector_preview_margin_spinbox: Spinbox::new(0, 0, 20, 1).with_label("Preview Margin").with_unit("px"),
+ textbox_height: 44,
+ textbox_height_spinbox: Spinbox::new(44, 10, 100, 1).with_label("Height").with_unit("px"),
+ slider_height: 28,
+ slider_height_spinbox: Spinbox::new(28, 10, 100, 1).with_label("Height").with_unit("px"),
+ font_selector_height: 44,
+ font_selector_height_spinbox: Spinbox::new(44, 10, 100, 1).with_label("Height").with_unit("px"),
+ dropdown_height: 44,
+ dropdown_height_spinbox: Spinbox::new(44, 10, 100, 1).with_label("Height").with_unit("px"),
+ nested_section_label_alignment: 0,
+ label_alignment_menu: Dropdown::new(
+ vec!["Left".to_string(), "Center".to_string(), "Right".to_string()],
+ 0,
+ ).with_label("Label Alignment"),
+ nested_section_label_offset: 0,
+ label_offset_spinbox: Spinbox::new(0, -100, 100, 1).with_label("Label Offset").with_unit("px"),
+ label_margin: 6,
+ label_margin_spinbox: Spinbox::new(6, 0, 100, 1).with_label("Label Margin").with_unit("px"),
typeface_loaded: false,
sans_serif: String::new(),
serif: String::new(),
@@ -136,22 +212,30 @@ impl Default for InterfaceState {
status_box: TextBox::default(),
fuzzel_box: TextBox::default(),
terminal_box: TextBox::default(),
- paginator_box: TextBox::default(),
- search_box: TextBox::default(),
- selected_font: None,
- list_box: ScrollingList::new(24.0, 4.0),
borders_menu: Dropdown::default(),
status_menu: Dropdown::default(),
fuzzel_menu: Dropdown::default(),
terminal_menu: Dropdown::default(),
- paginator_menu: Dropdown::default(),
borders_size_box: Spinbox::new(11, 6, 72, 1),
status_size_box: Spinbox::new(11, 6, 72, 1),
fuzzel_size_box: Spinbox::new(14, 6, 72, 1),
terminal_size_box: Spinbox::new(12, 6, 72, 1),
- paginator_size_box: Spinbox::new(12, 6, 72, 1),
- font_buttons: Vec::new(),
- copy_buttons: Vec::new(),
+ color_selector_font: "monospace".to_string(),
+ color_selector_font_selector: FontSelector::new("monospace".to_string()).with_label("Value"),
+ menubar_font: "Outfit".to_string(),
+ menubar_font_selector: FontSelector::new("Outfit".to_string()).with_label("Font"),
+ section_label_font: "Outfit".to_string(),
+ section_label_font_selector: FontSelector::new("Outfit".to_string()).with_label("Label"),
+ nested_section_label_font: "Outfit".to_string(),
+ nested_section_label_font_selector: FontSelector::new("Outfit".to_string()).with_label("Label"),
+ graph_show_grid: true,
+ graph_show_grid_toggle: Toggle::new().with_label("Show Grid"),
+ graph_snap_enabled: true,
+ graph_snap_enabled_toggle: Toggle::new().with_label("Grid Snapping"),
+ graph_uniform_background: false,
+ graph_uniform_background_toggle: Toggle::new().with_label("Uniform Background"),
+ graph_network_opacity: 0.95,
+ graph_network_opacity_slider: Slider::new().with_label("Network Opacity").with_value(0.95),
}
}
}
@@ -176,6 +260,30 @@ pub enum InterfaceMessage {
SetTabMarginY(u16),
SetTabPaddingX(u16),
SetTabPaddingY(u16),
+ SetSectionPadding(u16),
+ SetPlatePadding(u16),
+ SetPageMargin(u16),
+ SetGridMinColWidth(u16),
+ SetSpinboxHeight(u16),
+ SetToggleHeight(u16),
+ SetColorSelectorHeight(u16),
+ SetColorSelectorPreviewCornerRadius(u16),
+ SetColorSelectorPreviewMargin(u16),
+ SetTextboxHeight(u16),
+ SetSliderHeight(u16),
+ SetFontSelectorHeight(u16),
+ SetDropdownHeight(u16),
+ SetColorSelectorFont(String),
+ SetMenubarFont(String),
+ SetSectionLabelFont(String),
+ SetNestedSectionLabelFont(String),
+ SetNestedSectionLabelAlignment(usize),
+ SetNestedSectionLabelOffset(i16),
+ SetLabelMargin(u16),
+ SetGraphShowGrid(bool),
+ SetGraphSnapEnabled(bool),
+ SetGraphUniformBackground(bool),
+ SetGraphOpacity(f32),
PickLowColor,
PickHighColor,
PickDisabledColor,
@@ -199,20 +307,14 @@ pub enum InterfaceMessage {
SetStatus(String),
SetFuzzel(String),
SetTerminal(String),
- SetPaginator(String),
- SetSearch(String),
- SelectFont(String),
- CopyFontName(String),
SetBordersMenu(usize),
SetStatusMenu(usize),
SetFuzzelMenu(usize),
SetTerminalMenu(usize),
- SetPaginatorMenu(usize),
SetBordersSize(i32),
SetStatusSize(i32),
SetFuzzelSize(i32),
SetTerminalSize(i32),
- SetPaginatorSize(i32),
}
pub fn read_interface_config() -> InterfaceState {
@@ -260,6 +362,30 @@ pub fn read_interface_config() -> InterfaceState {
let paginator_tab_margin_y = parse_u16_from(&content, "paginator_tab_margin_y", if paginator_tab_margin_general != 999 { paginator_tab_margin_general } else { 10 });
let paginator_tab_padding_x = parse_u16_from(&content, "paginator_tab_padding_x", 10);
let paginator_tab_padding_y = parse_u16_from(&content, "paginator_tab_padding_y", 14);
+ let section_padding = parse_u16_from(&content, "section_padding", 8);
+ let plate_padding = parse_u16_from(&content, "plate_padding", 20);
+ 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 spinbox_height = parse_u16_from(&content, "spinbox_height", 26);
+ let toggle_height = parse_u16_from(&content, "toggle_height", 44);
+ let color_selector_height = parse_u16_from(&content, "color_selector_height", 22);
+ let color_selector_preview_corner_radius = parse_u16_from(&content, "color_selector_preview_corner_radius", 4);
+ let color_selector_preview_margin = parse_u16_from(&content, "color_selector_preview_margin", 0);
+ let textbox_height = parse_u16_from(&content, "textbox_height", 44);
+ let slider_height = parse_u16_from(&content, "slider_height", 28);
+ let font_selector_height = parse_u16_from(&content, "font_selector_height", 44);
+ let dropdown_height = parse_u16_from(&content, "dropdown_height", 44);
+ let color_selector_font = parse_string_from(&content, "color_selector_font", "monospace");
+ let menubar_font = parse_string_from(&content, "menubar_font", "Outfit");
+ let section_label_font = parse_string_from(&content, "section_label_font", "Outfit");
+ let nested_section_label_font = parse_string_from(&content, "nested_section_label_font", "Outfit");
+ let nested_section_label_alignment = parse_u16_from(&content, "nested_section_label_alignment", 0) as u8;
+ let nested_section_label_offset = parse_i16_from(&content, "nested_section_label_offset", 0);
+ let label_margin = parse_u16_from(&content, "label_margin", 6);
+ let graph_show_grid = parse_bool_from(&content, "graph_show_grid", true);
+ let graph_snap_enabled = parse_bool_from(&content, "graph_snap_enabled", true);
+ let graph_uniform_background = parse_bool_from(&content, "graph_uniform_background", false);
+ let graph_network_opacity = parse_f32_from(&content, "graph_network_opacity", 0.95);
InterfaceState {
low_color: bg,
@@ -277,20 +403,20 @@ pub fn read_interface_config() -> InterfaceState {
toggle_enabled_color: toggle_enabled,
toggle_disabled_color: toggle_disabled,
color_selectors: vec![
- ColorSelector::new(page_low).with_label("Low Color"), // 0: Pages - Low Color
- ColorSelector::new(border).with_label("High Color"), // 1: Layout - High Color
- ColorSelector::new(visual_guides).with_label("Visual Guides"), // 2: Layout - Visual Guides
- ColorSelector::new(disabled).with_label("Disabled"), // 3: Status - Disabled
- ColorSelector::new(separator).with_label("Separators"), // 4: Status - Separators
- ColorSelector::new(slider_track).with_label("Slider Track"), // 5: Controls - Slider Track
- ColorSelector::new(color_borders).with_label("Borders"), // 6: Controls - Borders
- ColorSelector::new(bg).with_label("Low Color"), // 7: Layout - Low Color
- ColorSelector::new(normal).with_label("Normal"), // 8: Status - Normal
- ColorSelector::new(paginator_sidebar).with_label("Paginator Sidebar"), // 9: Controls - Paginator Sidebar
- ColorSelector::new(primary_highlight).with_label("Primary Highlight"), // 10: Controls - Primary Highlight
- ColorSelector::new(paginator_tab_label).with_label("Paginator Tab Label"), // 11: Controls - Paginator Tab Label
- ColorSelector::new(toggle_enabled).with_label("Enabled"), // 12: Toggles - Enabled
- ColorSelector::new(toggle_disabled).with_label("Disabled"), // 13: Toggles - Disabled
+ ColorSelector::new(page_low).with_label("Low Color").with_font_family(&color_selector_font), // 0: Plate - Low Color
+ ColorSelector::new(border).with_label("High Color").with_font_family(&color_selector_font), // 1: Layout - High Color
+ ColorSelector::new(visual_guides).with_label("Visual Guides").with_font_family(&color_selector_font), // 2: Layout - Visual Guides
+ ColorSelector::new(disabled).with_label("Disabled").with_font_family(&color_selector_font), // 3: Status - Disabled
+ ColorSelector::new(separator).with_label("Separators").with_font_family(&color_selector_font), // 4: Status - Separators
+ ColorSelector::new(slider_track).with_label("Slider Track").with_font_family(&color_selector_font), // 5: Controls - Slider Track
+ ColorSelector::new(color_borders).with_label("Borders").with_font_family(&color_selector_font), // 6: Controls - Borders
+ ColorSelector::new(bg).with_label("Low Color").with_font_family(&color_selector_font), // 7: Layout - Low Color
+ ColorSelector::new(normal).with_label("Normal").with_font_family(&color_selector_font), // 8: Status - Normal
+ ColorSelector::new(paginator_sidebar).with_label("Paginator Sidebar").with_font_family(&color_selector_font), // 9: Controls - Paginator Sidebar
+ ColorSelector::new(primary_highlight).with_label("Primary Highlight").with_font_family(&color_selector_font), // 10: Controls - Primary Highlight
+ ColorSelector::new(paginator_tab_label).with_label("Paginator Tab Label").with_font_family(&color_selector_font), // 11: Controls - Paginator Tab Label
+ ColorSelector::new(toggle_enabled).with_label("Enabled").with_font_family(&color_selector_font), // 12: Toggles - Enabled
+ ColorSelector::new(toggle_disabled).with_label("Disabled").with_font_family(&color_selector_font), // 13: Toggles - Disabled
],
paginator_tab_margin_x,
paginator_tab_margin_y,
@@ -300,6 +426,41 @@ pub fn read_interface_config() -> InterfaceState {
paginator_tab_padding_y,
tab_padding_spinbox_x: Spinbox::new(paginator_tab_padding_x as i32, 0, 100, 1).with_label("Tab Padding X").with_unit("px"),
tab_padding_spinbox_y: Spinbox::new(paginator_tab_padding_y as i32, 0, 100, 1).with_label("Tab Padding Y").with_unit("px"),
+ section_padding,
+ section_padding_spinbox: Spinbox::new(section_padding as i32, 0, 100, 1).with_label("Padding").with_unit("px"),
+ plate_padding,
+ plate_padding_spinbox: Spinbox::new(plate_padding as i32, 0, 100, 1).with_label("Padding").with_unit("px"),
+ page_margin,
+ page_margin_spinbox: Spinbox::new(page_margin as i32, 0, 100, 1).with_label("Page Margin").with_unit("px"),
+ 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"),
+ spinbox_height,
+ spinbox_height_spinbox: Spinbox::new(spinbox_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ toggle_height,
+ toggle_height_spinbox: Spinbox::new(toggle_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ color_selector_height,
+ color_selector_height_spinbox: Spinbox::new(color_selector_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ color_selector_preview_corner_radius,
+ color_selector_preview_corner_radius_spinbox: Spinbox::new(color_selector_preview_corner_radius as i32, 0, 50, 1).with_label("Preview Corner Radius").with_unit("px"),
+ color_selector_preview_margin,
+ color_selector_preview_margin_spinbox: Spinbox::new(color_selector_preview_margin as i32, 0, 20, 1).with_label("Preview Margin").with_unit("px"),
+ textbox_height,
+ textbox_height_spinbox: Spinbox::new(textbox_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ slider_height,
+ slider_height_spinbox: Spinbox::new(slider_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ font_selector_height,
+ font_selector_height_spinbox: Spinbox::new(font_selector_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ dropdown_height,
+ dropdown_height_spinbox: Spinbox::new(dropdown_height as i32, 10, 100, 1).with_label("Height").with_unit("px"),
+ nested_section_label_alignment,
+ label_alignment_menu: Dropdown::new(
+ vec!["Left".to_string(), "Center".to_string(), "Right".to_string()],
+ nested_section_label_alignment as usize,
+ ).with_label("Label Alignment"),
+ nested_section_label_offset,
+ label_offset_spinbox: Spinbox::new(nested_section_label_offset as i32, -100, 100, 1).with_label("Label Offset").with_unit("px"),
+ label_margin,
+ label_margin_spinbox: Spinbox::new(label_margin as i32, 0, 100, 1).with_label("Label Margin").with_unit("px"),
typeface_loaded: false,
sans_serif: String::new(),
serif: String::new(),
@@ -318,25 +479,50 @@ pub fn read_interface_config() -> InterfaceState {
status_box: TextBox::default(),
fuzzel_box: TextBox::default(),
terminal_box: TextBox::default(),
- paginator_box: TextBox::default(),
- search_box: TextBox::default(),
- selected_font: None,
- list_box: ScrollingList::new(24.0, 4.0),
borders_menu: Dropdown::default(),
status_menu: Dropdown::default(),
fuzzel_menu: Dropdown::default(),
terminal_menu: Dropdown::default(),
- paginator_menu: Dropdown::default(),
borders_size_box: Spinbox::new(11, 6, 72, 1),
status_size_box: Spinbox::new(11, 6, 72, 1),
fuzzel_size_box: Spinbox::new(14, 6, 72, 1),
terminal_size_box: Spinbox::new(12, 6, 72, 1),
- paginator_size_box: Spinbox::new(12, 6, 72, 1),
- font_buttons: Vec::new(),
- copy_buttons: Vec::new(),
+ color_selector_font: color_selector_font.clone(),
+ color_selector_font_selector: FontSelector::new(color_selector_font.clone()).with_label("Value"),
+ menubar_font: menubar_font.clone(),
+ menubar_font_selector: FontSelector::new(menubar_font.clone()).with_label("Font"),
+ section_label_font: section_label_font.clone(),
+ section_label_font_selector: FontSelector::new(section_label_font.clone()).with_label("Label"),
+ nested_section_label_font: nested_section_label_font.clone(),
+ nested_section_label_font_selector: FontSelector::new(nested_section_label_font.clone()).with_label("Label"),
+ graph_show_grid,
+ graph_show_grid_toggle: Toggle::new().with_label("Show Grid"),
+ graph_snap_enabled,
+ graph_snap_enabled_toggle: Toggle::new().with_label("Grid Snapping"),
+ graph_uniform_background,
+ graph_uniform_background_toggle: Toggle::new().with_label("Uniform Background"),
+ graph_network_opacity,
+ graph_network_opacity_slider: Slider::new().with_label("Network Opacity").with_value(graph_network_opacity),
}
}
+pub fn parse_string_from(content: &str, key: &str, default: &str) -> String {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix(key) {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = rest.trim();
+ let val_str = if rest.starts_with('"') && rest.ends_with('"') && rest.len() >= 2 {
+ &rest[1..rest.len() - 1]
+ } else {
+ rest
+ };
+ return val_str.trim().to_string();
+ }
+ }
+ default.to_string()
+}
+
fn parse_color_from_key(content: &str, key: &str, default: [u8; 3]) -> [u8; 3] {
for line in content.lines() {
let trimmed = line.trim();
@@ -408,6 +594,21 @@ fn send_ipc_command(cmd: &str) {
}
}
+fn cce_graph_reload() {
+ let is_running = std::process::Command::new("pgrep")
+ .args(["-f", "cce-graph"])
+ .output()
+ .map(|o| !o.stdout.is_empty())
+ .unwrap_or(false);
+ if is_running {
+ let _ = std::process::Command::new("pkill")
+ .args(["-f", "cce-graph"])
+ .status();
+ std::thread::sleep(std::time::Duration::from_millis(150));
+ send_ipc_command("spawn cce-graph");
+ }
+}
+
fn apply_background(rgb: [u8; 3]) {
let _ = std::process::Command::new("pkill").args(["-x", "swaybg"]).status();
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -431,10 +632,10 @@ fn apply_disabled_color(rgb: [u8; 3]) {
fn status_interface_reload() {
let _ = std::process::Command::new("pkill")
- .args(["-f", "clear-status-interface"])
+ .args(["-f", "cce-status-interface"])
.status();
std::thread::sleep(std::time::Duration::from_millis(150));
- send_ipc_command("spawn clear-status-interface");
+ send_ipc_command("spawn cce-status-interface");
}
fn apply_separator_color(rgb: [u8; 3]) {
@@ -530,21 +731,126 @@ fn apply_toggle_disabled_color(rgb: [u8; 3]) {
fn apply_paginator_tab_margin_x(margin: u16) {
write_config_value("paginator_tab_margin_x", &margin.to_string());
send_ipc_command(&format!("layout paginator_tab_margin_x {}", margin));
+ clear_ui::layout::set_paginator_tab_margin_x(margin as f32);
}
fn apply_paginator_tab_margin_y(margin: u16) {
write_config_value("paginator_tab_margin_y", &margin.to_string());
send_ipc_command(&format!("layout paginator_tab_margin_y {}", margin));
+ clear_ui::layout::set_paginator_tab_margin_y(margin as f32);
}
fn apply_paginator_tab_padding_x(padding: u16) {
write_config_value("paginator_tab_padding_x", &padding.to_string());
send_ipc_command(&format!("layout paginator_tab_padding_x {}", padding));
+ clear_ui::layout::set_paginator_tab_padding_x(padding as f32);
}
fn apply_paginator_tab_padding_y(padding: u16) {
write_config_value("paginator_tab_padding_y", &padding.to_string());
send_ipc_command(&format!("layout paginator_tab_padding_y {}", padding));
+ clear_ui::layout::set_paginator_tab_padding_y(padding as f32);
+}
+
+fn apply_plate_padding(padding: u16) {
+ write_config_value("plate_padding", &padding.to_string());
+ clear_ui::layout::set_plate_padding(padding as f32);
+}
+
+fn apply_page_margin(margin: u16) {
+ write_config_value("page_margin", &margin.to_string());
+ clear_ui::layout::set_page_margin(margin as f32);
+}
+
+fn apply_grid_min_col_width(width: u16) {
+ write_config_value("grid_min_col_width", &width.to_string());
+ clear_ui::layout::set_grid_min_col_width(width as f32);
+}
+
+fn apply_section_padding(padding: u16) {
+ write_config_value("section_padding", &padding.to_string());
+ clear_ui::layout::set_section_padding(padding as f32);
+}
+
+fn apply_spinbox_height(height: u16) {
+ write_config_value("spinbox_height", &height.to_string());
+ clear_ui::layout::set_spinbox_height(height as f32);
+}
+
+fn apply_toggle_height(height: u16) {
+ write_config_value("toggle_height", &height.to_string());
+ clear_ui::layout::set_toggle_height(height as f32);
+}
+
+fn apply_color_selector_height(height: u16) {
+ write_config_value("color_selector_height", &height.to_string());
+ clear_ui::layout::set_color_selector_height(height as f32);
+}
+
+fn apply_color_selector_preview_corner_radius(radius: u16) {
+ write_config_value("color_selector_preview_corner_radius", &radius.to_string());
+ clear_ui::layout::set_color_selector_preview_corner_radius(radius as f32);
+}
+
+fn apply_color_selector_preview_margin(margin: u16) {
+ write_config_value("color_selector_preview_margin", &margin.to_string());
+ clear_ui::layout::set_color_selector_preview_margin(margin as f32);
+}
+
+fn apply_textbox_height(height: u16) {
+ write_config_value("textbox_height", &height.to_string());
+ clear_ui::layout::set_textbox_height(height as f32);
+}
+
+fn apply_slider_height(height: u16) {
+ write_config_value("slider_height", &height.to_string());
+ clear_ui::layout::set_slider_height(height as f32);
+}
+
+
+fn apply_font_selector_height(height: u16) {
+ write_config_value("font_selector_height", &height.to_string());
+ clear_ui::layout::set_font_selector_height(height as f32);
+}
+
+fn apply_dropdown_height(height: u16) {
+ write_config_value("dropdown_height", &height.to_string());
+ clear_ui::layout::set_dropdown_height(height as f32);
+}
+
+fn apply_color_selector_font(font: &str) {
+ write_config_value("color_selector_font", &format!("\"{}\"", font));
+ clear_ui::layout::set_color_selector_font(font);
+}
+
+fn apply_menubar_font(font: &str) {
+ write_config_value("menubar_font", &format!("\"{}\"", font));
+ clear_ui::layout::set_menubar_font(font);
+}
+
+fn apply_section_label_font(font: &str) {
+ write_config_value("section_label_font", &format!("\"{}\"", font));
+ clear_ui::layout::set_section_label_font(font);
+}
+
+fn apply_nested_section_label_font(font: &str) {
+ write_config_value("nested_section_label_font", &format!("\"{}\"", font));
+ clear_ui::layout::set_nested_section_label_font(font);
+}
+
+fn apply_nested_section_label_alignment(align: u8) {
+ write_config_value("nested_section_label_alignment", &align.to_string());
+ clear_ui::layout::set_nested_section_label_alignment(align);
+}
+
+fn apply_nested_section_label_offset(offset: i16) {
+ write_config_value("nested_section_label_offset", &offset.to_string());
+ clear_ui::layout::set_nested_section_label_offset(offset as f32);
+}
+
+fn apply_label_margin(margin: u16) {
+ write_config_value("label_margin", &margin.to_string());
+ clear_ui::layout::set_label_margin(margin as f32);
}
const FONTS_CONF_PATH: &str = "/home/lsgalante/.config/fontconfig/fonts.conf";
@@ -691,6 +997,20 @@ pub fn save_preferred_fonts(
let _ = fs::write(FONTS_CONF_PATH, new_content);
}
+pub fn parse_i16_from(content: &str, key: &str, default: i16) -> i16 {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix(key) {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val_str = rest.trim_end_matches('"').trim();
+ if let Ok(val) = val_str.parse::<i16>() {
+ return val;
+ }
+ }
+ }
+ default
+}
+
pub fn parse_u16_from(content: &str, key: &str, default: u16) -> u16 {
for line in content.lines() {
let trimmed = line.trim();
@@ -705,20 +1025,48 @@ pub fn parse_u16_from(content: &str, key: &str, default: u16) -> u16 {
default
}
+pub fn parse_bool_from(content: &str, key: &str, default: bool) -> bool {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix(key) {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val_str = rest.trim_end_matches('"').trim();
+ if let Ok(val) = val_str.parse::<bool>() {
+ return val;
+ }
+ }
+ }
+ default
+}
+
+pub fn parse_f32_from(content: &str, key: &str, default: f32) -> f32 {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix(key) {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val_str = rest.trim_end_matches('"').trim();
+ if let Ok(val) = val_str.parse::<f32>() {
+ return val;
+ }
+ }
+ }
+ default
+}
+
fn read_border_font_size() -> Option<u16> {
- let content = fs::read_to_string("/home/lsgalante/.config/ccec/config.toml").ok()?;
+ let content = fs::read_to_string("/home/lsgalante/.config/cce/config.toml").ok()?;
Some(parse_u16_from(&content, "border_font_size", 11))
}
fn read_status_size() -> Option<u16> {
- let content = fs::read_to_string("/home/lsgalante/.config/ccec/config.toml").ok()?;
+ let content = fs::read_to_string("/home/lsgalante/.config/cce/config.toml").ok()?;
Some(parse_u16_from(&content, "status_font_size", 11))
}
fn write_status_size(size: u16) {
write_config_value("status_font_size", &size.to_string());
let _ = std::process::Command::new("pkill")
- .args(["-f", "clear-status-interface"])
+ .args(["-f", "cce-status-interface"])
.spawn();
}
@@ -800,14 +1148,7 @@ fn write_terminal_size(size: u16) {
let _ = fs::write(path, new_lines.join("\n"));
}
-fn read_paginator_size() -> Option<u16> {
- let content = fs::read_to_string("/home/lsgalante/.config/ccec/config.toml").ok()?;
- Some(parse_u16_from(&content, "paginator_font_size", 12))
-}
-fn write_paginator_size(size: u16) {
- write_config_value("paginator_font_size", &size.to_string());
-}
fn parse_families(output: Option<std::process::Output>) -> Vec<String> {
let mut families = Vec::new();
@@ -840,7 +1181,7 @@ pub async fn fetch_typeface_state() -> InterfaceState {
.output().await.ok();
let mono_fonts = parse_families(mono_output);
- let selected_font = all_fonts.first().cloned();
+
let determine_dropdown_index = |font: &str, sans: &str, serif: &str, mono: &str| -> usize {
if font == sans {
@@ -858,8 +1199,6 @@ pub async fn fetch_typeface_state() -> InterfaceState {
let status_idx = determine_dropdown_index(&status, &sans, &serif, &mono);
let fuzzel_idx = determine_dropdown_index(&fuzzel_font, &sans, &serif, &mono);
let terminal_idx = determine_dropdown_index(&term, &sans, &serif, &mono);
- let paginator_idx = determine_dropdown_index(&paginator_font, &sans, &serif, &mono);
-
let menu_options = vec![
"Sans-Serif".to_string(),
"Serif".to_string(),
@@ -867,26 +1206,23 @@ pub async fn fetch_typeface_state() -> InterfaceState {
"Other".to_string(),
];
- let mut borders_box = TextBox::new(borders.clone()).with_label("Window Borders").with_width(300.0);
+ let mut borders_box = TextBox::new(borders.clone()).with_label("Window Borders");
borders_box.disabled = borders_idx != 3;
- let mut status_box = TextBox::new(status.clone()).with_label("Status Interface").with_width(300.0);
+ let mut status_box = TextBox::new(status.clone()).with_label("Status Interface");
status_box.disabled = status_idx != 3;
- let mut fuzzel_box = TextBox::new(fuzzel_font.clone()).with_label("Fuzzel").with_width(300.0);
+ let mut fuzzel_box = TextBox::new(fuzzel_font.clone()).with_label("Fuzzel");
fuzzel_box.disabled = fuzzel_idx != 3;
- let mut terminal_box = TextBox::new(term.clone()).with_label("Terminal").with_width(300.0);
+ let mut terminal_box = TextBox::new(term.clone()).with_label("Terminal");
terminal_box.disabled = terminal_idx != 3;
- let mut paginator_box = TextBox::new(paginator_font.clone()).with_label("Paginator Tab Labels").with_width(300.0);
- paginator_box.disabled = paginator_idx != 3;
let borders_size = read_border_font_size().unwrap_or(11);
let status_size = read_status_size().unwrap_or(11);
let fuzzel_size = read_fuzzel_size().unwrap_or(14);
let terminal_size = read_terminal_size().unwrap_or(12);
- let paginator_size = read_paginator_size().unwrap_or(12);
let mut state = InterfaceState::default();
state.typeface_loaded = true;
@@ -907,47 +1243,101 @@ pub async fn fetch_typeface_state() -> InterfaceState {
state.status_box = status_box;
state.fuzzel_box = fuzzel_box;
state.terminal_box = terminal_box;
- state.paginator_box = paginator_box;
- state.search_box = TextBox::new(String::new()).with_label("Filter Fonts");
- state.selected_font = selected_font;
- state.list_box = ScrollingList::new(24.0, 4.0);
state.borders_menu = Dropdown::new(menu_options.clone(), borders_idx);
state.status_menu = Dropdown::new(menu_options.clone(), status_idx);
state.fuzzel_menu = Dropdown::new(menu_options.clone(), fuzzel_idx);
- state.terminal_menu = Dropdown::new(menu_options.clone(), terminal_idx);
- state.paginator_menu = Dropdown::new(menu_options, paginator_idx);
+ state.terminal_menu = Dropdown::new(menu_options, terminal_idx);
state.borders_size_box = Spinbox::new(borders_size as i32, 6, 72, 1);
state.status_size_box = Spinbox::new(status_size as i32, 6, 72, 1);
state.fuzzel_size_box = Spinbox::new(fuzzel_size as i32, 6, 72, 1);
state.terminal_size_box = Spinbox::new(terminal_size as i32, 6, 72, 1);
- state.paginator_size_box = Spinbox::new(paginator_size as i32, 6, 72, 1);
state
}
-pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
- let sec_w = 320.0f32;
- let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(10);
-
- // 1. Pages Section
- builder.add_section(&mut final_pc, "Pages", false, |sec| {
- sec.spacing(8.0);
- state.color_selectors[0].color = state.page_low_color;
- sec.widget(&mut state.color_selectors[0], 12.0, 220.0, 40.0);
- sec.spacing(8.0);
- });
+ let sec_w = 260.0f32;
+ let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(5);
- // 2. Layout Section
+ // 1. Layout Section
builder.add_section(&mut final_pc, "Layout", false, |sec| {
sec.spacing(8.0);
state.color_selectors[7].color = state.low_color;
- sec.widget(&mut state.color_selectors[7], 12.0, 220.0, 40.0);
+ sec.widget_full(&mut state.color_selectors[7], 40.0, ctx);
sec.spacing(8.0);
state.color_selectors[1].color = state.high_color;
- sec.widget(&mut state.color_selectors[1], 12.0, 220.0, 40.0);
+ 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(&mut state.color_selectors[2], 12.0, 220.0, 40.0);
+ sec.widget_full(&mut state.color_selectors[2], 40.0, ctx);
+ 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);
+ });
+ 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);
+
+ // Grid Layout child section
+ sec.add_section("Grid Layout", 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);
+ });
+ 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(12.0);
+ state.graph_network_opacity_slider.set_value(state.graph_network_opacity);
+ subsec.widget_full(&mut state.graph_network_opacity_slider, state.slider_height as f32, ctx);
+ subsec.spacing(8.0);
+ });
sec.spacing(8.0);
});
@@ -955,273 +1345,249 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
builder.add_section(&mut final_pc, "Status", false, |sec| {
sec.spacing(8.0);
state.color_selectors[8].color = state.normal_color;
- sec.widget(&mut state.color_selectors[8], 12.0, 220.0, 40.0);
+ sec.widget_full(&mut state.color_selectors[8], 40.0, ctx);
sec.spacing(8.0);
state.color_selectors[3].color = state.disabled_color;
- sec.widget(&mut state.color_selectors[3], 12.0, 220.0, 40.0);
+ sec.widget_full(&mut state.color_selectors[3], 40.0, ctx);
sec.spacing(8.0);
state.color_selectors[4].color = state.separator_color;
- sec.widget(&mut state.color_selectors[4], 12.0, 220.0, 40.0);
+ sec.widget_full(&mut state.color_selectors[4], 40.0, ctx);
sec.spacing(8.0);
});
// 4. Controls Section
builder.add_section(&mut final_pc, "Controls", false, |sec| {
- sec.spacing(8.0);
- state.color_selectors[5].color = state.slider_track_color;
- sec.widget(&mut state.color_selectors[5], 12.0, 220.0, 40.0);
sec.spacing(8.0);
state.color_selectors[6].color = state.color_borders_color;
- sec.widget(&mut state.color_selectors[6], 12.0, 220.0, 40.0);
- sec.spacing(8.0);
- });
+ sec.widget_full(&mut state.color_selectors[6], 40.0, ctx);
+ sec.spacing(12.0);
- // 5. Primary Highlight Section
- builder.add_section(&mut final_pc, "Primary Highlight", false, |sec| {
- sec.spacing(8.0);
- state.color_selectors[10].color = state.primary_highlight_color;
- sec.widget(&mut state.color_selectors[10], 12.0, 220.0, 40.0);
- sec.spacing(8.0);
- });
+ // Slider Section
+ sec.add_section("Slider", false, |subsec| {
+ subsec.spacing(8.0);
+ state.color_selectors[5].color = state.slider_track_color;
+ subsec.widget_full(&mut state.color_selectors[5], 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);
- // 5. Paginator Section
- builder.add_section(&mut final_pc, "Paginator", false, |sec| {
- sec.spacing(8.0);
- state.color_selectors[9].color = state.paginator_sidebar_color;
- sec.widget(&mut state.color_selectors[9], 12.0, 220.0, 40.0);
- sec.spacing(8.0);
- state.color_selectors[11].color = state.paginator_tab_label_color;
- sec.widget(&mut state.color_selectors[11], 12.0, 220.0, 40.0);
- state.tab_margin_spinbox_x.value = state.paginator_tab_margin_x as i32;
- sec.widget(&mut state.tab_margin_spinbox_x, 12.0, 200.0, 44.0);
- sec.spacing(8.0);
- state.tab_margin_spinbox_y.value = state.paginator_tab_margin_y as i32;
- sec.widget(&mut state.tab_margin_spinbox_y, 12.0, 200.0, 44.0);
- sec.spacing(8.0);
- state.tab_padding_spinbox_x.value = state.paginator_tab_padding_x as i32;
- sec.widget(&mut state.tab_padding_spinbox_x, 12.0, 200.0, 44.0);
- sec.spacing(8.0);
- state.tab_padding_spinbox_y.value = state.paginator_tab_padding_y as i32;
- sec.widget(&mut state.tab_padding_spinbox_y, 12.0, 200.0, 44.0);
+
+ // MenuBar Section
+ sec.add_section("MenuBar", false, |subsec| {
+ subsec.spacing(8.0);
+ state.color_selectors[9].color = state.paginator_sidebar_color;
+ subsec.widget_full(&mut state.color_selectors[9], 40.0, ctx);
+ subsec.spacing(8.0);
+ state.color_selectors[11].color = state.paginator_tab_label_color;
+ subsec.widget_full(&mut state.color_selectors[11], 40.0, ctx);
+ state.tab_margin_spinbox_x.value = state.paginator_tab_margin_x as i32;
+ subsec.widget_full(&mut state.tab_margin_spinbox_x, 44.0, ctx);
+ subsec.spacing(8.0);
+ state.tab_margin_spinbox_y.value = state.paginator_tab_margin_y as i32;
+ subsec.widget_full(&mut state.tab_margin_spinbox_y, 44.0, ctx);
+ subsec.spacing(8.0);
+ state.tab_padding_spinbox_x.value = state.paginator_tab_padding_x as i32;
+ subsec.widget_full(&mut state.tab_padding_spinbox_x, 44.0, ctx);
+ subsec.spacing(8.0);
+ state.tab_padding_spinbox_y.value = state.paginator_tab_padding_y as i32;
+ subsec.widget_full(&mut state.tab_padding_spinbox_y, 44.0, ctx);
+ subsec.spacing(8.0);
+ 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);
+ });
+ sec.spacing(12.0);
+
+ // Toggles Section
+ sec.add_section("Toggles", false, |subsec| {
+ subsec.spacing(8.0);
+ state.color_selectors[12].color = state.toggle_enabled_color;
+ subsec.widget_full(&mut state.color_selectors[12], 40.0, ctx);
+ subsec.spacing(8.0);
+ state.color_selectors[13].color = state.toggle_disabled_color;
+ subsec.widget_full(&mut state.color_selectors[13], 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);
+ });
+ 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);
+ });
+ 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_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);
+ });
+ 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);
+ });
+ 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(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);
});
- // 6. Toggles Section
- builder.add_section(&mut final_pc, "Toggles", false, |sec| {
- sec.spacing(8.0);
- state.color_selectors[12].color = state.toggle_enabled_color;
- sec.widget(&mut state.color_selectors[12], 12.0, 220.0, 40.0);
+ // 5. Indicators Section
+ builder.add_section(&mut final_pc, "Indicators", false, |sec| {
sec.spacing(8.0);
- state.color_selectors[13].color = state.toggle_disabled_color;
- sec.widget(&mut state.color_selectors[13], 12.0, 220.0, 40.0);
+ sec.add_section("Primary Highlight", false, |subsec| {
+ subsec.spacing(8.0);
+ state.color_selectors[10].color = state.primary_highlight_color;
+ subsec.widget_full(&mut state.color_selectors[10], 40.0, ctx);
+ subsec.spacing(8.0);
+ });
sec.spacing(8.0);
});
+
let widget_h = 26.0;
const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
- // 7. System Typefaces Section
- builder.add_section(&mut final_pc, "System Typefaces", sec_focused.get(7).copied().unwrap_or(false), |sec| {
+ // 5. Fonts Section
+ builder.add_section(&mut final_pc, "Fonts", sec_focused.get(4).copied().unwrap_or(false), |sec| {
sec.spacing(8.0);
- if !state.typeface_loaded {
- sec.text("Loading typefaces...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
- } else {
- let inner_w = sec_w - 24.0;
- // Sans-Serif
- sec.widget(&mut state.sans_box, 12.0, inner_w, 44.0);
- sec.spacing(12.0);
-
- // Serif
- sec.widget(&mut state.serif_box, 12.0, inner_w, 44.0);
- sec.spacing(12.0);
+ // System Fonts Section
+ sec.add_section("System Fonts", false, |subsec| {
+ subsec.spacing(8.0);
- // Monospace
- sec.widget(&mut state.mono_box, 12.0, inner_w, 44.0);
- sec.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);
- // 8. Program Typefaces Section
- builder.add_section(&mut final_pc, "Program Typefaces", sec_focused.get(8).copied().unwrap_or(false), |sec| {
- sec.spacing(8.0);
+ // Serif
+ subsec.widget_full(&mut state.serif_box, 44.0, ctx);
+ subsec.spacing(12.0);
- if !state.typeface_loaded {
- sec.text("Loading typefaces...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
- } else {
- let inner_w = sec_w - 24.0;
-
- // Window Borders
- let start_y = sec.ay();
- let cols = sec.row_layout(2, 10.0);
- if cols.len() == 2 {
- state.borders_menu.set_row_rect(cols[0].0, cols[0].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.borders_menu, cols[0].0, start_y, cols[0].1, widget_h);
- state.borders_size_box.set_row_rect(cols[1].0, cols[1].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.borders_size_box, cols[1].0, start_y, cols[1].1, widget_h);
- }
- sec.spacing(widget_h);
- sec.widget(&mut state.borders_box, 12.0, inner_w, 44.0);
- sec.spacing(16.0);
-
- // Status Interface
- let start_y = sec.ay();
- let cols = sec.row_layout(2, 10.0);
- if cols.len() == 2 {
- state.status_menu.set_row_rect(cols[0].0, cols[0].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.status_menu, cols[0].0, start_y, cols[0].1, widget_h);
- state.status_size_box.set_row_rect(cols[1].0, cols[1].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.status_size_box, cols[1].0, start_y, cols[1].1, widget_h);
- }
- sec.spacing(widget_h);
- sec.widget(&mut state.status_box, 12.0, inner_w, 44.0);
- sec.spacing(16.0);
-
- // Fuzzel
- let start_y = sec.ay();
- let cols = sec.row_layout(2, 10.0);
- if cols.len() == 2 {
- state.fuzzel_menu.set_row_rect(cols[0].0, cols[0].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.fuzzel_menu, cols[0].0, start_y, cols[0].1, widget_h);
- state.fuzzel_size_box.set_row_rect(cols[1].0, cols[1].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.fuzzel_size_box, cols[1].0, start_y, cols[1].1, widget_h);
+ // Monospace
+ subsec.widget_full(&mut state.mono_box, 44.0, ctx);
+ subsec.spacing(8.0);
}
- sec.spacing(widget_h);
- sec.widget(&mut state.fuzzel_box, 12.0, inner_w, 44.0);
- sec.spacing(16.0);
-
- // Terminal
- let start_y = sec.ay();
- let cols = sec.row_layout(2, 10.0);
- if cols.len() == 2 {
- state.terminal_menu.set_row_rect(cols[0].0, cols[0].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.terminal_menu, cols[0].0, start_y, cols[0].1, widget_h);
- state.terminal_size_box.set_row_rect(cols[1].0, cols[1].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.terminal_size_box, cols[1].0, start_y, cols[1].1, widget_h);
- }
- sec.spacing(widget_h);
- sec.widget(&mut state.terminal_box, 12.0, inner_w, 44.0);
- sec.spacing(16.0);
-
- // Paginator Tab Labels
- let start_y = sec.ay();
- let cols = sec.row_layout(2, 10.0);
- if cols.len() == 2 {
- state.paginator_menu.set_row_rect(cols[0].0, cols[0].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.paginator_menu, cols[0].0, start_y, cols[0].1, widget_h);
- state.paginator_size_box.set_row_rect(cols[1].0, cols[1].1);
- clear_ui::layout::render_widget(sec.pc, &mut state.paginator_size_box, cols[1].0, start_y, cols[1].1, widget_h);
- }
- sec.spacing(widget_h);
- sec.widget(&mut state.paginator_box, 12.0, inner_w, 44.0);
- sec.spacing(8.0);
- }
- });
-
- // 9. Typefaces Section (List & Preview)
- builder.add_section(&mut final_pc, "Typefaces", sec_focused.get(9).copied().unwrap_or(false), |sec| {
+ });
sec.spacing(12.0);
- if !state.typeface_loaded {
- sec.text("Loading installed fonts...", 12.0, 0.0, 12.0, TEXT_DIM);
- sec.spacing(18.0);
- } else {
- let inner_w = sec_w - 24.0;
-
- // 1. Search Box
- let search_x = sec.left + 12.0;
- state.search_box.set_row_rect(search_x, inner_w);
- let search_y = sec.ay();
- clear_ui::layout::render_widget(
- sec.pc,
- &mut state.search_box,
- search_x,
- search_y,
- inner_w,
- 44.0,
- );
- sec.spacing(44.0 + 12.0);
-
- // 2. Scrolling List Box
- let list_box_x = sec.left + 12.0;
- let list_box_y = sec.ay();
- let list_box_h = 200.0;
-
- clear_ui::layout::render_widget(sec.pc, &mut state.list_box, list_box_x, list_box_y, inner_w, list_box_h);
-
- let query = state.search_box.text.to_lowercase();
- let matching_fonts: Vec<&String> = state.all_fonts.iter()
- .filter(|font| font.to_lowercase().contains(&query))
- .collect();
-
- if state.font_buttons.len() != matching_fonts.len() {
- state.font_buttons.clear();
- state.copy_buttons.clear();
- for _ in 0..matching_fonts.len() {
- state.font_buttons.push(InteractiveListItem::new(""));
- state.copy_buttons.push(Button::new_copy_icon(0.0, 0.0, 0.0, 0.0));
- }
- }
-
- let btn_h = 24.0;
- let list_inner_x = sec.left + 16.0;
- let list_inner_w = inner_w - 16.0;
-
- state.list_box.update_bounds(matching_fonts.len(), list_box_y, list_box_h);
-
- for (idx, font_name) in matching_fonts.iter().enumerate() {
- if let Some(draw_y) = state.list_box.get_item_draw_y(idx, 0.0) {
- let is_selected = state.selected_font.as_ref() == Some(*font_name);
-
- let font_btn = &mut state.font_buttons[idx];
- font_btn.title = font_name.to_string();
- font_btn.selected = is_selected;
- clear_ui::layout::render_widget(sec.pc, font_btn, list_inner_x, draw_y, list_inner_w - 44.0, btn_h);
-
- let copy_btn = &mut state.copy_buttons[idx];
- copy_btn.set_text("📋");
- copy_btn.selected = is_selected;
- clear_ui::layout::render_widget(sec.pc, copy_btn, list_inner_x + list_inner_w - 40.0, draw_y, 40.0, btn_h);
- }
- }
-
- if matching_fonts.is_empty() {
- sec.pc.text("No fonts match query", list_inner_x + 8.0, list_box_y + 16.0, 12.0, TEXT_DIM);
- }
+ // Program Fonts Section
+ sec.add_section("Program Fonts", false, |subsec| {
+ subsec.spacing(8.0);
- sec.spacing(list_box_h + 12.0);
-
- // 3. Info Box
- let info_h = 96.0;
- let info_y = sec.ay();
- let info_x = sec.left + 12.0;
- let mut info_box = InfoBox::new(
- "Font Directories & Installation",
- vec![
- "• Active Directory: ~/Dropbox/Fonts".to_string(),
- "• Place TTF/OTF files there to install new fonts.".to_string(),
- "• Changes will be cached automatically by fontconfig.".to_string(),
- ],
- );
- clear_ui::layout::render_widget(sec.pc, &mut info_box, info_x, info_y, inner_w, info_h);
- sec.spacing(info_h + 12.0);
-
- // 4. Preview Card
- let card_x = sec.left + 12.0;
- if let Some(ref font_name) = state.selected_font {
- let card_h = 240.0;
- let card_y = sec.ay();
- let mut font_preview = FontPreview::new(font_name.clone());
- clear_ui::layout::render_widget(sec.pc, &mut font_preview, card_x, card_y, inner_w, card_h);
- sec.spacing(card_h + 8.0);
+ if !state.typeface_loaded {
+ subsec.text("Loading typefaces...", 12.0, 0.0, 12.0, TEXT_DIM);
+ subsec.spacing(18.0);
} else {
- let text_y = sec.ay() + 20.0;
- sec.pc.text("Select a font to preview", card_x + 12.0, text_y, 13.0, TEXT_DIM);
- sec.spacing(40.0);
+ // Window Borders
+ let start_y = subsec.ay();
+ let cols = subsec.row_layout(2, 10.0);
+ if cols.len() == 2 {
+ state.borders_menu.set_row_rect(cols[0].0, cols[0].1);
+ clear_ui::layout::render_widget(subsec.pc, &mut state.borders_menu, cols[0].0, start_y, cols[0].1, widget_h, ctx);
+ state.borders_size_box.set_row_rect(cols[1].0, cols[1].1);
+ clear_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();
+ let cols = subsec.row_layout(2, 10.0);
+ if cols.len() == 2 {
+ state.status_menu.set_row_rect(cols[0].0, cols[0].1);
+ clear_ui::layout::render_widget(subsec.pc, &mut state.status_menu, cols[0].0, start_y, cols[0].1, widget_h, ctx);
+ state.status_size_box.set_row_rect(cols[1].0, cols[1].1);
+ clear_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();
+ let cols = subsec.row_layout(2, 10.0);
+ if cols.len() == 2 {
+ state.fuzzel_menu.set_row_rect(cols[0].0, cols[0].1);
+ clear_ui::layout::render_widget(subsec.pc, &mut state.fuzzel_menu, cols[0].0, start_y, cols[0].1, widget_h, ctx);
+ state.fuzzel_size_box.set_row_rect(cols[1].0, cols[1].1);
+ clear_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();
+ let cols = subsec.row_layout(2, 10.0);
+ if cols.len() == 2 {
+ state.terminal_menu.set_row_rect(cols[0].0, cols[0].1);
+ clear_ui::layout::render_widget(subsec.pc, &mut state.terminal_menu, cols[0].0, start_y, cols[0].1, widget_h, ctx);
+ state.terminal_size_box.set_row_rect(cols[1].0, cols[1].1);
+ clear_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);
});
final_pc
@@ -1302,12 +1668,140 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.paginator_tab_padding_y = padding;
apply_paginator_tab_padding_y(padding);
}
+ InterfaceMessage::SetSectionPadding(padding) => {
+ state.section_padding = padding;
+ apply_section_padding(padding);
+ }
+ InterfaceMessage::SetPlatePadding(padding) => {
+ state.plate_padding = padding;
+ apply_plate_padding(padding);
+ }
+ InterfaceMessage::SetPageMargin(margin) => {
+ state.page_margin = margin;
+ apply_page_margin(margin);
+ }
+ InterfaceMessage::SetGridMinColWidth(width) => {
+ state.grid_min_col_width = width;
+ apply_grid_min_col_width(width);
+ }
+ InterfaceMessage::SetSpinboxHeight(height) => {
+ state.spinbox_height = height;
+ apply_spinbox_height(height);
+ }
+ InterfaceMessage::SetToggleHeight(height) => {
+ state.toggle_height = height;
+ apply_toggle_height(height);
+ }
+ InterfaceMessage::SetColorSelectorHeight(height) => {
+ state.color_selector_height = height;
+ apply_color_selector_height(height);
+ }
+ InterfaceMessage::SetColorSelectorPreviewCornerRadius(radius) => {
+ state.color_selector_preview_corner_radius = radius;
+ apply_color_selector_preview_corner_radius(radius);
+ }
+ InterfaceMessage::SetColorSelectorPreviewMargin(margin) => {
+ state.color_selector_preview_margin = margin;
+ apply_color_selector_preview_margin(margin);
+ }
+ InterfaceMessage::SetTextboxHeight(height) => {
+ state.textbox_height = height;
+ apply_textbox_height(height);
+ }
+ InterfaceMessage::SetSliderHeight(height) => {
+ state.slider_height = height;
+ apply_slider_height(height);
+ }
+ InterfaceMessage::SetFontSelectorHeight(height) => {
+ state.font_selector_height = height;
+ apply_font_selector_height(height);
+ }
+ InterfaceMessage::SetDropdownHeight(height) => {
+ state.dropdown_height = height;
+ apply_dropdown_height(height);
+ }
+ InterfaceMessage::SetColorSelectorFont(font) => {
+ state.color_selector_font = font.clone();
+ state.color_selector_font_selector.font_family = font.clone();
+ for cs in &mut state.color_selectors {
+ cs.font_family = font.clone();
+ }
+ apply_color_selector_font(&font);
+ }
+ InterfaceMessage::SetMenubarFont(font) => {
+ state.menubar_font = font.clone();
+ state.menubar_font_selector.font_family = font.clone();
+ apply_menubar_font(&font);
+ }
+ InterfaceMessage::SetSectionLabelFont(font) => {
+ state.section_label_font = font.clone();
+ state.section_label_font_selector.font_family = font.clone();
+ apply_section_label_font(&font);
+ }
+ InterfaceMessage::SetNestedSectionLabelFont(font) => {
+ state.nested_section_label_font = font.clone();
+ state.nested_section_label_font_selector.font_family = font.clone();
+ apply_nested_section_label_font(&font);
+ }
+ InterfaceMessage::SetNestedSectionLabelAlignment(idx) => {
+ state.nested_section_label_alignment = idx as u8;
+ state.label_alignment_menu.selected = idx;
+ apply_nested_section_label_alignment(idx as u8);
+ }
+ InterfaceMessage::SetNestedSectionLabelOffset(offset) => {
+ state.nested_section_label_offset = offset;
+ state.label_offset_spinbox.value = offset as i32;
+ apply_nested_section_label_offset(offset);
+ }
+ InterfaceMessage::SetLabelMargin(margin) => {
+ state.label_margin = margin;
+ state.label_margin_spinbox.value = margin as i32;
+ apply_label_margin(margin);
+ }
+ InterfaceMessage::SetGraphShowGrid(show) => {
+ state.graph_show_grid = show;
+ state.graph_show_grid_toggle.set_toggled(show);
+ write_config_value("graph_show_grid", &show.to_string());
+ cce_graph_reload();
+ }
+ InterfaceMessage::SetGraphSnapEnabled(snap) => {
+ state.graph_snap_enabled = snap;
+ state.graph_snap_enabled_toggle.set_toggled(snap);
+ write_config_value("graph_snap_enabled", &snap.to_string());
+ cce_graph_reload();
+ }
+ InterfaceMessage::SetGraphUniformBackground(uniform) => {
+ state.graph_uniform_background = uniform;
+ state.graph_uniform_background_toggle.set_toggled(uniform);
+ write_config_value("graph_uniform_background", &uniform.to_string());
+ cce_graph_reload();
+ }
+ InterfaceMessage::SetGraphOpacity(opacity) => {
+ state.graph_network_opacity = opacity;
+ state.graph_network_opacity_slider.set_value(opacity);
+ write_config_value("graph_network_opacity", &format!("{:.2}", opacity));
+ cce_graph_reload();
+ }
InterfaceMessage::PickLowColor | InterfaceMessage::PickHighColor | InterfaceMessage::PickDisabledColor | InterfaceMessage::PickSeparatorColor | InterfaceMessage::PickVisualGuides | InterfaceMessage::PickSliderTrackColor | InterfaceMessage::PickPageLowColor | InterfaceMessage::PickColorBordersColor | InterfaceMessage::PickNormalColor | InterfaceMessage::PickPaginatorSidebarColor | InterfaceMessage::PickPrimaryHighlightColor | InterfaceMessage::PickPaginatorTabLabelColor | InterfaceMessage::PickToggleEnabledColor | InterfaceMessage::PickToggleDisabledColor => {}
InterfaceMessage::Refreshed(new) => {
let was_mx_hovered = state.tab_margin_spinbox_x.hovered();
let was_my_hovered = state.tab_margin_spinbox_y.hovered();
let was_px_hovered = state.tab_padding_spinbox_x.hovered();
let was_py_hovered = state.tab_padding_spinbox_y.hovered();
+ let was_sp_hovered = state.section_padding_spinbox.hovered();
+ let was_pp_hovered = state.plate_padding_spinbox.hovered();
+ let was_pm_hovered = state.page_margin_spinbox.hovered();
+ let was_gm_hovered = state.grid_min_col_width_spinbox.hovered();
+ let was_sh_hovered = state.spinbox_height_spinbox.hovered();
+ let was_th_hovered = state.toggle_height_spinbox.hovered();
+ let was_gsg_hovered = state.graph_show_grid_toggle.hovered();
+ let was_gse_hovered = state.graph_snap_enabled_toggle.hovered();
+ let was_gub_hovered = state.graph_uniform_background_toggle.hovered();
+ let was_gno_hovered = state.graph_network_opacity_slider.hovered();
+ let was_csh_hovered = state.color_selector_height_spinbox.hovered();
+ let was_tbh_hovered = state.textbox_height_spinbox.hovered();
+ let was_fsh_hovered = state.font_selector_height_spinbox.hovered();
+ let was_lm_hovered = state.label_margin_spinbox.hovered();
// Preserve typeface fields
let typeface_loaded = state.typeface_loaded;
let sans_serif = state.sans_serif.clone();
@@ -1327,22 +1821,14 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
let status_box = state.status_box.clone();
let fuzzel_box = state.fuzzel_box.clone();
let terminal_box = state.terminal_box.clone();
- let paginator_box = state.paginator_box.clone();
- let search_box = state.search_box.clone();
- let selected_font = state.selected_font.clone();
- let list_box = state.list_box.clone();
let borders_menu = state.borders_menu.clone();
let status_menu = state.status_menu.clone();
let fuzzel_menu = state.fuzzel_menu.clone();
let terminal_menu = state.terminal_menu.clone();
- let paginator_menu = state.paginator_menu.clone();
let borders_size_box = state.borders_size_box.clone();
let status_size_box = state.status_size_box.clone();
let fuzzel_size_box = state.fuzzel_size_box.clone();
let terminal_size_box = state.terminal_size_box.clone();
- let paginator_size_box = state.paginator_size_box.clone();
- let font_buttons = state.font_buttons.clone();
- let copy_buttons = state.copy_buttons.clone();
*state = new;
@@ -1350,49 +1836,54 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.tab_margin_spinbox_y.set_hovered(was_my_hovered);
state.tab_padding_spinbox_x.set_hovered(was_px_hovered);
state.tab_padding_spinbox_y.set_hovered(was_py_hovered);
-
- state.typeface_loaded = typeface_loaded;
- state.sans_serif = sans_serif;
- state.serif = serif;
- state.monospace = monospace;
- state.window_borders = window_borders;
- state.status_interface = status_interface;
- state.fuzzel = fuzzel;
- state.terminal = terminal;
- state.paginator = paginator;
- state.all_fonts = all_fonts;
- state.mono_fonts = mono_fonts;
- state.sans_box = sans_box;
- state.serif_box = serif_box;
- state.mono_box = mono_box;
- state.borders_box = borders_box;
- state.status_box = status_box;
- state.fuzzel_box = fuzzel_box;
- state.terminal_box = terminal_box;
- state.paginator_box = paginator_box;
- state.search_box = search_box;
- state.selected_font = selected_font;
- state.list_box = list_box;
- state.borders_menu = borders_menu;
- state.status_menu = status_menu;
- state.fuzzel_menu = fuzzel_menu;
- state.terminal_menu = terminal_menu;
- state.paginator_menu = paginator_menu;
- state.borders_size_box = borders_size_box;
- state.status_size_box = status_size_box;
- state.fuzzel_size_box = fuzzel_size_box;
- state.terminal_size_box = terminal_size_box;
- state.paginator_size_box = paginator_size_box;
- state.font_buttons = font_buttons;
- state.copy_buttons = copy_buttons;
+ state.section_padding_spinbox.set_hovered(was_sp_hovered);
+ state.plate_padding_spinbox.set_hovered(was_pp_hovered);
+ state.page_margin_spinbox.set_hovered(was_pm_hovered);
+ state.grid_min_col_width_spinbox.set_hovered(was_gm_hovered);
+ state.spinbox_height_spinbox.set_hovered(was_sh_hovered);
+ state.toggle_height_spinbox.set_hovered(was_th_hovered);
+ state.graph_show_grid_toggle.set_hovered(was_gsg_hovered);
+ state.graph_snap_enabled_toggle.set_hovered(was_gse_hovered);
+ state.graph_uniform_background_toggle.set_hovered(was_gub_hovered);
+ state.graph_network_opacity_slider.set_hovered(was_gno_hovered);
+ state.color_selector_height_spinbox.set_hovered(was_csh_hovered);
+ state.textbox_height_spinbox.set_hovered(was_tbh_hovered);
+ state.font_selector_height_spinbox.set_hovered(was_fsh_hovered);
+ state.label_margin_spinbox.set_hovered(was_lm_hovered);
+
+ if typeface_loaded {
+ state.typeface_loaded = typeface_loaded;
+ state.sans_serif = sans_serif;
+ state.serif = serif;
+ state.monospace = monospace;
+ state.window_borders = window_borders;
+ state.status_interface = status_interface;
+ state.fuzzel = fuzzel;
+ state.terminal = terminal;
+ state.paginator = paginator;
+ state.all_fonts = all_fonts;
+ state.mono_fonts = mono_fonts;
+ state.sans_box = sans_box;
+ state.serif_box = serif_box;
+ state.mono_box = mono_box;
+ state.borders_box = borders_box;
+ state.status_box = status_box;
+ state.fuzzel_box = fuzzel_box;
+ state.terminal_box = terminal_box;
+ state.borders_menu = borders_menu;
+ state.status_menu = status_menu;
+ state.fuzzel_menu = fuzzel_menu;
+ state.terminal_menu = terminal_menu;
+ state.borders_size_box = borders_size_box;
+ state.status_size_box = status_size_box;
+ state.fuzzel_size_box = fuzzel_size_box;
+ state.terminal_size_box = terminal_size_box;
+ }
}
InterfaceMessage::TypefaceRefreshed(new) => {
state.typeface_loaded = new.typeface_loaded;
state.all_fonts = new.all_fonts;
state.mono_fonts = new.mono_fonts;
- if state.selected_font.is_none() {
- state.selected_font = new.selected_font.clone();
- }
if !state.sans_box.editing {
state.sans_serif = new.sans_serif.clone();
state.sans_box = new.sans_box;
@@ -1425,24 +1916,10 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.terminal_box = new.terminal_box;
state.terminal_menu = new.terminal_menu;
}
- if !state.paginator_box.editing {
- state.paginator = new.paginator.clone();
- state.paginator_box = new.paginator_box;
- state.paginator_menu = new.paginator_menu;
- }
- if !state.search_box.editing {
- state.search_box = new.search_box;
- }
state.borders_size_box = new.borders_size_box;
state.status_size_box = new.status_size_box;
state.fuzzel_size_box = new.fuzzel_size_box;
state.terminal_size_box = new.terminal_size_box;
- state.paginator_size_box = new.paginator_size_box;
- state.font_buttons = new.font_buttons;
- state.copy_buttons = new.copy_buttons;
- let old_scroll = state.list_box.scroll_y();
- state.list_box = new.list_box;
- state.list_box.set_scroll_y(old_scroll);
}
InterfaceMessage::SetSans(sans) => {
state.sans_serif = sans.clone();
@@ -1463,10 +1940,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.terminal = state.sans_serif.clone();
state.terminal_box.text = state.sans_serif.clone();
}
- if state.paginator_menu.selected == 0 {
- state.paginator = state.sans_serif.clone();
- state.paginator_box.text = state.sans_serif.clone();
- }
save_preferred_fonts(
&state.sans_serif,
&state.serif,
@@ -1497,10 +1970,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.terminal = state.serif.clone();
state.terminal_box.text = state.serif.clone();
}
- if state.paginator_menu.selected == 1 {
- state.paginator = state.serif.clone();
- state.paginator_box.text = state.serif.clone();
- }
save_preferred_fonts(
&state.sans_serif,
&state.serif,
@@ -1531,10 +2000,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.terminal = state.monospace.clone();
state.terminal_box.text = state.monospace.clone();
}
- if state.paginator_menu.selected == 2 {
- state.paginator = state.monospace.clone();
- state.paginator_box.text = state.monospace.clone();
- }
save_preferred_fonts(
&state.sans_serif,
&state.serif,
@@ -1602,75 +2067,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
&state.paginator,
);
}
- InterfaceMessage::SetPaginator(paginator) => {
- state.paginator = paginator.clone();
- state.paginator_box.text = paginator;
- save_preferred_fonts(
- &state.sans_serif,
- &state.serif,
- &state.monospace,
- &state.window_borders,
- &state.status_interface,
- &state.fuzzel,
- &state.terminal,
- &state.paginator,
- );
- }
- InterfaceMessage::SetSearch(search) => {
- state.search_box.text = search;
- }
- InterfaceMessage::SelectFont(font) => {
- state.selected_font = Some(font);
- }
- InterfaceMessage::CopyFontName(font) => {
- use std::io::Write;
- std::thread::spawn({
- let text = font.clone();
- move || {
- let mut copied = false;
- let child = std::process::Command::new("wl-copy")
- .stdin(std::process::Stdio::piped())
- .stderr(std::process::Stdio::piped())
- .spawn();
- match child {
- Ok(mut child) => {
- if let Some(mut stdin) = child.stdin.take() {
- let _ = stdin.write_all(text.as_bytes());
- }
- match child.wait_with_output() {
- Ok(output) => {
- if output.status.success() {
- copied = true;
- } else {
- let err_msg = String::from_utf8_lossy(&output.stderr);
- eprintln!("wl-copy exited with error status: {:?}, stderr: {}", output.status, err_msg);
- }
- }
- Err(e) => {
- eprintln!("wl-copy wait failed: {:?}", e);
- }
- }
- }
- Err(e) => {
- eprintln!("wl-copy spawn failed: {:?}", e);
- }
- }
- if !copied {
- if let Ok(mut child) = std::process::Command::new("xclip")
- .arg("-selection")
- .arg("clipboard")
- .stdin(std::process::Stdio::piped())
- .spawn()
- {
- if let Some(mut stdin) = child.stdin.take() {
- let _ = stdin.write_all(text.as_bytes());
- }
- let _ = child.wait();
- }
- }
- }
- });
- }
+
InterfaceMessage::SetBordersMenu(idx) => {
state.borders_menu.selected = idx;
state.borders_box.disabled = idx != 3;
@@ -1767,30 +2164,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
&state.paginator,
);
}
- InterfaceMessage::SetPaginatorMenu(idx) => {
- state.paginator_menu.selected = idx;
- state.paginator_box.disabled = idx != 3;
- if idx == 0 {
- state.paginator = state.sans_serif.clone();
- state.paginator_box.text = state.sans_serif.clone();
- } else if idx == 1 {
- state.paginator = state.serif.clone();
- state.paginator_box.text = state.serif.clone();
- } else if idx == 2 {
- state.paginator = state.monospace.clone();
- state.paginator_box.text = state.monospace.clone();
- }
- save_preferred_fonts(
- &state.sans_serif,
- &state.serif,
- &state.monospace,
- &state.window_borders,
- &state.status_interface,
- &state.fuzzel,
- &state.terminal,
- &state.paginator,
- );
- }
InterfaceMessage::SetBordersSize(val) => {
state.borders_size_box.value = val;
write_config_value("border_font_size", &val.to_string());
@@ -1808,10 +2181,6 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
state.terminal_size_box.value = val;
write_terminal_size(val as u16);
}
- InterfaceMessage::SetPaginatorSize(val) => {
- state.paginator_size_box.value = val;
- write_paginator_size(val as u16);
- }
}
}
@@ -1909,4 +2278,603 @@ mod tests {
assert_eq!(parse_font_for_alias(content, "monospace"), Some("Berkeley Mono".to_string()));
assert_eq!(parse_font_for_alias(content, "serif"), None);
}
-}
+
+ #[test]
+ fn test_read_write_section_padding() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_section_padding_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse section_padding when missing (should return default 8)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "section_padding", 8);
+ assert_eq!(val, 8);
+
+ // 3. Write section_padding config
+ assert!(write_config_value_path(path_str, "section_padding", "12"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("section_padding = 12"));
+
+ // 4. Parse section_padding when present (should return written value 12)
+ let val2 = parse_u16_from(&updated, "section_padding", 8);
+ assert_eq!(val2, 12);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_plate_padding() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_plate_padding_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse plate_padding when missing (should return default 20)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "plate_padding", 20);
+ assert_eq!(val, 20);
+
+ // 3. Write plate_padding config
+ assert!(write_config_value_path(path_str, "plate_padding", "15"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("plate_padding = 15"));
+
+ // 4. Parse plate_padding when present (should return written value 15)
+ let val2 = parse_u16_from(&updated, "plate_padding", 20);
+ assert_eq!(val2, 15);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_page_margin() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_page_margin_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse page_margin when missing (should return default 20)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "page_margin", 20);
+ assert_eq!(val, 20);
+
+ // 3. Write page_margin config
+ assert!(write_config_value_path(path_str, "page_margin", "15"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("page_margin = 15"));
+
+ // 4. Parse page_margin when present (should return written value 15)
+ let val2 = parse_u16_from(&updated, "page_margin", 20);
+ assert_eq!(val2, 15);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_spinbox_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_spinbox_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse spinbox_height when missing (should return default 26)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "spinbox_height", 26);
+ assert_eq!(val, 26);
+
+ // 3. Write spinbox_height config
+ assert!(write_config_value_path(path_str, "spinbox_height", "30"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("spinbox_height = 30"));
+
+ // 4. Parse spinbox_height when present (should return written value 30)
+ let val2 = parse_u16_from(&updated, "spinbox_height", 26);
+ assert_eq!(val2, 30);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_toggle_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_toggle_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse toggle_height when missing (should return default 44)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "toggle_height", 44);
+ assert_eq!(val, 44);
+
+ // 3. Write toggle_height config
+ assert!(write_config_value_path(path_str, "toggle_height", "52"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("toggle_height = 52"));
+
+ // 4. Parse toggle_height when present (should return written value 52)
+ let val2 = parse_u16_from(&updated, "toggle_height", 44);
+ assert_eq!(val2, 52);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_color_selector_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_color_selector_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse color_selector_height when missing (should return default 22)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "color_selector_height", 22);
+ assert_eq!(val, 22);
+
+ // 3. Write color_selector_height config
+ assert!(write_config_value_path(path_str, "color_selector_height", "28"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("color_selector_height = 28"));
+
+ // 4. Parse color_selector_height when present (should return written value 28)
+ let val2 = parse_u16_from(&updated, "color_selector_height", 22);
+ assert_eq!(val2, 28);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_textbox_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_textbox_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse textbox_height when missing (should return default 44)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "textbox_height", 44);
+ assert_eq!(val, 44);
+
+ // 3. Write textbox_height config
+ assert!(write_config_value_path(path_str, "textbox_height", "48"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("textbox_height = 48"));
+
+ // 4. Parse textbox_height when present (should return written value 48)
+ let val2 = parse_u16_from(&updated, "textbox_height", 44);
+ assert_eq!(val2, 48);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_color_selector_font() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_color_selector_font_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse color_selector_font when missing (should return default "monospace")
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_string_from(&content, "color_selector_font", "monospace");
+ assert_eq!(val, "monospace");
+
+ // 3. Write color_selector_font config
+ assert!(write_config_value_path(path_str, "color_selector_font", "\"Berkeley Mono\""));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("color_selector_font = \"Berkeley Mono\""));
+
+ // 4. Parse color_selector_font when present (should return written value)
+ let val2 = parse_string_from(&updated, "color_selector_font", "monospace");
+ assert_eq!(val2, "Berkeley Mono");
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_menubar_font() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_menubar_font_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse menubar_font when missing (should return default "Outfit")
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_string_from(&content, "menubar_font", "Outfit");
+ assert_eq!(val, "Outfit");
+
+ // 3. Write menubar_font config
+ assert!(write_config_value_path(path_str, "menubar_font", "\"Inter\""));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("menubar_font = \"Inter\""));
+
+ // 4. Parse menubar_font when present (should return written value)
+ let val2 = parse_string_from(&updated, "menubar_font", "Outfit");
+ assert_eq!(val2, "Inter");
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_font_selector_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_font_selector_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse font_selector_height when missing (should return default 44)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "font_selector_height", 44);
+ assert_eq!(val, 44);
+
+ // 3. Write font_selector_height config
+ assert!(write_config_value_path(path_str, "font_selector_height", "48"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("font_selector_height = 48"));
+
+ // 4. Parse font_selector_height when present (should return written value 48)
+ let val2 = parse_u16_from(&updated, "font_selector_height", 44);
+ assert_eq!(val2, 48);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_grid_min_col_width() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_grid_min_col_width_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse grid_min_col_width when missing (should return default 260)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "grid_min_col_width", 260);
+ assert_eq!(val, 260);
+
+ // 3. Write grid_min_col_width config
+ assert!(write_config_value_path(path_str, "grid_min_col_width", "280"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("grid_min_col_width = 280"));
+
+ // 4. Parse grid_min_col_width when present (should return written value 280)
+ let val2 = parse_u16_from(&updated, "grid_min_col_width", 260);
+ assert_eq!(val2, 280);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_color_selector_preview_corner_radius() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_color_selector_preview_corner_radius_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse color_selector_preview_corner_radius when missing (should return default 4)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "color_selector_preview_corner_radius", 4);
+ assert_eq!(val, 4);
+
+ // 3. Write color_selector_preview_corner_radius config
+ assert!(write_config_value_path(path_str, "color_selector_preview_corner_radius", "8"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("color_selector_preview_corner_radius = 8"));
+
+ // 4. Parse color_selector_preview_corner_radius when present (should return written value 8)
+ let val2 = parse_u16_from(&updated, "color_selector_preview_corner_radius", 4);
+ assert_eq!(val2, 8);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_color_selector_preview_margin() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_color_selector_preview_margin_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse color_selector_preview_margin when missing (should return default 0)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "color_selector_preview_margin", 0);
+ assert_eq!(val, 0);
+
+ // 3. Write color_selector_preview_margin config
+ assert!(write_config_value_path(path_str, "color_selector_preview_margin", "3"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("color_selector_preview_margin = 3"));
+
+ // 4. Parse color_selector_preview_margin when present (should return written value 3)
+ let val2 = parse_u16_from(&updated, "color_selector_preview_margin", 0);
+ assert_eq!(val2, 3);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_paginator_tab_margin_x() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_paginator_tab_margin_x_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "paginator_tab_margin_x", 5);
+ assert_eq!(val, 5);
+
+ assert!(write_config_value_path(path_str, "paginator_tab_margin_x", "8"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("paginator_tab_margin_x = 8"));
+
+ let val2 = parse_u16_from(&updated, "paginator_tab_margin_x", 5);
+ assert_eq!(val2, 8);
+
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_paginator_tab_margin_y() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_paginator_tab_margin_y_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "paginator_tab_margin_y", 10);
+ assert_eq!(val, 10);
+
+ assert!(write_config_value_path(path_str, "paginator_tab_margin_y", "12"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("paginator_tab_margin_y = 12"));
+
+ let val2 = parse_u16_from(&updated, "paginator_tab_margin_y", 10);
+ assert_eq!(val2, 12);
+
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_paginator_tab_padding_x() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_paginator_tab_padding_x_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "paginator_tab_padding_x", 10);
+ assert_eq!(val, 10);
+
+ assert!(write_config_value_path(path_str, "paginator_tab_padding_x", "15"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("paginator_tab_padding_x = 15"));
+
+ let val2 = parse_u16_from(&updated, "paginator_tab_padding_x", 10);
+ assert_eq!(val2, 15);
+
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_paginator_tab_padding_y() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_paginator_tab_padding_y_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "paginator_tab_padding_y", 14);
+ assert_eq!(val, 14);
+
+ assert!(write_config_value_path(path_str, "paginator_tab_padding_y", "20"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("paginator_tab_padding_y = 20"));
+
+ let val2 = parse_u16_from(&updated, "paginator_tab_padding_y", 14);
+ assert_eq!(val2, 20);
+
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_slider_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_slider_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse slider_height when missing (should return default 28)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "slider_height", 28);
+ assert_eq!(val, 28);
+
+ // 3. Write slider_height config
+ assert!(write_config_value_path(path_str, "slider_height", "32"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("slider_height = 32"));
+
+ // 4. Parse slider_height when present (should return written value 32)
+ let val2 = parse_u16_from(&updated, "slider_height", 28);
+ assert_eq!(val2, 32);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_nested_section_label_alignment() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_nested_section_label_alignment_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse when missing (should return default 0)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "nested_section_label_alignment", 0);
+ assert_eq!(val, 0);
+
+ // 3. Write alignment config
+ assert!(write_config_value_path(path_str, "nested_section_label_alignment", "2"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("nested_section_label_alignment = 2"));
+
+ // 4. Parse when present (should return written value 2)
+ let val2 = parse_u16_from(&updated, "nested_section_label_alignment", 0);
+ assert_eq!(val2, 2);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_nested_section_label_offset() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_nested_section_label_offset_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse when missing (should return default 0)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_i16_from(&content, "nested_section_label_offset", 0);
+ assert_eq!(val, 0);
+
+ // 3. Write alignment config
+ assert!(write_config_value_path(path_str, "nested_section_label_offset", "-15"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("nested_section_label_offset = -15"));
+
+ // 4. Parse when present (should return written value -15)
+ let val2 = parse_i16_from(&updated, "nested_section_label_offset", 0);
+ assert_eq!(val2, -15);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_dropdown_height() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_dropdown_height_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse dropdown_height when missing (should return default 44)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "dropdown_height", 44);
+ assert_eq!(val, 44);
+
+ // 3. Write dropdown_height config
+ assert!(write_config_value_path(path_str, "dropdown_height", "48"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("dropdown_height = 48"));
+
+ // 4. Parse dropdown_height when present (should return written value 48)
+ let val2 = parse_u16_from(&updated, "dropdown_height", 44);
+ assert_eq!(val2, 48);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+
+ #[test]
+ fn test_read_write_label_margin() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_label_margin_config.toml");
+ let path_str = path.to_str().unwrap();
+
+ // 1. Initial configuration
+ let initial_content = "[layout]\ngap = 18\nborder_color = \"#374673\"\n";
+ fs::write(path_str, initial_content).unwrap();
+
+ // 2. Parse when missing (should return default 6)
+ let content = fs::read_to_string(path_str).unwrap();
+ let val = parse_u16_from(&content, "label_margin", 6);
+ assert_eq!(val, 6);
+
+ // 3. Write label_margin config
+ assert!(write_config_value_path(path_str, "label_margin", "12"));
+ let updated = fs::read_to_string(path_str).unwrap();
+ assert!(updated.contains("label_margin = 12"));
+
+ // 4. Parse when present (should return written value 12)
+ let val2 = parse_u16_from(&updated, "label_margin", 6);
+ assert_eq!(val2, 12);
+
+ // Clean up
+ let _ = fs::remove_file(path_str);
+ }
+}
+
+
+
diff --git a/src/pages/layout.rs b/src/pages/layout.rs
index 4018cb1..8fe9ef4 100644
--- a/src/pages/layout.rs
+++ b/src/pages/layout.rs
@@ -6,12 +6,12 @@ use clear_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
use clear_ui::widget::{Spinbox, Dropdown, LayoutPreview, PreviewLayoutMode};
-const CONFIG_PATH: &str = "/home/lsgalante/.config/ccec/config.toml";
+const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
fn get_socket_path() -> String {
match std::env::var("WAYLAND_DISPLAY") {
- Ok(display) => format!("/tmp/ccec-{}.sock", display),
- Err(_) => "/tmp/ccec.sock".to_string(),
+ Ok(display) => format!("/tmp/cce-client-{}.sock", display),
+ Err(_) => "/tmp/cce-client.sock".to_string(),
}
}
@@ -403,8 +403,8 @@ fn read_current_layout_status() -> LayoutStatusInfo {
let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".to_string());
- let tags_path = format!("/tmp/ccec-tags-{}", display);
- let tags_fallback = "/tmp/ccec-tags".to_string();
+ let tags_path = format!("/tmp/cce-client-tags-{}", display);
+ let tags_fallback = "/tmp/cce-client-tags".to_string();
let tags_content = fs::read_to_string(&tags_path)
.or_else(|_| fs::read_to_string(&tags_fallback))
.unwrap_or_default();
@@ -418,24 +418,24 @@ fn read_current_layout_status() -> LayoutStatusInfo {
}
}
- let title_path = format!("/tmp/ccec-title-{}", display);
- let title_fallback = "/tmp/ccec-title".to_string();
+ let title_path = format!("/tmp/cce-client-title-{}", display);
+ let title_fallback = "/tmp/cce-client-title".to_string();
let focused_title = fs::read_to_string(&title_path)
.or_else(|_| fs::read_to_string(&title_fallback))
.unwrap_or_default()
.trim()
.to_string();
- let layout_path = format!("/tmp/ccec-layout-{}", display);
- let layout_fallback = "/tmp/ccec-layout".to_string();
+ let layout_path = format!("/tmp/cce-client-layout-{}", display);
+ let layout_fallback = "/tmp/cce-client-layout".to_string();
let focused_layout_mode = fs::read_to_string(&layout_path)
.or_else(|_| fs::read_to_string(&layout_fallback))
.unwrap_or_else(|_| "Cascade".to_string())
.trim()
.to_string();
- let windows_path = format!("/tmp/ccec-windows-{}", display);
- let windows_fallback = "/tmp/ccec-windows".to_string();
+ let windows_path = format!("/tmp/cce-client-windows-{}", display);
+ let windows_fallback = "/tmp/cce-client-windows".to_string();
let windows_content = fs::read_to_string(&windows_path)
.or_else(|_| fs::read_to_string(&windows_fallback))
.unwrap_or_default();
@@ -513,7 +513,7 @@ fn read_current_layout_status() -> LayoutStatusInfo {
}
}
-pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(8);
@@ -551,7 +551,7 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
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);
+ 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;
@@ -561,7 +561,7 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
builder.add_section(&mut final_pc, "Fullscreen", sec_focused.get(0).copied().unwrap_or(false), |sec_fs| {
sec_fs.spacing(8.0);
state.spinboxes[0].set_label("Border Width");
- sec_fs.widget(&mut state.spinboxes[0], 14.0, 200.0, 44.0);
+ sec_fs.widget_full(&mut state.spinboxes[0], 44.0, ctx);
sec_fs.spacing(8.0);
});
@@ -569,16 +569,16 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
builder.add_section(&mut final_pc, "Cascade", sec_focused.get(1).copied().unwrap_or(false), |sec_cascade| {
sec_cascade.spacing(8.0);
state.spinboxes[1].set_label("Border Width");
- sec_cascade.widget(&mut state.spinboxes[1], 14.0, 200.0, 44.0);
+ sec_cascade.widget_full(&mut state.spinboxes[1], 44.0, ctx);
sec_cascade.spacing(8.0);
state.cascade_offset_spinbox.set_label("Offset");
- sec_cascade.widget(&mut state.cascade_offset_spinbox, 14.0, 200.0, 44.0);
+ sec_cascade.widget_full(&mut state.cascade_offset_spinbox, 44.0, ctx);
sec_cascade.spacing(8.0);
state.edge_gap_spinbox.set_label("Edge Gap");
- sec_cascade.widget(&mut state.edge_gap_spinbox, 14.0, 200.0, 44.0);
+ sec_cascade.widget_full(&mut state.edge_gap_spinbox, 44.0, ctx);
sec_cascade.spacing(8.0);
state.top_gap_spinbox.set_label("Top Gap");
- sec_cascade.widget(&mut state.top_gap_spinbox, 14.0, 200.0, 44.0);
+ sec_cascade.widget_full(&mut state.top_gap_spinbox, 44.0, ctx);
sec_cascade.spacing(8.0);
});
@@ -586,10 +586,10 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
builder.add_section(&mut final_pc, "Grid", sec_focused.get(2).copied().unwrap_or(false), |sec_grid| {
sec_grid.spacing(8.0);
state.spinboxes[2].set_label("Border Width");
- sec_grid.widget(&mut state.spinboxes[2], 14.0, 200.0, 44.0);
+ sec_grid.widget_full(&mut state.spinboxes[2], 44.0, ctx);
sec_grid.spacing(8.0);
state.grid_gap_spinbox.set_label("Gap");
- sec_grid.widget(&mut state.grid_gap_spinbox, 14.0, 200.0, 44.0);
+ sec_grid.widget_full(&mut state.grid_gap_spinbox, 44.0, ctx);
sec_grid.spacing(8.0);
});
@@ -597,7 +597,7 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
builder.add_section(&mut final_pc, "Floating", sec_focused.get(3).copied().unwrap_or(false), |sec_float| {
sec_float.spacing(8.0);
state.spinboxes[3].set_label("Border Width");
- sec_float.widget(&mut state.spinboxes[3], 14.0, 200.0, 44.0);
+ sec_float.widget_full(&mut state.spinboxes[3], 44.0, ctx);
sec_float.spacing(8.0);
});
@@ -605,7 +605,7 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
builder.add_section(&mut final_pc, "Movement", sec_focused.get(4).copied().unwrap_or(false), |movement_sec| {
movement_sec.spacing(8.0);
state.transition_duration_spinbox.set_label("Duration (ms)");
- movement_sec.widget(&mut state.transition_duration_spinbox, 14.0, 200.0, 44.0);
+ movement_sec.widget_full(&mut state.transition_duration_spinbox, 44.0, ctx);
movement_sec.spacing(8.0);
});
@@ -613,7 +613,7 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
builder.add_section(&mut final_pc, "Default Layouts", sec_focused.get(5).copied().unwrap_or(false), |default_layouts_sec| {
default_layouts_sec.spacing(8.0);
for i in 0..4 {
- default_layouts_sec.widget(&mut state.tag_layout_menus[i], 14.0, 200.0, 44.0);
+ default_layouts_sec.widget_full(&mut state.tag_layout_menus[i], 44.0, ctx);
default_layouts_sec.spacing(8.0);
}
});
@@ -621,13 +621,14 @@ pub fn view(state: &mut LayoutState, cx: f32, cy: f32, cw: f32, ch: f32, sec_foc
// 7. Side Panel Section
builder.add_section(&mut final_pc, "Side Panel", sec_focused.get(6).copied().unwrap_or(false), |side_panel_sec| {
side_panel_sec.spacing(8.0);
- side_panel_sec.widget(&mut state.side_panel_behavior_menu, 14.0, 200.0, 44.0);
+ side_panel_sec.widget_full(&mut state.side_panel_behavior_menu, 44.0, ctx);
side_panel_sec.spacing(8.0);
state.side_panel_width_spinbox.set_label("Default Width");
- side_panel_sec.widget(&mut state.side_panel_width_spinbox, 14.0, 200.0, 44.0);
+ side_panel_sec.widget_full(&mut state.side_panel_width_spinbox, 44.0, ctx);
side_panel_sec.spacing(8.0);
});
+
final_pc
}
@@ -792,7 +793,7 @@ mode = "popup"
fn test_view_layout_grid() {
let mut state = LayoutState::default();
let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
- let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false, false, false], &mut layout);
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false, false, false], &mut layout, &mut clear_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
}
}
diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index f9e9a9e..16a4ed2 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -10,6 +10,7 @@ pub mod hardware;
pub mod services;
pub mod interface;
pub mod accounts;
+pub mod packages;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Page {
@@ -24,17 +25,19 @@ pub enum Page {
Hardware,
Input,
Interface,
+ Packages,
}
impl Page {
- pub const ALL: [Page; 11] = [
+ pub const ALL: [Page; 12] = [
Page::Accounts,
Page::Audio,
- Page::Interface,
Page::Display,
+ Page::Hardware,
Page::Input,
+ Page::Interface,
Page::Layout,
- Page::Hardware,
+ Page::Packages,
Page::Radios,
Page::Services,
Page::Storage,
@@ -54,6 +57,7 @@ impl Page {
Page::Hardware => "Hardware",
Page::Input => "Input",
Page::Interface => "Interface",
+ Page::Packages => "Packages",
}
}
@@ -62,3 +66,4 @@ impl Page {
}
}
+
diff --git a/src/pages/network.rs b/src/pages/network.rs
index 1808140..adf55e1 100644
--- a/src/pages/network.rs
+++ b/src/pages/network.rs
@@ -244,7 +244,7 @@ const NET_BTN: [f32; 4] = [0.13, 0.20, 0.27, 1.0];
const ACT_BTN: [f32; 4] = [0.16, 0.29, 0.18, 1.0];
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
-pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(2);
@@ -300,7 +300,7 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
let list_box_w = sec_w - 24.0;
let list_box_h = 160.0;
- render_widget(sec.pc, &mut state.wifi_list_box, list_box_x, list_box_y, list_box_w, list_box_h);
+ render_widget(sec.pc, &mut state.wifi_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
state.wifi_list_box.update_bounds(state.available.len(), list_box_y, list_box_h);
@@ -471,7 +471,7 @@ mod tests {
fn test_view_layout_grid() {
let mut state = NetworkState::default();
let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
- let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &mut layout);
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &mut layout, &mut clear_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());
}
}
diff --git a/src/pages/packages.rs b/src/pages/packages.rs
new file mode 100644
index 0000000..f01c540
--- /dev/null
+++ b/src/pages/packages.rs
@@ -0,0 +1,754 @@
+use crate::app::{AppAction, PageContent, SectionContextExt};
+use clear_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, SectionContext};
+use clear_ui::widget::{Element, ScrollingList, TextBox, InteractiveListItem};
+
+#[derive(Debug, Clone)]
+pub struct PackageInfo {
+ pub name: String,
+ pub version: String,
+}
+
+#[derive(Debug, Clone)]
+pub struct UpdateInfo {
+ pub name: String,
+ pub old_version: String,
+ pub new_version: String,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PackageTab {
+ Installed,
+ Updates,
+}
+
+impl Default for PackageTab {
+ fn default() -> Self {
+ PackageTab::Installed
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct PackagesState {
+ pub loaded: bool,
+ pub installed: Vec<PackageInfo>,
+ pub updates: Vec<UpdateInfo>,
+ pub active_tab: PackageTab,
+ pub search_box: TextBox,
+ pub installed_list_box: ScrollingList,
+ pub installed_items: Vec<InteractiveListItem>,
+ pub updates_list_box: ScrollingList,
+ pub updates_items: Vec<InteractiveListItem>,
+ pub updating: bool,
+ pub last_update_res: Option<Result<(), String>>,
+ pub selected_package: Option<String>,
+ pub selected_package_info: Option<String>,
+ pub loading_info: bool,
+ pub uninstalling: bool,
+}
+
+impl Default for PackagesState {
+ fn default() -> Self {
+ Self {
+ loaded: false,
+ installed: Vec::new(),
+ updates: Vec::new(),
+ active_tab: PackageTab::Installed,
+ search_box: TextBox::new(String::new()).with_placeholder("Filter Packages..."),
+ installed_list_box: ScrollingList::new(32.0, 4.0),
+ installed_items: Vec::new(),
+ updates_list_box: ScrollingList::new(32.0, 4.0),
+ updates_items: Vec::new(),
+ updating: false,
+ last_update_res: None,
+ selected_package: None,
+ selected_package_info: None,
+ loading_info: false,
+ uninstalling: false,
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub enum PackagesMessage {
+ Refreshed(PackagesState),
+ SetTab(PackageTab),
+ StartUpdate,
+ UpdateFinished(Result<(), String>),
+ SelectPackage(Option<String>),
+ SelectAndScrollPackage(String),
+ InfoFetched(String, Result<String, String>),
+ StartUninstall(String),
+ UninstallFinished(Result<(), String>),
+}
+
+pub async fn fetch_packages_state() -> PackagesState {
+ let installed = fetch_installed_packages().await;
+ let updates = fetch_available_updates().await;
+ PackagesState {
+ loaded: true,
+ installed,
+ updates,
+ updating: false,
+ last_update_res: None,
+ ..Default::default()
+ }
+}
+
+async fn fetch_installed_packages() -> Vec<PackageInfo> {
+ let mut list = Vec::new();
+ if let Ok(output) = tokio::process::Command::new("pacman")
+ .arg("-Q")
+ .output()
+ .await
+ {
+ let stdout = String::from_utf8_lossy(&output.stdout);
+ for line in stdout.lines() {
+ let parts: Vec<&str> = line.split_whitespace().collect();
+ if parts.len() >= 2 {
+ list.push(PackageInfo {
+ name: parts[0].to_string(),
+ version: parts[1].to_string(),
+ });
+ }
+ }
+ }
+ list.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
+ list
+}
+
+async fn fetch_available_updates() -> Vec<UpdateInfo> {
+ let mut list = Vec::new();
+ if let Ok(output) = tokio::process::Command::new("checkupdates")
+ .output()
+ .await
+ {
+ let stdout = String::from_utf8_lossy(&output.stdout);
+ for line in stdout.lines() {
+ let parts: Vec<&str> = line.split_whitespace().collect();
+ if parts.len() >= 4 && parts[2] == "->" {
+ list.push(UpdateInfo {
+ name: parts[0].to_string(),
+ old_version: parts[1].to_string(),
+ new_version: parts[3].to_string(),
+ });
+ }
+ }
+ }
+ list.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
+ list
+}
+
+pub async fn run_update() -> Result<(), String> {
+ let output = tokio::process::Command::new("pkexec")
+ .args(["pacman", "-Syu", "--noconfirm"])
+ .output()
+ .await
+ .map_err(|e| format!("Failed to run update: {}", e))?;
+
+ if !output.status.success() {
+ let err = String::from_utf8_lossy(&output.stderr).to_string();
+ return Err(format!("Update process failed: {}", err));
+ }
+
+ Ok(())
+}
+
+pub async fn run_uninstall(name: String) -> Result<(), String> {
+ let output = tokio::process::Command::new("pkexec")
+ .args(["pacman", "-R", "--noconfirm", &name])
+ .output()
+ .await
+ .map_err(|e| format!("Failed to run uninstall: {}", e))?;
+
+ if !output.status.success() {
+ let err = String::from_utf8_lossy(&output.stderr).to_string();
+ return Err(format!("Uninstall process failed: {}", err));
+ }
+
+ Ok(())
+}
+
+pub async fn fetch_package_info(name: String, installed: bool) -> Result<String, String> {
+ let arg = if installed { "-Qi" } else { "-Si" };
+ let output = tokio::process::Command::new("pacman")
+ .args([arg, &name])
+ .output()
+ .await
+ .map_err(|e| format!("Failed to run pacman: {}", e))?;
+
+ if !output.status.success() {
+ let err = String::from_utf8_lossy(&output.stderr).to_string();
+ return Err(format!("Command failed: {}", err));
+ }
+
+ let mut raw_info = String::from_utf8_lossy(&output.stdout).to_string();
+ if installed {
+ if let Ok(ql_out) = tokio::process::Command::new("pacman")
+ .args(["-Ql", &name])
+ .output()
+ .await
+ {
+ let stdout = String::from_utf8_lossy(&ql_out.stdout);
+ let mut binaries = Vec::new();
+ for line in stdout.lines() {
+ let parts: Vec<&str> = line.split_whitespace().collect();
+ if parts.len() >= 2 {
+ let path = parts[1];
+ if !path.ends_with('/') && (
+ path.starts_with("/usr/bin/") ||
+ path.starts_with("/bin/") ||
+ path.starts_with("/usr/sbin/") ||
+ path.starts_with("/sbin/")
+ ) {
+ if let Some(filename) = path.split('/').last() {
+ binaries.push(filename.to_string());
+ }
+ }
+ }
+ }
+ if !binaries.is_empty() {
+ binaries.sort();
+ binaries.dedup();
+ raw_info.push_str(&format!("\nCommands : {}\n", binaries.join(" ")));
+ }
+ }
+ }
+ Ok(raw_info)
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct ParsedPackageInfo {
+ pub name: String,
+ pub version: String,
+ pub description: String,
+ pub website: String,
+ pub size: String,
+ pub licenses: String,
+ pub packager: String,
+ pub build_date: String,
+ pub required_by: String,
+ pub commands: String,
+}
+
+pub fn parse_package_info(raw: &str) -> ParsedPackageInfo {
+ let mut current_key = String::new();
+ let mut map = std::collections::HashMap::new();
+
+ for line in raw.lines() {
+ if line.is_empty() {
+ continue;
+ }
+ if !line.starts_with(' ') {
+ if let Some(pos) = line.find(':') {
+ let key = line[..pos].trim().to_string();
+ let val = line[pos + 1..].trim().to_string();
+ current_key = key.clone();
+ map.insert(key, val);
+ }
+ } else if !current_key.is_empty() {
+ if let Some(val) = map.get_mut(¤t_key) {
+ val.push(' ');
+ val.push_str(line.trim());
+ }
+ }
+ }
+
+ let get_val = |k: &str| map.get(k).cloned().unwrap_or_default();
+
+ let name = get_val("Name");
+ let version = get_val("Version");
+ let description = get_val("Description");
+ let website = get_val("URL");
+
+ let mut size = get_val("Installed Size");
+ if size.is_empty() {
+ size = get_val("Download Size");
+ }
+
+ let licenses = get_val("Licenses");
+ let packager = get_val("Packager");
+ let build_date = get_val("Build Date");
+ let required_by = get_val("Required By");
+ let commands = get_val("Commands");
+
+ ParsedPackageInfo {
+ name,
+ version,
+ description,
+ website,
+ size,
+ licenses,
+ packager,
+ build_date,
+ required_by,
+ commands,
+ }
+}
+
+pub fn wrap_text(text: &str, max_chars: usize) -> Vec<String> {
+ let mut lines = Vec::new();
+ for paragraph in text.split('\n') {
+ let mut current_line = String::new();
+ for word in paragraph.split_whitespace() {
+ if current_line.is_empty() {
+ current_line.push_str(word);
+ } else if current_line.len() + 1 + word.len() > max_chars {
+ lines.push(current_line);
+ current_line = word.to_string();
+ } else {
+ current_line.push(' ');
+ current_line.push_str(word);
+ }
+ }
+ if !current_line.is_empty() {
+ lines.push(current_line);
+ }
+ }
+ lines
+}
+
+const TEXT_FG: [f32; 4] = [0.83, 0.83, 0.83, 1.0];
+const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
+const ACCENT: [f32; 4] = [0.36, 0.56, 0.38, 1.0];
+const TOGGLE_ON: [f32; 4] = [0.16, 0.41, 0.18, 1.0];
+const TOGGLE_OFF: [f32; 4] = [0.16, 0.16, 0.24, 1.0];
+const BTN_HOVER: [f32; 4] = [0.25, 0.30, 0.26, 1.0];
+const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
+const RED: [f32; 4] = [0.85, 0.25, 0.25, 1.0];
+
+pub fn view(
+ state: &mut PackagesState,
+ cx: f32,
+ cy: f32,
+ cw: f32,
+ ch: f32,
+ sec_focused: &[bool],
+ layout: &mut dyn LayoutStrategy,
+ ctx: &mut clear_ui::context::UiContext,
+) -> PageContent {
+ let mut final_pc = PageContent::new();
+ let sec_w = 320.0f32;
+ let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(2);
+
+ // Section 1: Packages List
+ builder.add_section(&mut final_pc, "Packages", sec_focused.first().copied().unwrap_or(false), |sec| {
+ 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;
+ let tab_h = 28.0;
+ let tab_y = sec.ay();
+ let active_bg = [0.20, 0.40, 0.65, 0.4];
+ let inactive_bg = [0.10, 0.10, 0.16, 0.3];
+ let hover_bg = [0.20, 0.20, 0.25, 0.15];
+
+ let label1 = "Installed";
+ let label2 = "Updates";
+
+ let tab_x1 = sec.left + 12.0;
+ let tab_x2 = sec.left + 12.0 + tab_w + 8.0;
+
+ sec.pc.button(
+ label1,
+ tab_x1,
+ tab_y,
+ tab_w,
+ tab_h,
+ if state.active_tab == PackageTab::Installed { active_bg } else { inactive_bg },
+ hover_bg,
+ [0.90, 0.90, 0.95, 1.0],
+ AppAction::Packages(PackagesMessage::SetTab(PackageTab::Installed)),
+ );
+
+ sec.pc.button(
+ label2,
+ tab_x2,
+ tab_y,
+ tab_w,
+ tab_h,
+ if state.active_tab == PackageTab::Updates { active_bg } else { inactive_bg },
+ hover_bg,
+ [0.90, 0.90, 0.95, 1.0],
+ AppAction::Packages(PackagesMessage::SetTab(PackageTab::Updates)),
+ );
+ sec.content_y += tab_h + 12.0;
+
+ // Search box
+ let search_y = sec.ay();
+ let search_w = sec_w - 24.0;
+ let search_h = 46.0;
+
+ state.search_box.set_row_rect(sec.left + 12.0, search_w);
+ render_widget(sec.pc, &mut state.search_box, sec.left + 12.0, search_y, search_w, search_h, ctx);
+ sec.content_y += search_h + 16.0;
+
+ // List area
+ let list_box_x = sec.left + 12.0;
+ let list_box_y = sec.ay();
+ let list_box_w = sec_w - 24.0;
+ let list_box_h = 360.0;
+
+ let query = if state.search_box.editing {
+ state.search_box.edit_buffer.to_lowercase()
+ } else {
+ state.search_box.text.to_lowercase()
+ };
+
+ match state.active_tab {
+ PackageTab::Installed => {
+ render_widget(sec.pc, &mut state.installed_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
+
+ let filtered: Vec<&PackageInfo> = state.installed.iter()
+ .filter(|p| p.name.to_lowercase().contains(&query) || p.version.to_lowercase().contains(&query))
+ .collect();
+
+ state.installed_list_box.update_bounds(filtered.len(), list_box_y, list_box_h);
+ let item_h = state.installed_list_box.item_height;
+
+ if state.installed_items.len() != filtered.len() {
+ state.installed_items.clear();
+ for _ in 0..filtered.len() {
+ state.installed_items.push(InteractiveListItem::new(""));
+ }
+ }
+
+ for (idx, pkg) in filtered.iter().enumerate() {
+ if let Some(draw_y) = state.installed_list_box.get_item_draw_y(idx, 4.0) {
+ let item = &mut state.installed_items[idx];
+ item.title = pkg.name.clone();
+ item.subtitle = Some(format!("Version: {}", pkg.version));
+ item.selected = Some(&pkg.name) == state.selected_package.as_ref();
+ render_widget(sec.pc, item, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
+ }
+ }
+
+ if filtered.is_empty() {
+ sec.pc.text("No packages match the query", list_box_x + 16.0, list_box_y + 16.0, 12.0, TEXT_DIM);
+ }
+ }
+ PackageTab::Updates => {
+ render_widget(sec.pc, &mut state.updates_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
+
+ let filtered: Vec<&UpdateInfo> = state.updates.iter()
+ .filter(|p| p.name.to_lowercase().contains(&query))
+ .collect();
+
+ state.updates_list_box.update_bounds(filtered.len(), list_box_y, list_box_h);
+ let item_h = state.updates_list_box.item_height;
+
+ if state.updates_items.len() != filtered.len() {
+ state.updates_items.clear();
+ for _ in 0..filtered.len() {
+ state.updates_items.push(InteractiveListItem::new(""));
+ }
+ }
+
+ for (idx, pkg) in filtered.iter().enumerate() {
+ if let Some(draw_y) = state.updates_list_box.get_item_draw_y(idx, 4.0) {
+ let item = &mut state.updates_items[idx];
+ item.title = pkg.name.clone();
+ item.subtitle = Some(format!("{} -> {}", pkg.old_version, pkg.new_version));
+ item.selected = Some(&pkg.name) == state.selected_package.as_ref();
+ render_widget(sec.pc, item, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
+ }
+ }
+
+ if filtered.is_empty() {
+ sec.pc.text("No updates match the query", list_box_x + 16.0, list_box_y + 16.0, 12.0, TEXT_DIM);
+ }
+ }
+ }
+
+ 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);
+ if parsed.name.is_empty() {
+ parsed.name = pkg_name.clone();
+ }
+
+ 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);
+ let val_start_x = 90.0f32;
+ let usable_w = sub.cw - val_start_x - 12.0;
+ let char_w = 6.0f32;
+ let max_chars = (usable_w / char_w).max(15.0) as usize;
+
+ 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);
+ }
+ };
+
+ render_detail(subsec, "Version:", &parsed.version);
+ if !parsed.size.is_empty() {
+ render_detail(subsec, "Size:", &parsed.size);
+ }
+ if !parsed.licenses.is_empty() {
+ render_detail(subsec, "Licenses:", &parsed.licenses);
+ }
+ if !parsed.website.is_empty() {
+ render_detail(subsec, "Website:", &parsed.website);
+ }
+ if !parsed.packager.is_empty() {
+ render_detail(subsec, "Packager:", &parsed.packager);
+ }
+ if !parsed.build_date.is_empty() {
+ render_detail(subsec, "Build Date:", &parsed.build_date);
+ }
+ 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;
+ let gap = 6.0;
+ let btn_h = 24.0;
+
+ for chunk in reqs.chunks(cols_count) {
+ let btn_y = subsec.ay();
+ let cols = subsec.row_layout(cols_count, gap);
+ for (i, &pkg) in chunk.iter().enumerate() {
+ if let Some(&(x, w)) = cols.get(i) {
+ let action = AppAction::Packages(PackagesMessage::SelectAndScrollPackage(pkg.to_string()));
+ 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 {
+ ("Uninstalling...", TOGGLE_OFF, TOGGLE_OFF, AppAction::Packages(PackagesMessage::StartUninstall(pkg_name.clone())))
+ } else {
+ ("Uninstall Package", RED, BTN_HOVER, AppAction::Packages(PackagesMessage::StartUninstall(pkg_name.clone())))
+ };
+ let cols = subsec.row_layout(1, 0.0);
+ 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);
+ }
+ });
+ }
+ });
+
+ // Section 2: Update Actions / Status
+ 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..."
+ } else if state.updates.is_empty() {
+ "System is up to date"
+ } else {
+ "Updates available"
+ };
+ 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);
+ }
+ }
+ }
+
+ let btn_h = 32.0;
+ let btn_y = sec2.ay();
+
+ let (btn_lbl, bg, hover, action) = if state.updating {
+ ("Updating...", TOGGLE_OFF, TOGGLE_OFF, AppAction::Packages(PackagesMessage::StartUpdate))
+ } else {
+ ("Update System", TOGGLE_ON, BTN_HOVER, AppAction::Packages(PackagesMessage::StartUpdate))
+ };
+
+ let cols = sec2.row_layout(1, 0.0);
+ 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);
+ }
+ });
+
+ final_pc
+}
+
+pub fn update(state: &mut PackagesState, msg: PackagesMessage) {
+ match msg {
+ PackagesMessage::Refreshed(new) => {
+ let active = state.active_tab;
+ let query = state.search_box.text.clone();
+ let is_editing = state.search_box.editing;
+ let edit_buf = state.search_box.edit_buffer.clone();
+
+ let selected_package = state.selected_package.clone();
+ let selected_package_info = state.selected_package_info.clone();
+ let loading_info = state.loading_info;
+
+ let installed_scroll = state.installed_list_box.scroll_y();
+ let updates_scroll = state.updates_list_box.scroll_y();
+
+ *state = new;
+
+ state.active_tab = active;
+ state.search_box.text = query;
+ state.search_box.editing = is_editing;
+ state.search_box.edit_buffer = edit_buf;
+
+ state.selected_package = selected_package;
+ state.selected_package_info = selected_package_info;
+ state.loading_info = loading_info;
+
+ state.installed_list_box.set_scroll_y(installed_scroll);
+ state.updates_list_box.set_scroll_y(updates_scroll);
+ }
+ PackagesMessage::SetTab(tab) => {
+ state.active_tab = tab;
+ state.installed_list_box.set_scroll_y(0.0);
+ state.updates_list_box.set_scroll_y(0.0);
+ state.installed_items.clear();
+ state.updates_items.clear();
+ state.selected_package = None;
+ state.selected_package_info = None;
+ state.loading_info = false;
+ }
+ PackagesMessage::StartUpdate => {
+ state.updating = true;
+ state.last_update_res = None;
+ }
+ PackagesMessage::UpdateFinished(res) => {
+ state.updating = false;
+ state.last_update_res = Some(res);
+ }
+ PackagesMessage::SelectPackage(name) => {
+ if name != state.selected_package {
+ state.selected_package = name;
+ state.selected_package_info = None;
+ state.loading_info = state.selected_package.is_some();
+ }
+ }
+ PackagesMessage::InfoFetched(name, res) => {
+ if state.selected_package.as_ref() == Some(&name) {
+ state.loading_info = false;
+ match res {
+ Ok(info) => {
+ state.selected_package_info = Some(info);
+ }
+ Err(err) => {
+ state.selected_package_info = Some(format!("Error loading package info: {}", err));
+ }
+ }
+ }
+ }
+ PackagesMessage::StartUninstall(_name) => {
+ state.uninstalling = true;
+ }
+ PackagesMessage::UninstallFinished(res) => {
+ state.uninstalling = false;
+ match res {
+ Ok(_) => {
+ state.selected_package = None;
+ state.selected_package_info = None;
+ }
+ Err(err) => {
+ state.selected_package_info = Some(format!("Uninstall failed: {}", err));
+ }
+ }
+ }
+ PackagesMessage::SelectAndScrollPackage(name) => {
+ state.select_and_scroll_to(&name);
+ }
+ }
+}
+
+impl PackagesState {
+ pub fn select_and_scroll_to(&mut self, pkg_name: &str) {
+ self.active_tab = PackageTab::Installed;
+ self.search_box.text.clear();
+ self.search_box.edit_buffer.clear();
+ self.search_box.editing = false;
+ self.selected_package = Some(pkg_name.to_string());
+ self.selected_package_info = None;
+ self.loading_info = true;
+ if let Some(idx) = self.installed.iter().position(|p| p.name == pkg_name) {
+ let item_height_full = self.installed_list_box.item_height + self.installed_list_box.item_gap;
+ let target_y = idx as f32 * item_height_full - 164.0;
+ self.installed_list_box.set_scroll_y(target_y);
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_view_layout_grid() {
+ let mut state = PackagesState::default();
+ let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false], &mut layout, &mut clear_ui::context::UiContext::new());
+ assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());
+ }
+}
diff --git a/src/pages/services.rs b/src/pages/services.rs
index f6c33b3..6804308 100644
--- a/src/pages/services.rs
+++ b/src/pages/services.rs
@@ -75,7 +75,6 @@ pub struct ServicesState {
pub status_underline: bool,
pub status_running: bool,
pub status_label: Label,
- pub status_size_label: Label,
pub status_separators_toggle: Toggle,
pub status_underline_toggle: Toggle,
pub status_padding_spinbox: Spinbox,
@@ -112,7 +111,6 @@ impl Default for ServicesState {
status_underline: true,
status_running: false,
status_label: Label::new("Status Interface: Stopped").with_font_size(14.0).with_color([170, 51, 51]),
- status_size_label: Label::new("Font size: 11px").with_font_size(13.0).with_color([212, 212, 212]),
status_separators_toggle: Toggle::new().with_label("Show Separators"),
status_underline_toggle: Toggle::new().with_label("Show Underline"),
status_padding_spinbox: Spinbox::new(8, 0, 32, 1).with_label("Side Padding").with_unit("px"),
@@ -136,8 +134,6 @@ pub enum ServicesMessage {
// Status Interface variants
StatusRefreshed(StatusData),
- StatusFontSizeUp,
- StatusFontSizeDown,
StatusToggleSeparators,
StatusToggleUnderline,
StatusReload,
@@ -224,12 +220,13 @@ fn service_action(name: &str, action: &str, is_system: bool) {
const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(3);
builder.add_section(&mut final_pc, "Services", sec_focused.first().copied().unwrap_or(false), |sec| {
+ let sec_w = sec.cw;
if !state.loaded {
sec.text("Loading systemd services...", 12.0, 0.0, 12.0, TEXT_DIM);
sec.spacing(18.0);
@@ -286,6 +283,7 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
search_y,
search_w,
search_h,
+ ctx,
);
sec.content_y += search_h + 16.0;
@@ -295,7 +293,7 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
let list_box_w = sec_w - 24.0;
let list_box_h = 360.0;
- clear_ui::layout::render_widget(sec.pc, &mut state.list_box, list_box_x, list_box_y, list_box_w, list_box_h);
+ clear_ui::layout::render_widget(sec.pc, &mut state.list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
// Filter services
let query = if state.search_box.editing {
@@ -352,7 +350,7 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
let item_btn = &mut state.service_items[idx];
item_btn.title = service.name.clone();
item_btn.subtitle = Some(desc_truncated);
- clear_ui::layout::render_widget(sec.pc, item_btn, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h);
+ clear_ui::layout::render_widget(sec.pc, item_btn, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
// Render StatusDot
let status_dot_state = if service.active_state == "failed" {
@@ -363,7 +361,7 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
DotStatus::Inactive
};
let mut dot = StatusDot::new(status_dot_state);
- clear_ui::layout::render_widget(sec.pc, &mut dot, list_box_x + 10.0, draw_y + (item_h - 10.0) / 2.0, 10.0, 10.0);
+ clear_ui::layout::render_widget(sec.pc, &mut dot, list_box_x + 10.0, draw_y + (item_h - 10.0) / 2.0, 10.0, 10.0, ctx);
let active_txt = [0.90, 0.90, 0.95, 1.0];
let disabled_txt = [0.40, 0.40, 0.45, 1.0];
@@ -423,27 +421,25 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
// ── System Notifications ──
builder.add_section(&mut final_pc, "System Notifications", sec_focused.get(1).copied().unwrap_or(false), |sec2| {
- let toggle_w = 48.0;
- let toggle_h = 42.0;
+ let sec_w = sec2.cw;
state.notifications_enable_toggle.set_toggled(state.notifications_enable);
- sec2.widget(&mut state.notifications_enable_toggle, 14.0, toggle_w, toggle_h);
+ sec2.widget_full(&mut state.notifications_enable_toggle, clear_ui::layout::toggle_height(), ctx);
sec2.spacing(8.0);
state.notifications_bell_toggle.set_toggled(state.notifications_bell);
- sec2.widget(&mut state.notifications_bell_toggle, 14.0, toggle_w, toggle_h);
+ sec2.widget_full(&mut state.notifications_bell_toggle, clear_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, 200.0, 44.0);
+ sec2.widget(&mut state.notifications_duration_spinbox, 14.0, sec_w - 28.0, 44.0, ctx);
sec2.spacing(16.0);
// Opacity Slider (Transparency, moved here)
state.notifications_opacity_slider.set_value(state.notifications_opacity);
- sec2.widget(&mut state.notifications_opacity_slider, 14.0, 300.0, 38.0);
+ sec2.widget(&mut state.notifications_opacity_slider, 14.0, sec_w - 28.0, 38.0, ctx);
sec2.spacing(16.0);
- let btn_w = 160.0;
let btn_h = 32.0;
let btn_y = sec2.ay();
let white_color = [1.0, 1.0, 1.0, 1.0];
@@ -451,12 +447,12 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
let btn_hover = [0.28, 0.50, 0.78, 1.0];
let cols = sec2.row_layout(1, 0.0);
- if let Some(&(x, _)) = cols.first() {
+ if let Some(&(x, w)) = cols.first() {
sec2.button(
"Send Test Notification",
x,
btn_y,
- btn_w,
+ w,
btn_h,
btn_bg,
btn_hover,
@@ -469,6 +465,7 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
// ── Status Interface ──
builder.add_section(&mut final_pc, "Status Interface", sec_focused.get(2).copied().unwrap_or(false), |sec3| {
+ let sec_w = sec3.cw;
if !state.status_loaded {
sec3.text("Loading Status Interface status...", 12.0, 0.0, 12.0, TEXT_DIM);
sec3.spacing(18.0);
@@ -478,68 +475,30 @@ pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_f
let status_color = if state.status_running { [92, 143, 97] } else { [170, 51, 51] };
state.status_label.set_text(status_text);
state.status_label.set_color(status_color);
- sec3.widget(&mut state.status_label, 12.0, sec_w - 24.0, 20.0);
- sec3.spacing(12.0);
-
- // Font size
- state.status_size_label.set_text(&format!("Font size: {}px", state.status_font_size));
- sec3.widget(&mut state.status_size_label, 12.0, sec_w - 24.0, 20.0);
+ sec3.widget(&mut state.status_label, 12.0, sec_w - 24.0, 20.0, ctx);
sec3.spacing(12.0);
- let btn_h = 28.0;
- let yt = sec3.ay();
- let ax1 = sec3.ax(12.0);
- let ax2 = sec3.ax(56.0);
- let ax3 = sec3.ax(12.0 + 36.0 + 8.0);
- let text_color = [0.83, 0.83, 0.83, 1.0];
-
- sec3.button(
- "-1",
- ax1,
- yt,
- 36.0,
- btn_h,
- [0.13, 0.18, 0.14, 1.0],
- [0.25, 0.30, 0.26, 1.0],
- [1.0, 1.0, 1.0, 1.0],
- AppAction::Services(ServicesMessage::StatusFontSizeDown),
- );
-
- sec3.pc.text(&format!(" {}px ", state.status_font_size), ax2, yt + 7.0, 13.0, text_color);
-
- sec3.button(
- "+1",
- ax3,
- yt,
- 36.0,
- btn_h,
- [0.20, 0.40, 0.22, 1.0],
- [0.25, 0.30, 0.26, 1.0],
- [1.0, 1.0, 1.0, 1.0],
- AppAction::Services(ServicesMessage::StatusFontSizeUp),
- );
- sec3.spacing(16.0);
+ sec3.spacing(4.0);
// Separators toggle
state.status_separators_toggle.set_toggled(state.status_separators);
- sec3.widget(&mut state.status_separators_toggle, 12.0, 48.0, 42.0);
+ sec3.widget_full(&mut state.status_separators_toggle, clear_ui::layout::toggle_height(), ctx);
sec3.spacing(16.0);
// Underline toggle
state.status_underline_toggle.set_toggled(state.status_underline);
- sec3.widget(&mut state.status_underline_toggle, 12.0, 48.0, 42.0);
+ sec3.widget_full(&mut state.status_underline_toggle, clear_ui::layout::toggle_height(), ctx);
sec3.spacing(16.0);
// Padding spinbox
state.status_padding_spinbox.value = state.status_padding as i32;
- sec3.widget(&mut state.status_padding_spinbox, 12.0, 200.0, 44.0);
+ sec3.widget(&mut state.status_padding_spinbox, 12.0, sec_w - 24.0, 44.0, ctx);
sec3.spacing(16.0);
// Reload button
let yt_reload = sec3.ay();
- let btn_w = (sec_w - 24.0).min(200.0);
- let rx = sec3.left;
- let button_x = rx + sec_w / 2.0 - btn_w / 2.0;
+ let btn_w = sec_w - 24.0;
+ let button_x = sec3.left + 12.0;
sec3.button(
"Reload Status Interface",
button_x,
@@ -609,7 +568,7 @@ pub fn update(state: &mut ServicesState, msg: ServicesMessage) {
send_ipc_command("reload");
}
ServicesMessage::SendTestNotification => {
- send_ipc_command("notify \"ccec\" \"System notifications are working correctly!\"");
+ send_ipc_command("notify \"cce-client\" \"System notifications are working correctly!\"");
}
ServicesMessage::NotificationsRefreshed(new) => {
state.notifications_loaded = true;
@@ -620,7 +579,6 @@ pub fn update(state: &mut ServicesState, msg: ServicesMessage) {
}
ServicesMessage::StatusRefreshed(new) => {
let was_status_hovered = state.status_label.hovered();
- let was_size_hovered = state.status_size_label.hovered();
let was_separators_hovered = state.status_separators_toggle.hovered();
let was_underline_hovered = state.status_underline_toggle.hovered();
@@ -632,24 +590,10 @@ pub fn update(state: &mut ServicesState, msg: ServicesMessage) {
state.status_running = new.running;
state.status_label.set_hovered(was_status_hovered);
- state.status_size_label.set_hovered(was_size_hovered);
state.status_separators_toggle.set_hovered(was_separators_hovered);
state.status_underline_toggle.set_hovered(was_underline_hovered);
}
- ServicesMessage::StatusFontSizeUp => {
- if state.status_font_size < 28 {
- state.status_font_size += 1;
- write_status_font_size(state.status_font_size);
- status_interface_reload();
- }
- }
- ServicesMessage::StatusFontSizeDown => {
- if state.status_font_size > 8 {
- state.status_font_size -= 1;
- write_status_font_size(state.status_font_size);
- status_interface_reload();
- }
- }
+
ServicesMessage::StatusToggleSeparators => {
state.status_separators = !state.status_separators;
write_status_separators(state.status_separators);
@@ -673,12 +617,12 @@ pub fn update(state: &mut ServicesState, msg: ServicesMessage) {
// ── Notifications Configuration Reader & Writer ──
-const CONFIG_PATH: &str = "/home/lsgalante/.config/ccec/config.toml";
+const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
fn get_socket_path() -> String {
match std::env::var("WAYLAND_DISPLAY") {
- Ok(display) => format!("/tmp/ccec-{}.sock", display),
- Err(_) => "/tmp/ccec.sock".to_string(),
+ Ok(display) => format!("/tmp/cce-client-{}.sock", display),
+ Err(_) => "/tmp/cce-client.sock".to_string(),
}
}
@@ -934,12 +878,12 @@ fn get_config_path() -> String {
if let Some(path) = p.borrow().as_ref() {
return path.clone();
}
- "/home/lsgalante/.config/ccec/config.toml".to_string()
+ "/home/lsgalante/.config/cce/config.toml".to_string()
})
}
#[cfg(not(test))]
{
- "/home/lsgalante/.config/ccec/config.toml".to_string()
+ "/home/lsgalante/.config/cce/config.toml".to_string()
}
}
@@ -952,9 +896,6 @@ fn read_status_font_size() -> Option<u16> {
Some(parse_u16_from(&content, "status_font_size", 11))
}
-fn write_status_font_size(size: u16) {
- write_status_value("status_font_size", &size.to_string());
-}
fn read_status_padding() -> Option<u16> {
let content = std::fs::read_to_string(&get_config_path()).ok()?;
@@ -1003,15 +944,15 @@ fn write_status_underline(val: bool) {
fn status_interface_reload() {
let _ = std::process::Command::new("pkill")
- .args(["-f", "clear-status-interface"])
+ .args(["-f", "cce-status-interface"])
.status();
std::thread::sleep(std::time::Duration::from_millis(150));
- send_ipc_command("spawn clear-status-interface");
+ send_ipc_command("spawn cce-status-interface");
}
pub async fn fetch_status_state() -> StatusData {
let running = tokio::process::Command::new("pgrep")
- .args(["-f", "clear-status-interface"]).output().await.ok()
+ .args(["-f", "cce-status-interface"]).output().await.ok()
.map(|o| !o.stdout.is_empty())
.unwrap_or(false);
@@ -1038,7 +979,8 @@ mod tests {
let mut state = ServicesState::default();
let mut layout = clear_ui::layout::ColumnLayout::new(20.0);
let sec_focused = vec![false, false];
- let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &sec_focused, &mut layout);
+ let mut ctx = clear_ui::context::UiContext::new();
+ let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &sec_focused, &mut layout, &mut ctx);
assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
}
diff --git a/src/pages/storage.rs b/src/pages/storage.rs
index f31797c..6d142fb 100644
--- a/src/pages/storage.rs
+++ b/src/pages/storage.rs
@@ -43,7 +43,7 @@ pub enum StorageMessage {
}
fn status_path() -> String {
- format!("{}/.config/clear-system-interface/backup_status.txt", std::env::var("HOME").unwrap_or_default())
+ format!("{}/.config/cce-system-interface/backup_status.txt", std::env::var("HOME").unwrap_or_default())
}
pub fn read_backup_status() -> (String, String, Option<String>) {
@@ -111,7 +111,7 @@ pub async fn fetch_storage_state() -> StorageState {
pub async fn run_backup() -> Result<(String, String), String> {
// Run the backup system helper script via pkexec (graphical auth prompt)
let output = tokio::process::Command::new("pkexec")
- .arg("/home/lsgalante/.local/share/clear-system-interface/helpers/backup-system.sh")
+ .arg("/home/lsgalante/.local/share/cce-system-interface/helpers/backup-system.sh")
.output()
.await
.map_err(|e| format!("Failed to run backup script: {}", e))?;
@@ -166,13 +166,14 @@ const BTN_HOVER: [f32; 4] = [0.28, 0.50, 0.78, 1.0];
const BTN_DISABLED: [f32; 4] = [0.15, 0.18, 0.22, 1.0];
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
-pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy, ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(3);
// Section 1: Local Storage
builder.add_section(&mut final_pc, "Local Storage", false, |sec| {
+ 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);
@@ -195,12 +196,13 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
let disk_bar_x = sec.ax(12.0);
let mut disk_bar = clear_ui::widget::UsageBar::new((disk_pct as f32 / 100.0).min(1.0))
.with_colors([0.36, 0.60, 0.36, 1.0], [0.15, 0.15, 0.25, 1.0]);
- render_widget(sec.pc, &mut disk_bar, disk_bar_x, yt, bar_w, 8.0);
+ render_widget(sec.pc, &mut disk_bar, disk_bar_x, yt, bar_w, 8.0, ctx);
}
});
// Section 2: Memory
builder.add_section(&mut final_pc, "Memory", false, |sec| {
+ 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);
@@ -223,7 +225,7 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
let ram_bar_x = sec.ax(12.0);
let mut ram_bar = clear_ui::widget::UsageBar::new((ram_pct as f32 / 100.0).min(1.0))
.with_colors([0.50, 0.50, 0.65, 1.0], [0.15, 0.15, 0.25, 1.0]);
- render_widget(sec.pc, &mut ram_bar, ram_bar_x, yt, bar_w, 8.0);
+ render_widget(sec.pc, &mut ram_bar, ram_bar_x, yt, bar_w, 8.0, ctx);
}
});
@@ -268,7 +270,6 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
}
// Action Button
- let btn_w = 120.0;
let btn_h = 32.0;
let yt = sec.ay();
@@ -279,8 +280,8 @@ pub fn view(state: &StorageState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &m
};
let cols = sec.row_layout(1, 0.0);
- if let Some(&(x, _)) = cols.first() {
- sec.button(btn_label, x, yt, btn_w, btn_h, bg, hover, WHITE, action.clone());
+ 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 713173c..4cc30cf 100644
--- a/src/pages/system_info.rs
+++ b/src/pages/system_info.rs
@@ -48,7 +48,7 @@ fn spawn_systemctl(action: &str) {
let _ = tokio::process::Command::new("systemctl").arg(action).spawn();
}
-pub fn view(state: &SystemState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy) -> PageContent {
+pub fn view(state: &SystemState, cx: f32, cy: f32, cw: f32, ch: f32, layout: &mut dyn LayoutStrategy, _ctx: &mut clear_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(2);