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

commit18f64720e607acfac18f2301593aa9577ace3368
parent83ee793dad
authorLucas Galante <[email protected]>
date2026-07-05 15:21
feat: add spinbox background_color, button_color, button_hover_color, and text_color KDL styling properties

 src/color.rs                | 68 +++++++++++++++++++++++++++++++++++++++++++++
 src/widget/input/spinbox.rs | 21 ++++++++------
 2 files changed, 80 insertions(+), 9 deletions(-)

diff --git a/src/color.rs b/src/color.rs
index a5e5410..79ea01c 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -72,6 +72,10 @@ static PROGRESS_BG_COLOR: RwLock<[f32; 4]> = RwLock::new(PROGRESS_BG);
 static PROGRESS_FILL_COLOR: RwLock<[f32; 4]> = RwLock::new(PROGRESS_FILL);
 static RANGE_SLIDER_TRACK_COLOR: RwLock<[f32; 4]> = RwLock::new(SLIDER_TRACK);
 static RANGE_SLIDER_FILL_COLOR: RwLock<[f32; 4]> = RwLock::new(PROGRESS_FILL);
+static SPINBOX_DISPLAY_COLOR: RwLock<[f32; 4]> = RwLock::new(SPINBOX_DISPLAY);
+static SPINBOX_BUTTON_COLOR: RwLock<[f32; 4]> = RwLock::new(SPINBOX_BUTTON);
+static SPINBOX_BUTTON_HOVER_COLOR: RwLock<[f32; 4]> = RwLock::new(SPINBOX_BUTTON_HOVER);
+static SPINBOX_TEXT_COLOR: RwLock<[f32; 4]> = RwLock::new([0.8, 0.8, 0.83, 1.0]);
 
 static TREE_BACKGROUND_COLOR: RwLock<[f32; 4]> = RwLock::new([0.08, 0.08, 0.12, 0.3]);
 static TREE_BORDER_COLOR: RwLock<[f32; 4]> = RwLock::new([0.18, 0.18, 0.24, 1.0]);
@@ -346,6 +350,26 @@ fn parse_and_set_colors(content: &str) {
     if let Some(c) = get_color("/style/control/control_panel/border_color") {
         if let Ok(mut lock) = CONTROL_PANEL_BORDER_COLOR.write() { *lock = c; }
     }
+    if let Some(c) = get_color("/style/control/spinbox/background_color") {
+        if let Ok(mut lock) = SPINBOX_DISPLAY_COLOR.write() { *lock = c; }
+    }
+    if let Some(c) = get_color("/style/control/spinbox/button_color") {
+        if let Ok(mut lock) = SPINBOX_BUTTON_COLOR.write() { *lock = c; }
+        if let Ok(mut lock_hover) = SPINBOX_BUTTON_HOVER_COLOR.write() {
+            *lock_hover = [
+                (c[0] + 0.1).min(1.0),
+                (c[1] + 0.1).min(1.0),
+                (c[2] + 0.1).min(1.0),
+                c[3]
+            ];
+        }
+    }
+    if let Some(c) = get_color("/style/control/spinbox/button_hover_color") {
+        if let Ok(mut lock) = SPINBOX_BUTTON_HOVER_COLOR.write() { *lock = c; }
+    }
+    if let Some(c) = get_color("/style/control/spinbox/text_color") {
+        if let Ok(mut lock) = SPINBOX_TEXT_COLOR.write() { *lock = c; }
+    }
     if let Some(c) = get_color("/style/control/progressbar/background") {
         if let Ok(mut lock) = PROGRESS_BG_COLOR.write() { *lock = c; }
     }
@@ -1082,6 +1106,50 @@ pub fn set_rangeslider_fill(color: [f32; 4]) {
     }
 }
 
