git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commita34a05aa7a8d16e4da73d5d46fd8c98d4b59b85e
parentd11e8f36c6
authorLucas Galante <[email protected]>
date2026-05-22 10:19
Support custom slider ranges and dynamic menu items updating

 src/widget.rs | 47 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/src/widget.rs b/src/widget.rs
index e134f9c..fb54126 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -51,6 +51,7 @@ pub trait Widget {
 
     fn menu_click(&mut self) -> Option<(usize, usize)> { None }
     fn set_item_checked(&mut self, _menu_idx: usize, _item_idx: usize, _checked: bool) {}
+    fn set_menu_items(&mut self, _menu_idx: usize, _items: &[String]) {}
     fn set_grid_snap(&mut self, _gx: f32, _gy: f32) {}
     fn set_node_name(&mut self, _name: &str) {}
     fn set_visible(&mut self, _visible: bool) {}
@@ -211,6 +212,18 @@ impl ParametersBg {
     }
 }
 
+fn parse_slider_range(ptype: &str) -> (f32, f32) {
+    if ptype.starts_with("slider:") {
+        let parts: Vec<&str> = ptype.split(':').collect();
+        if parts.len() >= 3 {
+            if let (Ok(min), Ok(max)) = (parts[1].parse::<f32>(), parts[2].parse::<f32>()) {
+                return (min, max);
+            }
+        }
+    }
+    (0.0, 2.0)
+}
+
 impl Widget for ParametersBg {
     fn rect(&self) -> (f32, f32, f32, f32) { (self.x, self.y, self.w, self.h) }
     fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) { self.x = x; self.y = y; self.w = w; self.h = h; }
@@ -230,7 +243,7 @@ impl Widget for ParametersBg {
     }
 
     fn draggable(&self) -> bool {
-        self.display_params.iter().any(|p| p.2 == "slider")
+        self.display_params.iter().any(|p| p.2.starts_with("slider"))
     }
 
     fn is_dragging(&self) -> bool {
@@ -239,11 +252,17 @@ impl Widget for ParametersBg {
 
     fn drag_begin(&mut self, px: f32, py: f32) {
         for (i, p) in self.display_params.iter().enumerate() {
-            if p.2 == "slider" {
+            if p.2.starts_with("slider") {
                 let row_y = self.y + 30.0 + (i as f32) * 20.0;
                 if py >= row_y - 2.0 && py <= row_y + 18.0 {
                     let val = p.1.parse::<f32>().unwrap_or(0.0);
-                    let t = (val / 2.0).clamp(0.0, 1.0);
+                    let (min, max) = parse_slider_range(&p.2);
+                    let denom = max - min;
+                    let t = if denom != 0.0 {
+                        ((val - min) / denom).clamp(0.0, 1.0)
+                    } else {
+                        0.0
+                    };
                     let track_x = self.x + 100.0;
                     let track_w = (self.w - 100.0 - 20.0).max(10.0);
                     let thumb_size = 10.0;
@@ -271,7 +290,8 @@ impl Widget for ParametersBg {
             if range > 0.0 {
                 let raw = (px - self.drag_offset - track_x) / range;
                 let t = raw.clamp(0.0, 1.0);
-                let new_val = t * 2.0;
+                let (min, max) = parse_slider_range(&self.display_params[i].2);
+                let new_val = min + t * (max - min);
                 let old_val = &self.display_params[i].1;
                 let new_val_str = format!("{:.2}", new_val);
                 if *old_val != new_val_str {
@@ -290,9 +310,15 @@ impl Widget for ParametersBg {
     fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
         let mut quads = Vec::new();
         for (i, p) in self.display_params.iter().enumerate() {
-            if p.2 == "slider" {
+            if p.2.starts_with("slider") {
                 let val = p.1.parse::<f32>().unwrap_or(0.0);
-                let t = (val / 2.0).clamp(0.0, 1.0);
+                let (min, max) = parse_slider_range(&p.2);
+                let denom = max - min;
+                let t = if denom != 0.0 {
+                    ((val - min) / denom).clamp(0.0, 1.0)
+                } else {
+                    0.0
+                };
                 let track_x = self.x + 100.0;
                 let track_w = (self.w - 100.0 - 20.0).max(10.0);
                 let track_y = self.y + 30.0 + (i as f32) * 20.0 + 6.0;
@@ -317,7 +343,7 @@ impl Widget for ParametersBg {
 
     fn text_labels(&self) -> Vec<TextLabel> {
         self.display_params.iter().enumerate().map(|(i, (name, value, ptype))| {
-            let text = if ptype == "slider" {
+            let text = if ptype.starts_with("slider") {
                 let val = value.parse::<f32>().unwrap_or(0.0);
                 format!("{}: {:.2}", name, val)
             } else {
@@ -631,6 +657,13 @@ impl Widget for MenuBar {
         }
     }
 
+    fn set_menu_items(&mut self, menu_idx: usize, items: &[String]) {
+        if menu_idx < self.menu_dropdowns.len() {
+            self.menu_dropdowns[menu_idx] = items.to_vec();
+            self.menu_dropdown_checked[menu_idx] = vec![Some(false); items.len()];
+        }
+    }
+
     fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
         let mut quads = Vec::new();
         if let Some(idx) = self.hovered_menu {