system settings
git clone https://git.lucas.co/cce-system-interface.git
Add Background Opacity and Background Blur sliders to Status section
src/input_handler.rs | 65 ++++++++++++++++++++++++++++
src/main.rs | 16 +++----
src/pages/system_info.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++-
src/renderer.rs | 2 +
4 files changed, 180 insertions(+), 13 deletions(-)
diff --git a/src/input_handler.rs b/src/input_handler.rs
index 9c5e802..2a3b2ad 100644
--- a/src/input_handler.rs
+++ b/src/input_handler.rs
@@ -87,6 +87,23 @@ impl SystemInterface {
}
}
}
+ if self.app.current_page == Page::System {
+ if self.status_box_opacity_dragging {
+ drag_handled = true;
+ if self.app.system_info.status_box_opacity_slider.drag_update(lx, ly) {
+ changed = true;
+ let val = self.app.system_info.status_box_opacity_slider.value();
+ self.handle_action(&AppAction::SystemInfo(pages::system_info::SystemMessage::StatusSetBoxOpacity(val)));
+ }
+ } else if self.status_box_blur_dragging {
+ drag_handled = true;
+ if self.app.system_info.status_box_blur_slider.drag_update(lx, ly) {
+ changed = true;
+ let val = self.app.system_info.status_box_blur_slider.value();
+ self.handle_action(&AppAction::SystemInfo(pages::system_info::SystemMessage::StatusSetBoxBlur(val)));
+ }
+ }
+ }
if !drag_handled {
let event = cce_ui::widget::Event::PointerMove { x: lx, y: ly, local_x: lx, local_y: ly };
@@ -218,6 +235,18 @@ impl SystemInterface {
self.needs_rebuild = true;
}
}
+ if self.app.current_page == Page::System {
+ if self.status_box_opacity_dragging {
+ self.app.system_info.status_box_opacity_slider.drag_end();
+ self.status_box_opacity_dragging = false;
+ self.needs_rebuild = true;
+ }
+ if self.status_box_blur_dragging {
+ self.app.system_info.status_box_blur_slider.drag_end();
+ self.status_box_blur_dragging = false;
+ self.needs_rebuild = true;
+ }
+ }
}
let lx = self.cursor_x / s;
@@ -227,6 +256,36 @@ impl SystemInterface {
self.ui_context.propagate_event(&event, root);
}
+ if state == cce_ui::widget::ElementState::Pressed {
+ if self.app.current_page == Page::Display {
+ if self.app.display.brightness_slider.is_dragging() {
+ self.display_brightness_dragging = true;
+ }
+ }
+ if self.app.current_page == Page::Audio {
+ for (i, s) in self.app.audio.sink_sliders.iter().enumerate() {
+ if s.is_dragging() {
+ self.audio_sink_dragging = Some(i);
+ break;
+ }
+ }
+ for (i, s) in self.app.audio.source_sliders.iter().enumerate() {
+ if s.is_dragging() {
+ self.audio_source_dragging = Some(i);
+ break;
+ }
+ }
+ }
+ if self.app.current_page == Page::System {
+ if self.app.system_info.status_box_opacity_slider.is_dragging() {
+ self.status_box_opacity_dragging = true;
+ }
+ if self.app.system_info.status_box_blur_slider.is_dragging() {
+ self.status_box_blur_dragging = true;
+ }
+ }
+ }
+
self.propagate_widget_changes(&mut actions);
for a in &actions {
@@ -629,6 +688,12 @@ impl SystemInterface {
if self.app.system_info.status_padding_spinbox.take_change() {
actions.push(AppAction::SystemInfo(pages::system_info::SystemMessage::StatusSetPadding(self.app.system_info.status_padding_spinbox.value as u16)));
}
+ if self.app.system_info.status_box_opacity_slider.take_change() {
+ actions.push(AppAction::SystemInfo(pages::system_info::SystemMessage::StatusSetBoxOpacity(self.app.system_info.status_box_opacity_slider.value())));
+ }
+ if self.app.system_info.status_box_blur_slider.take_change() {
+ actions.push(AppAction::SystemInfo(pages::system_info::SystemMessage::StatusSetBoxBlur(self.app.system_info.status_box_blur_slider.value())));
+ }
}
Page::Accounts => {
if self.app.accounts.adding_new && self.app.accounts.email_box.take_change() {
diff --git a/src/main.rs b/src/main.rs
index 36c5c28..a9da7df 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -204,6 +204,8 @@ struct SystemInterface {
audio_sink_dragging: Option<usize>,
audio_source_dragging: Option<usize>,
display_brightness_dragging: bool,
+ status_box_opacity_dragging: bool,
+ status_box_blur_dragging: bool,
page_sec_containers: Vec<cce_ui::widget::SectionContainer>,
root_window: cce_ui::widget::Backplate,
menubar: cce_ui::widget::Paginator,
@@ -309,6 +311,8 @@ impl cce_ui::engine::Application for SystemInterface {
audio_sink_dragging: None,
audio_source_dragging: None,
display_brightness_dragging: false,
+ status_box_opacity_dragging: false,
+ status_box_blur_dragging: false,
page_sec_containers: Vec::new(),
root_window: cce_ui::widget::Backplate::new(0.0, 0.0, 820.0, 680.0)
.with_background([
@@ -516,20 +520,10 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
if hover_animation::tick(dt) {
needs_redraw = true;
}
- let menubar_changed = self.menubar.tick(dt, &mut self.ui_context);
- let switcher_changed = self.switcher.tick(dt, &mut self.ui_context);
- if menubar_changed || switcher_changed {
+ if self.ui_context.tick(dt) {
needs_redraw = true;
self.needs_rebuild = true;
}
- if let Some(root_ptr) = self.get_page_root_widget() {
- unsafe {
- if (*root_ptr).tick(dt, &mut self.ui_context) {
- needs_redraw = true;
- self.needs_rebuild = true;
- }
- }
- }
// Asynchronously check color selector changes (e.g. Zenity process exit)
let mut color_changed = false;
diff --git a/src/pages/system_info.rs b/src/pages/system_info.rs
index 8e1488a..f30a205 100644
--- a/src/pages/system_info.rs
+++ b/src/pages/system_info.rs
@@ -1,7 +1,7 @@
use crate::app::{AppAction, PageContent, SectionContextExt};
use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
-use cce_ui::widget::{Label, Dropdown, InfoBox, Toggle, Spinbox, Element};
-use crate::pages::interface::parse_u16_from;
+use cce_ui::widget::{Label, Dropdown, InfoBox, Toggle, Spinbox, Slider, Element};
+use crate::pages::interface::{parse_u16_from, parse_f32_from};
use crate::config_manager::CONFIG_PATH;
use std::io::Write;
use std::fs;
@@ -33,6 +33,8 @@ pub struct StatusData {
pub separators: bool,
pub underline: bool,
pub running: bool,
+ pub bg_opacity: f32,
+ pub bg_blur: f32,
}
#[derive(Debug, Clone)]
@@ -80,6 +82,10 @@ pub struct SystemState {
pub status_separators_toggle: Toggle,
pub status_underline_toggle: Toggle,
pub status_padding_spinbox: Spinbox,
+ pub status_box_opacity: f32,
+ pub status_box_blur: f32,
+ pub status_box_opacity_slider: Slider,
+ pub status_box_blur_slider: Slider,
}
impl Default for SystemState {
@@ -133,6 +139,10 @@ impl Default for SystemState {
status_separators_toggle: Toggle::new().with_label("Show Separators").with_config(&get_config_path(), "status_separators"),
status_underline_toggle: Toggle::new().with_label("Show Underline").with_config(&get_config_path(), "status_underline"),
status_padding_spinbox: Spinbox::new(8, 0, 32, 1).with_label("Side Padding").with_unit("px").with_config(&get_config_path(), "status_padding"),
+ status_box_opacity: 1.0,
+ status_box_blur: 0.0,
+ status_box_opacity_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(1.0).with_label("Background Opacity").with_config(&get_config_path(), "status_box_opacity"),
+ status_box_blur_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(0.0).with_label("Background Blur").with_config(&get_config_path(), "status_box_blur"),
}
}
}
@@ -160,6 +170,8 @@ pub enum SystemMessage {
StatusToggleUnderline,
StatusReload,
StatusSetPadding(u16),
+ StatusSetBoxOpacity(f32),
+ StatusSetBoxBlur(f32),
}
// ── zbus proxies ────────────────────────────────────────────────────
@@ -478,6 +490,10 @@ pub async fn fetch_system_state() -> SystemState {
status_separators_toggle: Toggle::new().with_label("Show Separators").with_config(&get_config_path(), "status_separators"),
status_underline_toggle: Toggle::new().with_label("Show Underline").with_config(&get_config_path(), "status_underline"),
status_padding_spinbox: Spinbox::new(8, 0, 32, 1).with_label("Side Padding").with_unit("px").with_config(&get_config_path(), "status_padding"),
+ status_box_opacity: 1.0,
+ status_box_blur: 0.0,
+ status_box_opacity_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(1.0).with_label("Background Opacity").with_config(&get_config_path(), "status_box_opacity"),
+ status_box_blur_slider: Slider::new().with_range(0.0, 100.0).with_scroll(true).with_value(0.0).with_label("Background Blur").with_config(&get_config_path(), "status_box_blur"),
}
}
@@ -760,6 +776,22 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
sec3.widget(&mut state.status_padding_spinbox, 12.0, sec_w - 24.0, 44.0, ctx);
sec3.spacing(16.0);
+ // Opacity slider
+ state.status_box_opacity_slider.set_label(&format!("Background Opacity: {}%", (state.status_box_opacity * 100.0).round() as i32));
+ state.status_box_opacity_slider.set_value(state.status_box_opacity);
+ let label_h_op = cce_ui::widget::label_offset(&state.status_box_opacity_slider);
+ let slider_h_op = cce_ui::layout::slider_height() + label_h_op;
+ sec3.widget_full(&mut state.status_box_opacity_slider, slider_h_op, ctx);
+ sec3.spacing(16.0);
+
+ // Blur slider
+ state.status_box_blur_slider.set_label(&format!("Background Blur: {}%", (state.status_box_blur * 100.0).round() as i32));
+ state.status_box_blur_slider.set_value(state.status_box_blur);
+ let label_h_bl = cce_ui::widget::label_offset(&state.status_box_blur_slider);
+ let slider_h_bl = cce_ui::layout::slider_height() + label_h_bl;
+ sec3.widget_full(&mut state.status_box_blur_slider, slider_h_bl, ctx);
+ sec3.spacing(16.0);
+
// Reload button
let yt_reload = sec3.ay();
let btn_w = sec_w - 24.0;
@@ -875,6 +907,8 @@ pub fn update(state: &mut SystemState, msg: SystemMessage) {
let was_status_hovered = state.status_label.hovered();
let was_separators_hovered = state.status_separators_toggle.hovered();
let was_underline_hovered = state.status_underline_toggle.hovered();
+ let was_opacity_hovered = state.status_box_opacity_slider.hovered();
+ let was_blur_hovered = state.status_box_blur_slider.hovered();
state.status_loaded = true;
state.status_font_size = new.font_size;
@@ -882,10 +916,14 @@ pub fn update(state: &mut SystemState, msg: SystemMessage) {
state.status_separators = new.separators;
state.status_underline = new.underline;
state.status_running = new.running;
+ state.status_box_opacity = new.bg_opacity;
+ state.status_box_blur = new.bg_blur;
state.status_label.set_hovered(was_status_hovered);
state.status_separators_toggle.set_hovered(was_separators_hovered);
state.status_underline_toggle.set_hovered(was_underline_hovered);
+ state.status_box_opacity_slider.set_hovered(was_opacity_hovered);
+ state.status_box_blur_slider.set_hovered(was_blur_hovered);
}
SystemMessage::StatusToggleSeparators => {
state.status_separators = !state.status_separators;
@@ -902,6 +940,16 @@ pub fn update(state: &mut SystemState, msg: SystemMessage) {
write_status_padding(val);
status_interface_reload();
}
+ SystemMessage::StatusSetBoxOpacity(val) => {
+ state.status_box_opacity = val;
+ write_status_box_opacity(val);
+ status_interface_reload();
+ }
+ SystemMessage::StatusSetBoxBlur(val) => {
+ state.status_box_blur = val;
+ write_status_box_blur(val);
+ status_interface_reload();
+ }
SystemMessage::StatusReload => {
status_interface_reload();
}
@@ -1019,6 +1067,24 @@ fn write_status_underline(val: bool) {
write_status_value("status_underline", &val.to_string());
}
+fn read_status_box_opacity() -> Option<f32> {
+ let content = std::fs::read_to_string(&get_config_path()).ok()?;
+ Some(parse_f32_from(&content, "status_box_opacity", 1.0))
+}
+
+fn write_status_box_opacity(val: f32) {
+ write_status_value("status_box_opacity", &val.to_string());
+}
+
+fn read_status_box_blur() -> Option<f32> {
+ let content = std::fs::read_to_string(&get_config_path()).ok()?;
+ Some(parse_f32_from(&content, "status_box_blur", 0.0))
+}
+
+fn write_status_box_blur(val: f32) {
+ write_status_value("status_box_blur", &val.to_string());
+}
+
fn status_interface_reload() {
std::thread::spawn(|| {
let _ = std::process::Command::new("pkill")
@@ -1039,6 +1105,8 @@ pub async fn fetch_status_state() -> StatusData {
let padding = read_status_padding().unwrap_or(8);
let separators = read_status_separators().unwrap_or(true);
let underline = read_status_underline().unwrap_or(true);
+ let bg_opacity = read_status_box_opacity().unwrap_or(1.0);
+ let bg_blur = read_status_box_blur().unwrap_or(0.0);
StatusData {
font_size,
@@ -1046,6 +1114,8 @@ pub async fn fetch_status_state() -> StatusData {
separators,
underline,
running,
+ bg_opacity,
+ bg_blur,
}
}
@@ -1160,4 +1230,40 @@ mod tests {
let _ = fs::remove_file(path);
}
+
+ #[test]
+ fn test_read_write_status_box_opacity() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_status_box_opacity.json");
+ let path_str = path.to_str().unwrap().to_string();
+
+ let _ = fs::write(&path_str, "{\"layout\": {\"status_box_opacity\": 1.0}}");
+ TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
+
+ let original = read_status_box_opacity().unwrap_or(1.0);
+ write_status_box_opacity(0.75);
+ assert_eq!(read_status_box_opacity(), Some(0.75));
+ write_status_box_opacity(original);
+ assert_eq!(read_status_box_opacity(), Some(original));
+
+ let _ = fs::remove_file(path);
+ }
+
+ #[test]
+ fn test_read_write_status_box_blur() {
+ let dir = std::env::temp_dir();
+ let path = dir.join("test_status_box_blur.json");
+ let path_str = path.to_str().unwrap().to_string();
+
+ let _ = fs::write(&path_str, "{\"layout\": {\"status_box_blur\": 0.0}}");
+ TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
+
+ let original = read_status_box_blur().unwrap_or(0.0);
+ write_status_box_blur(0.5);
+ assert_eq!(read_status_box_blur(), Some(0.5));
+ write_status_box_blur(original);
+ assert_eq!(read_status_box_blur(), Some(original));
+
+ let _ = fs::remove_file(path);
+ }
}
diff --git a/src/renderer.rs b/src/renderer.rs
index a4272ad..d2e21c3 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -297,6 +297,8 @@ impl SystemInterface {
link_parent_child(&mut self.page_sec_containers[8], &mut self.app.system_info.status_separators_toggle, &mut self.ui_context);
link_parent_child(&mut self.page_sec_containers[8], &mut self.app.system_info.status_underline_toggle, &mut self.ui_context);
link_parent_child(&mut self.page_sec_containers[8], &mut self.app.system_info.status_padding_spinbox, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[8], &mut self.app.system_info.status_box_opacity_slider, &mut self.ui_context);
+ link_parent_child(&mut self.page_sec_containers[8], &mut self.app.system_info.status_box_blur_slider, &mut self.ui_context);
}
Page::Processes => {
self.page_sec_containers.clear();