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

commit0e16fef02be8331ab090042d23402f318ecea96c
parent6fe182313d
authorLucas Galante <[email protected]>
date2026-07-31 13:32
feat: per-slider display precision — slider:min:max:decimals

The slider type string's optional 4th segment sets the row's decimal
places (default 2, the historical pane-wide constant). Slider grows
with_decimals() for its readout/edit buffer; every ParametersBg
format site (drag, wheel, glide fold, keyboard, unfocus, idempotence
guard) resolves precision per row.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/widget/container/parameters_bg.rs | 21 ++++++++++++++-------
 src/widget/input/slider.rs            | 11 ++++++++++-
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index 8972034..894e50d 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -790,7 +790,7 @@ impl ParametersBg {
                         s.unfocus();
                         let (min, max) = parse_slider_range(&p.2);
                         let new_val = min + s.value * (max - min);
-                        p.1 = format!("{:.2}", new_val);
+                        p.1 = format!("{:.*}", slider_decimals(&p.2), new_val);
                     }
                 } else if p.2.starts_with("float3") {
                     if let Some(f) = &mut self.float3s[idx] {
@@ -1476,7 +1476,7 @@ impl Input for ParametersBg {
                     let (min, max) = parse_slider_range(&self.display_params[i].2);
                     let new_val = min + s.value * (max - min);
                     let old_val = &self.display_params[i].1;
-                    let new_val_str = format!("{:.2}", new_val);
+                    let new_val_str = format!("{:.*}", slider_decimals(&self.display_params[i].2), new_val);
                     if *old_val != new_val_str {
                         self.display_params[i].1 = new_val_str;
                         return true;
@@ -1540,7 +1540,7 @@ impl Input for ParametersBg {
                 if s.tick(dt, &mut dummy) {
                     let (min, max) = parse_slider_range(&self.display_params[i].2);
                     let new_val = min + s.value * (max - min);
-                    let new_val_str = format!("{:.2}", new_val);
+                    let new_val_str = format!("{:.*}", slider_decimals(&self.display_params[i].2), new_val);
                     if self.display_params[i].1 != new_val_str {
                         self.display_params[i].1 = new_val_str;
                     }
@@ -2148,7 +2148,7 @@ impl Input for ParametersBg {
                                 if s.keyboard_input(event, ui) {
                                     let (min, max) = parse_slider_range(&p.2);
                                     let new_val = min + s.value * (max - min);
-                                    p.1 = format!("{:.2}", new_val);
+                                    p.1 = format!("{:.*}", slider_decimals(&p.2), new_val);
                                     if !s.editing {
                                         self.focused_param = None;
                                     }
@@ -2247,7 +2247,7 @@ impl Input for ParametersBg {
                                     let (min, max) = parse_slider_range(&p.2);
                                     let new_val = min + s.value * (max - min);
                                     let old_val = &p.1;
-                                    let new_val_str = format!("{:.2}", new_val);
+                                    let new_val_str = format!("{:.*}", slider_decimals(&p.2), new_val);
                                     if *old_val != new_val_str {
                                         p.1 = new_val_str;
                                         changed = true;
@@ -2361,6 +2361,13 @@ impl Input for ParametersBg {
     }
 }
 
+/// Display precision for a slider row from the type string's optional 4th
+/// segment (`slider:min:max:decimals`); 2 when absent — the pane-wide
+/// historical default.
+fn slider_decimals(ptype: &str) -> usize {
+    ptype.split(':').nth(3).and_then(|s| s.parse().ok()).unwrap_or(2)
+}
+
 fn parse_slider_range(ptype: &str) -> (f32, f32) {
     if ptype.starts_with("slider:") || ptype.starts_with("float3:") {
         let parts: Vec<&str> = ptype.split(':').collect();
@@ -2447,7 +2454,7 @@ impl ParamController for ParametersBg {
                     } else {
                         0.0
                     };
-                    Some(Slider::new().with_value(t).with_range(min, max).with_readout(true).with_label(&p.0))
+                    Some(Slider::new().with_value(t).with_range(min, max).with_readout(true).with_decimals(slider_decimals(&p.2)).with_label(&p.0))
                 } else {
                     None
                 }
@@ -2540,7 +2547,7 @@ impl ParamController for ParametersBg {
                         // wheel events/glide ticks (visible as jitter). Only
                         // re-seed when the incoming string says something the
                         // current value doesn't (a genuinely external change).
-                        let cur_str = format!("{:.2}", min + s.value * (max - min));
+                        let cur_str = format!("{:.*}", slider_decimals(&p_new.2), min + s.value * (max - min));
                         if cur_str != p_new.1 {
                             let val = p_new.1.parse::<f32>().unwrap_or(0.0);
                             let t = if max - min != 0.0 {
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index b8e905e..701c5ef 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -59,6 +59,8 @@ pub struct Slider {
     /// exponential decay instead of stopping dead.
     scroll_vel: f32,
     last_wheel: Option<std::time::Instant>,
+    /// Readout / edit-buffer display precision (decimal places).
+    decimals: usize,
 }
 
 impl Slider {
@@ -79,6 +81,7 @@ impl Slider {
             recessed: crate::layout::control_relief(),
             scroll_vel: 0.0,
             last_wheel: None,
+            decimals: 2,
         })
     }
 
@@ -328,7 +331,7 @@ impl Slider {
     }
 
     fn scaled_string(&self) -> String {
-        format!("{:.2}", self.min + self.value * (self.max - self.min))
+        format!("{:.*}", self.decimals, self.min + self.value * (self.max - self.min))
     }
 
     fn set_value_marking(&mut self, new_val: f32) -> bool {
@@ -389,6 +392,12 @@ impl Adapted<Slider> {
         self.show_readout = enabled;
         self
     }
+
+    /// Readout display precision in decimal places (default 2).
+    pub fn with_decimals(mut self, decimals: usize) -> Self {
+        self.decimals = decimals;
+        self
+    }
 }
 
 impl Layout for Slider {