GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Implement customizable scrollbar style configurations (width, track_color, thumb_color) under style.control.scrollbar
src/color.rs | 14 ++++++++++++++
src/layout.rs | 39 ++++++++++++++++++++++++++++++++++++++
src/widget/container/scroll_box.rs | 8 ++++----
3 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/src/color.rs b/src/color.rs
index d8a0c95..3dd2b7f 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -68,6 +68,9 @@ static TREE_TYPE_TEXT_COLOR: RwLock<[f32; 4]> = RwLock::new([0.78, 0.47, 0.87, 1
static TREE_VALUE_TEXT_COLOR: RwLock<[f32; 4]> = RwLock::new([0.51, 0.51, 0.54, 1.0]);
static TREE_SEPARATOR_COLOR: RwLock<[f32; 4]> = RwLock::new([0.15, 0.15, 0.19, 1.0]);
+static SCROLLBAR_TRACK_COLOR: RwLock<[f32; 4]> = RwLock::new([0.15, 0.15, 0.20, 0.3]);
+static SCROLLBAR_THUMB_COLOR: RwLock<[f32; 4]> = RwLock::new([0.60, 0.60, 0.65, 0.4]);
+
pub fn button_background_color() -> [f32; 4] {
*BUTTON_BACKGROUND_COLOR.read().unwrap()
}
@@ -310,6 +313,12 @@ fn parse_and_set_colors(content: &str) {
if let Some(c) = get_color("/style/data/tree/separator_color") {
if let Ok(mut lock) = TREE_SEPARATOR_COLOR.write() { *lock = c; }
}
+ if let Some(c) = get_color("/style/control/scrollbar/track_color") {
+ if let Ok(mut lock) = SCROLLBAR_TRACK_COLOR.write() { *lock = c; }
+ }
+ if let Some(c) = get_color("/style/control/scrollbar/thumb_color") {
+ if let Ok(mut lock) = SCROLLBAR_THUMB_COLOR.write() { *lock = c; }
+ }
}
fn load_colors_once() {
@@ -697,3 +706,8 @@ pub fn set_tree_type_text_color(c: [f32; 4]) { if let Ok(mut lock) = TREE_TYPE_T
pub fn set_tree_value_text_color(c: [f32; 4]) { if let Ok(mut lock) = TREE_VALUE_TEXT_COLOR.write() { *lock = c; } }
pub fn set_tree_separator_color(c: [f32; 4]) { if let Ok(mut lock) = TREE_SEPARATOR_COLOR.write() { *lock = c; } }
+pub fn scrollbar_track_color() -> [f32; 4] { *SCROLLBAR_TRACK_COLOR.read().unwrap() }
+pub fn set_scrollbar_track_color(c: [f32; 4]) { if let Ok(mut lock) = SCROLLBAR_TRACK_COLOR.write() { *lock = c; } }
+pub fn scrollbar_thumb_color() -> [f32; 4] { *SCROLLBAR_THUMB_COLOR.read().unwrap() }
+pub fn set_scrollbar_thumb_color(c: [f32; 4]) { if let Ok(mut lock) = SCROLLBAR_THUMB_COLOR.write() { *lock = c; } }
+
diff --git a/src/layout.rs b/src/layout.rs
index a215a25..40fdb40 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -101,6 +101,7 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
"style.label.font" => "label_font",
"style.control.slider.height" => "slider_height",
"style.control.slider.corner_radius" => "slider_corner_radius",
+ "style.control.scrollbar.width" => "scrollbar_width",
"style.control.spinbox.height" => "spinbox_height",
"style.control.spinbox.button_padding" => "spinbox_button_padding",
"style.control.spinbox.corner_radius" => "spinbox_corner_radius",
@@ -210,6 +211,7 @@ static BREADCRUMB_FONT: RwLock<String> = RwLock::new(String::new());
static PAGINATOR_TAB_PADDING_X: RwLock<f32> = RwLock::new(10.0);
static BUTTON_PADDING: RwLock<f32> = RwLock::new(14.0);
static BUTTON_STRIP_SPACING: RwLock<f32> = RwLock::new(8.0);
+static SCROLLBAR_WIDTH: RwLock<f32> = RwLock::new(4.0);
static PLATE_PADDING: RwLock<f32> = RwLock::new(20.0);
static DROPDOWN_HEIGHT: RwLock<f32> = RwLock::new(44.0);
@@ -373,6 +375,15 @@ pub fn reload_config() {
}
}
}
+ if let Some(rest) = trimmed.strip_prefix("scrollbar_width") {
+ 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) = SCROLLBAR_WIDTH.write() {
+ *lock = val;
+ }
+ }
+ }
if let Some(rest) = trimmed.strip_prefix("spinbox_height") {
let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
let val_str = rest.trim_end_matches('"').trim();
@@ -2266,6 +2277,34 @@ pub fn spinbox_button_padding() -> f32 {
*SPINBOX_BUTTON_PADDING.read().unwrap()
}
+pub fn scrollbar_width() -> 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("scrollbar_width") {
+ 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) = SCROLLBAR_WIDTH.write() {
+ *lock = val;
+ }
+ }
+ }
+ }
+ }
+ });
+ *SCROLLBAR_WIDTH.read().unwrap()
+}
+
+pub fn set_scrollbar_width(width: f32) {
+ if let Ok(mut lock) = SCROLLBAR_WIDTH.write() {
+ *lock = width;
+ }
+}
+
pub fn set_spinbox_button_padding(padding: f32) {
if let Ok(mut lock) = SPINBOX_BUTTON_PADDING.write() {
*lock = padding;
diff --git a/src/widget/container/scroll_box.rs b/src/widget/container/scroll_box.rs
index 8aa57b6..77d92f5 100644
--- a/src/widget/container/scroll_box.rs
+++ b/src/widget/container/scroll_box.rs
@@ -116,13 +116,13 @@ impl Element for ScrollBox {
// Scrollbar
if self.content_h > self.viewport_h {
- let sb_x = self.base.x + self.base.w - 8.0;
- let sb_w = 4.0;
+ let sb_w = crate::layout::scrollbar_width();
+ let sb_x = self.base.x + self.base.w - sb_w - 4.0;
let sb_track_h = self.viewport_h - 8.0;
let sb_track_y = self.viewport_y + 4.0;
// Track
- quads.push((sb_x, sb_track_y, sb_w, sb_track_h, [0.15, 0.15, 0.20, 0.3]));
+ quads.push((sb_x, sb_track_y, sb_w, sb_track_h, crate::color::scrollbar_track_color()));
// Thumb
let visible_ratio = self.viewport_h / self.content_h;
@@ -135,7 +135,7 @@ impl Element for ScrollBox {
let scroll_ratio = if max_scroll > 0.0 { self.scroll_y / max_scroll } else { 0.0 };
let thumb_y = sb_track_y + scroll_ratio * (sb_track_h - thumb_h);
- quads.push((sb_x, thumb_y, sb_w, thumb_h, [0.60, 0.60, 0.65, 0.4]));
+ quads.push((sb_x, thumb_y, sb_w, thumb_h, crate::color::scrollbar_thumb_color()));
}
quads