+pub fn spinbox_display() -> [f32; 4] {
+    load_colors_once();
+    *SPINBOX_DISPLAY_COLOR.read().unwrap()
+}
+
+pub fn set_spinbox_display(color: [f32; 4]) {
+    if let Ok(mut lock) = SPINBOX_DISPLAY_COLOR.write() {
+        *lock = color;
+    }
+}
+
+pub fn spinbox_button() -> [f32; 4] {
+    load_colors_once();
+    *SPINBOX_BUTTON_COLOR.read().unwrap()
+}
+
+pub fn set_spinbox_button(color: [f32; 4]) {
+    if let Ok(mut lock) = SPINBOX_BUTTON_COLOR.write() {
+        *lock = color;
+    }
+}
+
+pub fn spinbox_button_hover() -> [f32; 4] {
+    load_colors_once();
+    *SPINBOX_BUTTON_HOVER_COLOR.read().unwrap()
+}
+
+pub fn set_spinbox_button_hover(color: [f32; 4]) {
+    if let Ok(mut lock) = SPINBOX_BUTTON_HOVER_COLOR.write() {
+        *lock = color;
+    }
+}
+
+pub fn spinbox_text_color() -> [f32; 4] {
+    load_colors_once();
+    *SPINBOX_TEXT_COLOR.read().unwrap()
+}
+
+pub fn set_spinbox_text_color(color: [f32; 4]) {
+    if let Ok(mut lock) = SPINBOX_TEXT_COLOR.write() {
+        *lock = color;
+    }
+}
+
 pub fn set_backplate_corner_radius(radius: f32) {
     if let Ok(mut lock) = BACKPLATE_CORNER_RADIUS.write() {
         *lock = radius;
diff --git a/src/widget/input/spinbox.rs b/src/widget/input/spinbox.rs
index 1b0275a..1dcb672 100644
--- a/src/widget/input/spinbox.rs
+++ b/src/widget/input/spinbox.rs
@@ -354,13 +354,13 @@ impl Element for Spinbox {
 
         let p = crate::layout::spinbox_button_padding();
         let split_dec = self.base.x + display_w;
-        let inc_col = if self.hover_inc { colors::SPINBOX_BUTTON_HOVER } else { colors::SPINBOX_BUTTON };
-        let dec_col = if self.hover_dec { colors::SPINBOX_BUTTON_HOVER } else { colors::SPINBOX_BUTTON };
+        let inc_col = if self.hover_inc { colors::spinbox_button_hover() } else { colors::spinbox_button() };
+        let dec_col = if self.hover_dec { colors::spinbox_button_hover() } else { colors::spinbox_button() };
         
         let display_bg = if self.editing {
             [0.06, 0.10, 0.18, 1.0]
         } else {
-            colors::SPINBOX_DISPLAY
+            colors::spinbox_display()
         };
         
         quads.push((self.base.x, self.base.y + top, self.base.w, visual_h, display_bg));
@@ -408,7 +408,7 @@ impl Element for Spinbox {
         let display_bg = if self.editing {
             [0.06, 0.10, 0.18, 1.0]
         } else {
-            colors::SPINBOX_DISPLAY
+            colors::spinbox_display()
         };
 
         let display_w = self.base.w * 0.55;
@@ -431,8 +431,8 @@ impl Element for Spinbox {
         let pair_w = (self.base.w * 0.45 - 2.0 * p).max(0.0);
         let btn_w_padded = pair_w / 2.0;
         let split_dec = self.base.x + display_w;
-        let inc_col = if self.hover_inc { colors::SPINBOX_BUTTON_HOVER } else { colors::SPINBOX_BUTTON };
-        let dec_col = if self.hover_dec { colors::SPINBOX_BUTTON_HOVER } else { colors::SPINBOX_BUTTON };
+        let inc_col = if self.hover_inc { colors::spinbox_button_hover() } else { colors::spinbox_button() };
+        let dec_col = if self.hover_dec { colors::spinbox_button_hover() } else { colors::spinbox_button() };
 
         if btn_h > 0.0 && btn_w_padded > 0.0 {
             // Decrement button (middle, no rounded corners)
@@ -471,12 +471,15 @@ impl Element for Spinbox {
         let top = self.base.label_offset();
         let _visual_h = self.base.h - top;
         
+        let tc = colors::spinbox_text_color();
+        let text_color_u8 = [(tc[0]*255.0) as u8, (tc[1]*255.0) as u8, (tc[2]*255.0) as u8];
+
         labels.push(TextLabel {
             text: value_text,
             x: self.base.x + 4.0,
             y: crate::layout::align_text_y(self.base.y, self.base.h, 14.0, top),
             font_size: 14.0,
-            color: [0xcc, 0xcc, 0xd4],
+            color: text_color_u8,
         });
         if let Some(ref unit) = self.unit {
             labels.push(TextLabel {
@@ -502,14 +505,14 @@ impl Element for Spinbox {
                 x: dec_center_x - 4.0,
                 y: crate::layout::align_text_y(self.base.y, self.base.h, 12.0, top),
                 font_size: 12.0,
-                color: [0xcc, 0xcc, 0xd4],
+                color: text_color_u8,
             });
             labels.push(TextLabel {
                 text: "+".to_string(),
                 x: inc_center_x - 4.0,
                 y: crate::layout::align_text_y(self.base.y, self.base.h, 12.0, top),
                 font_size: 12.0,
-                color: [0xcc, 0xcc, 0xd4],
+                color: text_color_u8,
             });
         }
         labels