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

commit8f59a01d05ca53bd53a339c0f9277aa25439ca81
parentbcbd078e03
authorLucas Galante <[email protected]>
date2026-06-27 21:28
Implement slider corner radius configuration

 src/layout.rs              | 38 ++++++++++++++++++++++++++++++++++++++
 src/widget/input/button.rs | 25 +++++++++++++++----------
 src/widget/input/slider.rs | 26 ++++++++++++++++++++++++++
 src/widget/json_layout.rs  | 24 ++++++++++++++++++++++--
 src/widget/mod.rs          |  2 +-
 5 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/src/layout.rs b/src/layout.rs
index a41baf0..7171c7b 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -102,6 +102,7 @@ static TEXTBOX_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
 static FONT_SELECTOR_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
 static DROPDOWN_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
 static TOGGLE_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
+static SLIDER_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
 static PLATE_CORNER_RADIUS: RwLock<f32> = RwLock::new(12.0);
 static PLATE_OPACITY: RwLock<f32> = RwLock::new(1.0);
 static PAGE_OPACITY: RwLock<f32> = RwLock::new(1.0);
@@ -481,6 +482,15 @@ pub fn reload_config() {
                     }
                 }
             }
+            if let Some(rest) = trimmed.strip_prefix("slider_corner_radius") {
+                let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+                let val_str = rest.trim_end_matches('"').trim();
+                if let Ok(val) = val_str.parse::<f32>() {
+                    if let Ok(mut lock) = SLIDER_CORNER_RADIUS.write() {
+                        *lock = val;
+                    }
+                }
+            }
         }
         if menubar_font_changed {
             if let Ok(mut lock) = MENUBAR_FONT_CACHED.write() {
@@ -817,6 +827,34 @@ pub fn set_toggle_corner_radius(radius: f32) {
     }
 }
 
+pub fn slider_corner_radius() -> f32 {
+    use std::sync::Once;
+    static INIT: Once = Once::new();
+    INIT.call_once(|| {
+        if let Some(content) = read_config() {
+            for line in content.lines() {
+                let trimmed = line.trim();
+                if let Some(rest) = trimmed.strip_prefix("slider_corner_radius") {
+                    let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+                    let val_str = rest.trim_end_matches('"').trim();
+                    if let Ok(val) = val_str.parse::<f32>() {
+                        if let Ok(mut lock) = SLIDER_CORNER_RADIUS.write() {
+                            *lock = val;
+                        }
+                    }
+                }
+            }
+        }
+    });
+    *SLIDER_CORNER_RADIUS.read().unwrap()
+}
+
+pub fn set_slider_corner_radius(radius: f32) {
+    if let Ok(mut lock) = SLIDER_CORNER_RADIUS.write() {
+        *lock = radius;
+    }
+}
+
 pub fn plate_corner_radius() -> f32 {
     use std::sync::Once;
     static INIT: Once = Once::new();
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index 2099632..16e32ed 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -20,7 +20,7 @@ pub struct Button {
     pub bg: Option<[f32; 4]>,
     pub hover_bg: Option<[f32; 4]>,
     pub label_color: Option<[f32; 4]>,
-    pub left_align: bool,
+    pub justify: Justification,
 }
 
 impl std::fmt::Debug for Button {
@@ -48,7 +48,7 @@ impl Button {
             bg: None,
             hover_bg: None,
             label_color: None,
-            left_align: false,
+            justify: Justification::Center,
         }
     }
 
@@ -63,7 +63,7 @@ impl Button {
             bg: None,
             hover_bg: None,
             label_color: None,
-            left_align: false,
+            justify: Justification::Center,
         }
     }
 
@@ -78,7 +78,7 @@ impl Button {
             bg: None,
             hover_bg: None,
             label_color: None,
-            left_align: false,
+            justify: Justification::Center,
         }
     }
 
@@ -93,7 +93,7 @@ impl Button {
             bg: None,
             hover_bg: None,
             label_color: None,
-            left_align: false,
+            justify: Justification::Center,
         }
     }
 
@@ -128,7 +128,12 @@ impl Button {
     }
 
     pub fn with_left_align(mut self, left_align: bool) -> Self {
-        self.left_align = left_align;
+        self.justify = if left_align { Justification::Left } else { Justification::Center };
+        self
+    }
+
+    pub fn with_justify(mut self, justify: Justification) -> Self {
+        self.justify = justify;
         self
     }
 }
@@ -235,10 +240,10 @@ impl Element for Button {
                     _ => [0xcc, 0xcc, 0xd4]
                 }
             };
