GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Added style.surface.backplate.menubar and style.surface.backplate.statusbar styling domains
src/color.rs | 80 ++++++++++++++++++++++++++++++++++++++++
src/config.rs | 33 ++++++++++++++++-
src/layout.rs | 6 +++
src/widget/container/menu.rs | 51 +++++++++++++++++++++++--
src/widget/display/status_bar.rs | 37 ++++++++++++++++---
src/widget/input/text_box.rs | 1 +
6 files changed, 198 insertions(+), 10 deletions(-)
diff --git a/src/color.rs b/src/color.rs
index 42389b0..b7873ee 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -47,6 +47,14 @@ static POPOVER_BG_COLOR: RwLock<[f32; 4]> = RwLock::new([0.08, 0.08, 0.12, 1.0])
static PAGE_COLOR: RwLock<[f32; 4]> = RwLock::new([0.0, 0.0, 0.0, 0.0]);
static LAYER_COLOR: RwLock<[f32; 4]> = RwLock::new([0.0, 0.0, 0.0, 0.0]);
static BACKPLATE_CORNER_RADIUS: RwLock<f32> = RwLock::new(12.0);
+
+static BACKPLATE_MENUBAR_COLOR: RwLock<[f32; 4]> = RwLock::new([0.08, 0.08, 0.12, 1.0]);
+static BACKPLATE_MENUBAR_TEXT_COLOR: RwLock<[f32; 4]> = RwLock::new([0.90196, 0.90196, 0.94902, 1.0]);
+static BACKPLATE_MENUBAR_BLUR: RwLock<bool> = RwLock::new(false);
+
+static BACKPLATE_STATUSBAR_COLOR: RwLock<[f32; 4]> = RwLock::new([0.06, 0.06, 0.10, 1.0]);
+static BACKPLATE_STATUSBAR_TEXT_COLOR: RwLock<[f32; 4]> = RwLock::new([0.6666, 0.6666, 0.7333, 1.0]);
+static BACKPLATE_STATUSBAR_BLUR: RwLock<bool> = RwLock::new(false);
static BUTTON_BACKGROUND_COLOR: RwLock<[f32; 4]> = RwLock::new(BUTTON_IDLE);
static TREE_BACKGROUND_COLOR: RwLock<[f32; 4]> = RwLock::new([0.08, 0.08, 0.12, 0.3]);
@@ -219,6 +227,30 @@ fn parse_and_set_colors(content: &str) {
if let Ok(mut lock) = PAGE_LOW_COLOR.write() { *lock = c; }
if let Ok(mut lock) = BACKPLATE_OPACITY.write() { *lock = Some(c[3]); }
}
+
+ if let Some(c) = get_color("/style/surface/backplate/menubar/color") {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_COLOR.write() { *lock = c; }
+ }
+ if let Some(c) = get_color("/style/surface/backplate/menubar/text_color") {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_TEXT_COLOR.write() { *lock = c; }
+ }
+ if let Some(blur) = val.pointer("/style/surface/backplate/menubar/blur").and_then(|v| v.as_bool()) {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_BLUR.write() { *lock = blur; }
+ } else if let Some(blur_val) = val.pointer("/style/surface/backplate/menubar/blur").and_then(|v| v.as_f64()) {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_BLUR.write() { *lock = blur_val > 0.001; }
+ }
+
+ if let Some(c) = get_color("/style/surface/backplate/statusbar/color") {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_COLOR.write() { *lock = c; }
+ }
+ if let Some(c) = get_color("/style/surface/backplate/statusbar/text_color") {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_TEXT_COLOR.write() { *lock = c; }
+ }
+ if let Some(blur) = val.pointer("/style/surface/backplate/statusbar/blur").and_then(|v| v.as_bool()) {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_BLUR.write() { *lock = blur; }
+ } else if let Some(blur_val) = val.pointer("/style/surface/backplate/statusbar/blur").and_then(|v| v.as_f64()) {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_BLUR.write() { *lock = blur_val > 0.001; }
+ }
if let Some(c) = get_color("/layout/color_borders_color") {
if let Ok(mut lock) = COLOR_BORDERS_COLOR.write() { *lock = c; }
}
@@ -955,3 +987,51 @@ pub fn set_tree_open_search_key(k: String) {
}
}
+pub fn backplate_menubar_color() -> [f32; 4] {
+ load_colors_once();
+ *BACKPLATE_MENUBAR_COLOR.read().unwrap()
+}
+pub fn set_backplate_menubar_color(c: [f32; 4]) {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_COLOR.write() { *lock = c; }
+}
+
+pub fn backplate_menubar_text_color() -> [f32; 4] {
+ load_colors_once();
+ *BACKPLATE_MENUBAR_TEXT_COLOR.read().unwrap()
+}
+pub fn set_backplate_menubar_text_color(c: [f32; 4]) {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_TEXT_COLOR.write() { *lock = c; }
+}
+
+pub fn backplate_menubar_blur() -> bool {
+ load_colors_once();
+ *BACKPLATE_MENUBAR_BLUR.read().unwrap()
+}
+pub fn set_backplate_menubar_blur(b: bool) {
+ if let Ok(mut lock) = BACKPLATE_MENUBAR_BLUR.write() { *lock = b; }
+}
+
+pub fn backplate_statusbar_color() -> [f32; 4] {
+ load_colors_once();
+ *BACKPLATE_STATUSBAR_COLOR.read().unwrap()
+}
+pub fn set_backplate_statusbar_color(c: [f32; 4]) {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_COLOR.write() { *lock = c; }
+}
+
+pub fn backplate_statusbar_text_color() -> [f32; 4] {
+ load_colors_once();
+ *BACKPLATE_STATUSBAR_TEXT_COLOR.read().unwrap()
+}
+pub fn set_backplate_statusbar_text_color(c: [f32; 4]) {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_TEXT_COLOR.write() { *lock = c; }
+}
+
+pub fn backplate_statusbar_blur() -> bool {
+ load_colors_once();
+ *BACKPLATE_STATUSBAR_BLUR.read().unwrap()
+}
+pub fn set_backplate_statusbar_blur(b: bool) {
+ if let Ok(mut lock) = BACKPLATE_STATUSBAR_BLUR.write() { *lock = b; }
+}
+
diff --git a/src/config.rs b/src/config.rs
index 83487b1..58f8f23 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -252,7 +252,8 @@ pub fn parse_config_path(key: &str, default_section: &str) -> (String, String, O
const PROP_NODES: &[&str] = &[
"gestures", "key_bindings", "pointer_bind", "gesture_bind",
"button", "button_strip", "dropdown", "toggle", "spinbox", "slider", "font_selector",
- "status", "overlay", "backplate", "desktop", "list", "section", "textbox", "multiline", "editor", "tree"
+ "status", "overlay", "backplate", "desktop", "list", "section", "textbox", "multiline", "editor", "tree",
+ "menubar", "statusbar"
];
fn get_or_create_node_mut<'a>(doc: &'a mut kdl::KdlDocument, path: &[&str]) -> Option<&'a mut kdl::KdlNode> {
@@ -583,6 +584,36 @@ mod tests {
let doc_parsed = kdl_str.parse::<kdl::KdlDocument>();
assert!(doc_parsed.is_ok(), "Failed to parse KDL: {:?}", doc_parsed.err());
}
+
+ #[test]
+ fn test_backplate_menubar_statusbar_styling() {
+ // Trigger load_colors_once first to initialize the Once block from the real config file
+ let _ = crate::color::backplate_statusbar_blur();
+
+ let content = r##"
+ style {
+ surface {
+ backplate blur=(f64)0.1 color=(rgba)"#5e657acf" corner_radius=(i64)12 {
+ menubar blur=(bool)true color=(rgba)"#1a1d26d0" text_color=(rgba)"#e2e4f0ff"
+ statusbar blur=(bool)false color=(rgba)"#12141cd0" text_color=(rgba)"#b5b9c8ff"
+ }
+ }
+ }
+ "##;
+
+ // Parse into json and set colors
+ crate::color::reload_colors(content);
+
+ // Verify values are parsed correctly
+ assert_eq!(crate::color::backplate_menubar_blur(), true);
+ assert_eq!(crate::color::backplate_statusbar_blur(), false);
+
+ // Colors are in sRGB converted to linear, let's verify text colors
+ let menubar_txt = crate::color::backplate_menubar_text_color();
+ assert!(menubar_txt[0] > 0.0);
+ let statusbar_txt = crate::color::backplate_statusbar_text_color();
+ assert!(statusbar_txt[0] > 0.0);
+ }
}
fn format_kdl_type(ty: &str) -> String {
diff --git a/src/layout.rs b/src/layout.rs
index 932d835..4c1c355 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -126,6 +126,12 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
"style.surface.backplate.color" => "backplate_color",
"style.surface.backplate.blur" => "backplate_blur",
"style.surface.backplate.corner_radius" => "backplate_corner_radius",
+ "style.surface.backplate.menubar.color" => "backplate_menubar_color",
+ "style.surface.backplate.menubar.text_color" => "backplate_menubar_text_color",
+ "style.surface.backplate.menubar.blur" => "backplate_menubar_blur",
+ "style.surface.backplate.statusbar.color" => "backplate_statusbar_color",
+ "style.surface.backplate.statusbar.text_color" => "backplate_statusbar_text_color",
+ "style.surface.backplate.statusbar.blur" => "backplate_statusbar_blur",
"style.surface.page.opacity" => "page_opacity",
"style.surface.page.margin" => "page_margin",
"style.surface.graph.cell_color" => "graph_cell_color",
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index f133c42..4a0ef26 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -301,6 +301,24 @@ impl MenuBar {
};
Some((dx, dy, dw, dh))
}
+
+ pub fn text_color(&self) -> [f32; 4] {
+ if let Some(p_ptr) = self.parent {
+ if unsafe { (*p_ptr).is_backplate() } {
+ return crate::colors::backplate_menubar_text_color();
+ }
+ }
+ crate::colors::menubar_tab_label_color()
+ }
+
+ pub fn is_blur_enabled(&self) -> bool {
+ if let Some(p_ptr) = self.parent {
+ if unsafe { (*p_ptr).is_backplate() } {
+ return crate::colors::backplate_menubar_blur();
+ }
+ }
+ self.blur
+ }
}
impl Element for MenuBar {
@@ -463,9 +481,16 @@ impl Element for MenuBar {
}
fn color(&self) -> [f32; 4] {
+ if let Some(p_ptr) = self.parent {
+ if unsafe { (*p_ptr).is_backplate() } {
+ return crate::colors::backplate_menubar_color();
+ }
+ }
self.color.unwrap_or_else(|| colors::sidebar_bg_color())
}
+
+
fn rounded_corners(&self) -> (bool, bool, bool, bool) {
if let Some(p_ptr) = self.parent {
let is_bp = unsafe { (*p_ptr).is_backplate() };
@@ -714,7 +739,7 @@ impl Element for MenuBar {
pc.rect(colors::PANEL_MENU_HOVER, dx + 2.0, iy + 2.0, dw - 4.0, DROPDOWN_ITEM_H - 4.0);
}
- let label_color = crate::colors::menubar_tab_label_color();
+ let label_color = self.text_color();
let srgb = crate::colors::to_srgb(label_color);
let color_f32 = [srgb[0], srgb[1], srgb[2], 1.0];
let bounds = Some([dx, dy, dx + dw, dy + dh]);
@@ -741,7 +766,7 @@ impl Element for MenuBar {
pc.rect(colors::PANEL_MENU_HOVER, dx + 2.0, iy + 2.0, dw - 4.0, DROPDOWN_ITEM_H - 4.0);
}
- let label_color = crate::colors::menubar_tab_label_color();
+ let label_color = self.text_color();
let srgb = crate::colors::to_srgb(label_color);
let color_f32 = [srgb[0], srgb[1], srgb[2], 1.0];
let bounds = Some([dx, dy, dx + dw, dy + dh]);
@@ -917,7 +942,7 @@ impl Element for MenuBar {
if !self.visible {
return Vec::new();
}
- let label_color = crate::colors::menubar_tab_label_color();
+ let label_color = self.text_color();
let srgb = crate::colors::to_srgb(label_color);
let text_color = [
(srgb[0] * 255.0) as u8,
@@ -1178,6 +1203,24 @@ impl Menu {
};
(dx, dy, dw, dh)
}
+
+ pub fn text_color(&self) -> [f32; 4] {
+ if let Some(p_ptr) = self.parent {
+ let mut curr = p_ptr;
+ loop {
+ if unsafe { (*curr).is_backplate() } {
+ return crate::colors::backplate_menubar_text_color();
+ }
+ let dummy = crate::context::UiContext::new();
+ if let Some(next_p) = unsafe { (*curr).parent(&dummy) } {
+ curr = next_p;
+ } else {
+ break;
+ }
+ }
+ }
+ crate::colors::menubar_tab_label_color()
+ }
}
impl Element for Menu {
crate::impl_widget_base!(Menu);
@@ -1351,7 +1394,7 @@ impl Element for Menu {
}
fn text_labels(&self) -> Vec<TextLabel> {
- let label_color = crate::colors::menubar_tab_label_color();
+ let label_color = self.text_color();
let srgb = crate::colors::to_srgb(label_color);
let text_color = [
(srgb[0] * 255.0) as u8,
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index fcad77b..dd9a9bb 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -57,6 +57,24 @@ impl StatusBar {
pub fn set_bg_color(&mut self, color: [f32; 4]) {
self.bg_color = Some(color);
}
+
+ pub fn get_actual_text_color(&self) -> [f32; 4] {
+ if let Some(p_ptr) = self.parent {
+ if unsafe { (*p_ptr).is_backplate() } {
+ return crate::colors::backplate_statusbar_text_color();
+ }
+ }
+ self.text_color.unwrap_or([0.6666, 0.6666, 0.7333, 1.0])
+ }
+
+ pub fn is_blur_enabled(&self) -> bool {
+ if let Some(p_ptr) = self.parent {
+ if unsafe { (*p_ptr).is_backplate() } {
+ return crate::colors::backplate_statusbar_blur();
+ }
+ }
+ false
+ }
}
impl Element for StatusBar {
@@ -73,7 +91,14 @@ impl Element for StatusBar {
fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
self as *mut Self as *mut (dyn Element + 'static)
}
- fn color(&self) -> [f32; 4] { self.bg_color.unwrap_or(colors::STATUS_BG) }
+ fn color(&self) -> [f32; 4] {
+ if let Some(p_ptr) = self.parent {
+ if unsafe { (*p_ptr).is_backplate() } {
+ return crate::colors::backplate_statusbar_color();
+ }
+ }
+ self.bg_color.unwrap_or(colors::STATUS_BG)
+ }
fn set_hovered(&mut self, v: bool) { self.hovered = v; }
fn hovered(&self) -> bool { self.hovered }
@@ -138,11 +163,12 @@ impl Element for StatusBar {
fn get_text_items(&self) -> Vec<(&glyphon::Buffer, f32, f32, glyphon::Color)> {
if let Some(ref text_buf) = self.text_buf {
let offset_x = self.text_offset_x.unwrap_or(12.0);
- let color = self.text_color.map(|c| glyphon::Color::rgb(
+ let c = self.get_actual_text_color();
+ let color = glyphon::Color::rgb(
(c[0] * 255.0) as u8,
(c[1] * 255.0) as u8,
(c[2] * 255.0) as u8,
- )).unwrap_or_else(|| glyphon::Color::rgb(0xaa, 0xaa, 0xbb));
+ );
vec![(text_buf, self.x + offset_x, self.y + 4.0, color)]
} else {
Vec::new()
@@ -151,11 +177,12 @@ impl Element for StatusBar {
fn text_labels(&self) -> Vec<TextLabel> {
if !self.text.is_empty() {
let offset_x = self.text_offset_x.unwrap_or(12.0);
- let color = self.text_color.map(|c| [
+ let c = self.get_actual_text_color();
+ let color = [
(c[0] * 255.0) as u8,
(c[1] * 255.0) as u8,
(c[2] * 255.0) as u8,
- ]).unwrap_or([0xaa, 0xaa, 0xbb]);
+ ];
vec![TextLabel {
text: self.text.clone(),
x: self.x + offset_x,
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index 5c2cd62..f911e64 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -1699,6 +1699,7 @@ mod tests {
#[test]
fn test_multiline_textbox_border_width() {
let _dummy = crate::context::UiContext::new();
+ crate::layout::set_textbox_multiline_border_width(1.0);
let tb_single = TextBox::new("Singleline".to_string()).with_multiline(false);
let tb_multi = TextBox::new("Multiline".to_string()).with_multiline(true);