GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat: optional style.control.toggle.button_color — recolors only the slide button
When set, the slide toggle's gliding button fills with this fixed color
(button_opacity still applies) instead of crossfading the on/off state
colors. Track, border, and state colors are untouched; unset falls back
to the existing crossfade.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/color.rs | 19 +++++++++++++++++++
src/widget/input/checkbox.rs | 23 ++++++++++++++---------
2 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/src/color.rs b/src/color.rs
index 6cc0808..664716a 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -43,6 +43,7 @@ static BACKPLATE_OPACITY: RwLock<Option<f32>> = RwLock::new(None);
static TOGGLE_ON_COLOR: RwLock<[f32; 4]> = RwLock::new(TOGGLE_ON);
static TOGGLE_OFF_COLOR: RwLock<[f32; 4]> = RwLock::new(TOGGLE_OFF);
static TOGGLE_BG_COLOR: RwLock<[f32; 4]> = RwLock::new([0.18, 0.18, 0.22, 1.0]);
+static TOGGLE_BUTTON_COLOR: RwLock<Option<[f32; 4]>> = RwLock::new(None);
static LIST_BG_COLOR: RwLock<[f32; 4]> = RwLock::new([0.08, 0.08, 0.12, 0.3]);
static LIST_ENTRY_BG_COLOR: RwLock<[f32; 4]> = RwLock::new([1.0, 1.0, 1.0, 0.04]);
static LIST_ENTRY_HIGHLIGHT_COLOR: RwLock<[f32; 4]> = RwLock::new([1.0, 1.0, 1.0, 0.8]);
@@ -381,6 +382,9 @@ fn parse_and_set_colors(content: &str) {
if let Some(c) = get_color("/style/control/toggle/background_color").or_else(|| get_color("/layout/toggle_bg_color")) {
if let Ok(mut lock) = TOGGLE_BG_COLOR.write() { *lock = c; }
}
+ if let Some(c) = get_color("/style/control/toggle/button_color") {
+ if let Ok(mut lock) = TOGGLE_BUTTON_COLOR.write() { *lock = Some(c); }
+ }
if let Some(c) = get_color("/style/control/ramp/background") {
if let Ok(mut lock) = RAMP_BACKGROUND_COLOR.write() { *lock = c; }
}
@@ -1185,6 +1189,21 @@ pub fn set_toggle_bg_color(color: [f32; 4]) {
}
}
+/// Optional dedicated fill for the slide toggle's gliding button
+/// (`style.control.toggle.button_color`). `None` → the button falls back to
+/// crossfading the on/off state colors. Only the button reads this — the
+/// track, border, and state colors are untouched.
+pub fn toggle_button_color() -> Option<[f32; 4]> {
+ load_colors_once();
+ *TOGGLE_BUTTON_COLOR.read().unwrap()
+}
+
+pub fn set_toggle_button_color(color: Option<[f32; 4]>) {
+ if let Ok(mut lock) = TOGGLE_BUTTON_COLOR.write() {
+ *lock = color;
+ }
+}
+
pub fn list_bg_color() -> [f32; 4] {
load_colors_once();
*LIST_BG_COLOR.read().unwrap()
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index f905453..1810949 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -295,16 +295,21 @@ impl Toggle {
/// then knocked down to a mostly-transparent glass tint
/// (`style.control.toggle.button_opacity`): the beveled edges carry the
/// button's read, the fill is a whisper over the track.
+ /// `style.control.toggle.button_color` replaces the crossfaded base with
+ /// a fixed color (opacity still applies) — it recolors ONLY the button.
pub fn slide_button_color(&self) -> [f32; 4] {
- let off = colors::toggle_off_color();
- let on = colors::toggle_on_color();
- let t = self.slide_t;
- [
- off[0] + (on[0] - off[0]) * t,
- off[1] + (on[1] - off[1]) * t,
- off[2] + (on[2] - off[2]) * t,
- (off[3] + (on[3] - off[3]) * t) * crate::layout::toggle_button_opacity(),
- ]
+ let base = colors::toggle_button_color().unwrap_or_else(|| {
+ let off = colors::toggle_off_color();
+ let on = colors::toggle_on_color();
+ let t = self.slide_t;
+ [
+ off[0] + (on[0] - off[0]) * t,
+ off[1] + (on[1] - off[1]) * t,
+ off[2] + (on[2] - off[2]) * t,
+ off[3] + (on[3] - off[3]) * t,
+ ]
+ });
+ [base[0], base[1], base[2], base[3] * crate::layout::toggle_button_opacity()]
}
/// The rocker's two halves over `rect` as FLAT relief steps: (half rect,