git.lucas.co / cce-system-interface
system settings
git clone https://git.lucas.co/cce-system-interface.git

commit404789957d175cc5dd6c66024d0ab633941f74fa
parentf1a956a168
authorLucas Galante <[email protected]>
date2026-06-16 21:55
Integrate MultiControl widget in Custom Parameters layout and route mouse/cursor events

 src/main.rs            | 24 +++++++++++++++++++++++-
 src/pages/interface.rs | 19 +++++++++++++++++--
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index feb753a..c0f8921 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -716,6 +716,8 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
         self.app.interface.button_corner_radius_spinbox.set_parent(None, &mut self.ui_context);
         self.app.interface.notification_opacity_spinbox.clear_children(&mut self.ui_context);
         self.app.interface.notification_opacity_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.custom_multicontrol.clear_children(&mut self.ui_context);
+        self.app.interface.custom_multicontrol.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);
@@ -895,7 +897,8 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                     link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
                 }
                 
-                // Section 0: Custom Parameters (empty top-level section)
+                // Section 0: Custom Parameters
+                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.interface.custom_multicontrol, &mut self.ui_context);
                 
                 // Section 1: Layout (parent of Plate, Sections, Grid Layout)
                 // (Layout widgets)
@@ -2020,6 +2023,9 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             if self.app.interface.terminal_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
                 changed = true;
             }
+            if self.app.interface.custom_multicontrol.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, &mut self.ui_context) {
@@ -2418,6 +2424,7 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                     if self.app.layout.blur_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                 }
                 Page::Interface => {
+                    if self.app.interface.custom_multicontrol.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     for cp in &mut self.app.interface.color_selectors {
                         if cp.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     }
@@ -2908,6 +2915,16 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(sb.value as u16)));
             }
         }
+
+        if self.app.current_page == Page::Interface {
+            let mc = &mut self.app.interface.custom_multicontrol;
+            if state == cce_ui::widget::ElementState::Pressed && !mc.hit_test(lx, ly, &self.ui_context) {
+                mc.unfocus();
+            }
+            if mc.mouse_input(button, state, lx, ly, &mut self.ui_context) {
+                self.needs_rebuild = true;
+            }
+        }
         if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Input {
             let sb = &mut self.app.input.rate_spinbox;
             if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
@@ -4302,6 +4319,11 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             }
         }
         if self.app.current_page == Page::Interface {
+            let mc = &mut self.app.interface.custom_multicontrol;
+            if mc.keyboard_input(event, &mut self.ui_context) {
+                self.needs_rebuild = true;
+                return true;
+            }
             let mut changed = false;
             let mut actions = Vec::new();
             for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index 98dfcbb..a2e7c0a 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -3,7 +3,7 @@ use std::io::Write;
 use crate::app::PageContent;
 use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
 use cce_ui::widget::{
-    ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle
+    ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle, MultiControl
 };
 
 const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.toml";
@@ -136,6 +136,7 @@ pub struct InterfaceState {
     pub graph_gap_opacity_spinbox: Spinbox,
     pub graph_gap_width: u16,
     pub graph_gap_width_spinbox: Spinbox,
+    pub custom_multicontrol: MultiControl,
 }
 
 impl Default for InterfaceState {
@@ -280,6 +281,7 @@ impl Default for InterfaceState {
             notification_bg_color: [0x08, 0x08, 0x0c],
             notification_opacity: 0.9,
             notification_opacity_spinbox: Spinbox::new(90, 0, 100, 5).with_label("Opacity").with_unit("%"),
+            custom_multicontrol: MultiControl::new("custom_parameters".to_string()).with_label("custom_parameters"),
         }
     }
 }
@@ -605,6 +607,7 @@ pub fn read_interface_config() -> InterfaceState {
         notification_bg_color,
         notification_opacity,
         notification_opacity_spinbox: Spinbox::new((notification_opacity * 100.0).round() as i32, 0, 100, 5).with_label("Opacity").with_unit("%"),
+        custom_multicontrol: MultiControl::new("custom_parameters".to_string()).with_label("custom_parameters"),
     }
 }
 
@@ -1414,7 +1417,12 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
     let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(7);
 
     // 1. Custom Parameters Section
-    builder.add_section(&mut final_pc, "Custom Parameters", false, |_sec| {});
+    builder.add_section(&mut final_pc, "Custom Parameters", false, |sec| {
+        sec.spacing(8.0);
+        let h = state.custom_multicontrol.preferred_height().unwrap_or(100.0);
+        sec.widget_full(&mut state.custom_multicontrol, h, ctx);
+        sec.spacing(8.0);
+    });
 
     // 2. Layout Section
     builder.add_section(&mut final_pc, "Layout", false, |sec| {
@@ -3519,6 +3527,13 @@ mod tests {
         // Clean up
         let _ = fs::remove_file(path_str);
     }
+
+    #[test]
+    fn test_custom_multicontrol_initialization() {
+        let state = InterfaceState::default();
+        assert_eq!(state.custom_multicontrol.name, "custom_parameters");
+        assert_eq!(state.custom_multicontrol.base.label, Some("custom_parameters".to_string()));
+    }
 }