-            let x = if self.left_align {
-                self.base.x + 8.0
-            } else {
-                self.base.x + (self.base.w - est_w) / 2.0
+            let x = match self.justify {
+                Justification::Left => self.base.x + 8.0,
+                Justification::Right => self.base.x + self.base.w - est_w - 8.0,
+                Justification::Center => self.base.x + (self.base.w - est_w) / 2.0,
             };
             labels.push(TextLabel {
                 text: label.clone(),
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index c5a5fcc..e7b06dc 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -153,6 +153,19 @@ impl Element for Slider {
         Some(crate::layout::slider_height())
     }
 
+    fn rounded_corners(&self) -> (bool, bool, bool, bool) {
+        let r = crate::layout::slider_corner_radius();
+        if r > 0.0 {
+            (true, true, true, true)
+        } else {
+            (false, false, false, false)
+        }
+    }
+
+    fn corner_radius(&self) -> f32 {
+        crate::layout::slider_corner_radius()
+    }
+
     fn draggable(&self) -> bool { true }
     fn is_dragging(&self) -> bool { self.dragging }
 
@@ -513,6 +526,19 @@ impl Element for RangeSlider {
         Some(crate::layout::slider_height())
     }
 
+    fn rounded_corners(&self) -> (bool, bool, bool, bool) {
+        let r = crate::layout::slider_corner_radius();
+        if r > 0.0 {
+            (true, true, true, true)
+        } else {
+            (false, false, false, false)
+        }
+    }
+
+    fn corner_radius(&self) -> f32 {
+        crate::layout::slider_corner_radius()
+    }
+
     fn draggable(&self) -> bool { true }
     fn is_dragging(&self) -> bool { self.active_thumb.is_some() }
 
diff --git a/src/widget/json_layout.rs b/src/widget/json_layout.rs
index d2b08e2..6c3ef5d 100644
--- a/src/widget/json_layout.rs
+++ b/src/widget/json_layout.rs
@@ -23,10 +23,19 @@ pub struct JsonWidgetConfig {
     pub target_page: Option<usize>,
 }
 
+#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[serde(rename_all = "lowercase")]
+pub enum Justification {
+    Left,
+    Center,
+    Right,
+}
+
 #[derive(Deserialize, Debug, Clone)]
 pub struct JsonPageConfig {
     pub title: String,
     pub widgets: Vec<JsonWidgetConfig>,
+    pub justify: Option<Justification>,
 }
 
 #[derive(Deserialize, Debug, Clone)]
@@ -35,6 +44,7 @@ pub struct JsonLayoutConfig {
     pub height: Option<u32>,
     pub widgets: Option<Vec<JsonWidgetConfig>>,
     pub pages: Option<Vec<JsonPageConfig>>,
+    pub justify: Option<Justification>,
 }
 
 pub struct JsonWidget {
@@ -68,6 +78,7 @@ impl JsonLayoutWidget {
         if let Some(ref pages_conf) = config.pages {
             for (page_idx, page) in pages_conf.iter().enumerate() {
                 page_titles.push(page.title.clone());
+                let page_justify = page.justify.unwrap_or(Justification::Center);
                 for (idx, w_conf) in page.widgets.iter().enumerate() {
                     let id = w_conf.id.clone().unwrap_or_else(|| format!("widget_{}_{}", page_idx, idx));
                     let widget_type = w_conf.widget_type.clone();
@@ -82,7 +93,11 @@ impl JsonLayoutWidget {
                             Box::new(cb)
                         }
                         "button" => {
-                            Box::new(Button::new(0.0, 0.0, 0.0, 0.0).with_label(&text))
+                            Box::new(Button::new(0.0, 0.0, 0.0, 0.0)
+                                .with_label(&text)
+                                .with_justify(page_justify)
+                                .with_bg([0.0, 0.0, 0.0, 0.0])
+                                .with_hover_bg([0.20, 0.35, 0.65, 0.9]))
                         }
                         "label" => {
                             Box::new(Label::new(&text).with_font_size(13.0).with_color([0xcc, 0xcc, 0xd4]))
@@ -135,6 +150,7 @@ impl JsonLayoutWidget {
                 }
             }
         } else if let Some(ref widgets_conf) = config.widgets {
+            let global_justify = config.justify.unwrap_or(Justification::Center);
             for (idx, w_conf) in widgets_conf.iter().enumerate() {
                 let id = w_conf.id.clone().unwrap_or_else(|| format!("widget_{}", idx));
                 let widget_type = w_conf.widget_type.clone();
@@ -149,7 +165,11 @@ impl JsonLayoutWidget {
                         Box::new(cb)
                     }
                     "button" => {
-                        Box::new(Button::new(0.0, 0.0, 0.0, 0.0).with_label(&text))
+                        Box::new(Button::new(0.0, 0.0, 0.0, 0.0)
+                            .with_label(&text)
+                            .with_justify(global_justify)
+                            .with_bg([0.0, 0.0, 0.0, 0.0])
+                            .with_hover_bg([0.20, 0.35, 0.65, 0.9]))
                     }
                     "label" => {
                         Box::new(Label::new(&text).with_font_size(13.0).with_color([0xcc, 0xcc, 0xd4]))
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index 1886f9f..cf6d21f 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -61,7 +61,7 @@ pub struct KeyEvent {
 }
 
 pub mod json_layout;
-pub use json_layout::{JsonLayoutWidget, JsonLayoutConfig, JsonWidgetConfig, JsonPageConfig, JsonWidget};
+pub use json_layout::{JsonLayoutWidget, JsonLayoutConfig, JsonWidgetConfig, JsonPageConfig, JsonWidget, Justification};
 
 use crate::colors;
 use std::sync::atomic::AtomicUsize;