GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat: control_relief — DE-wide default for the demo's relief styling
window_manager.control_relief (config.kdl, default on) now drives the
construction-time default for the whole relief family: raised
Button/Toggle/Dropdown plates, recessed TextBox/Slider wells, recessed
MenuBar/StatusBar bands. The per-widget with_raised / with_recessed /
with_recess builders still override in either direction, and 0 reverts
the DE to the flat look. The demo drops its per-widget opt-ins (the
defaults are now the reference), and the two tests exercising the flat
legacy bridges pin with_raised(false) / with_recess(false).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XxjKyZK55xkRz43M8Fecsf
src/layout.rs | 11 +++++++++++
src/main.rs | 15 +++++++--------
src/widget/container/menu.rs | 2 +-
src/widget/display/status_bar.rs | 6 ++++--
src/widget/input/button.rs | 6 ++++--
src/widget/input/checkbox.rs | 2 +-
src/widget/input/dropdown.rs | 2 +-
src/widget/input/slider.rs | 2 +-
src/widget/input/text_box.rs | 2 +-
9 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/src/layout.rs b/src/layout.rs
index b1c506d..b608722 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -110,6 +110,7 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
"window_manager.bevel_depth" => "bevel_depth",
"window_manager.bevel_width" => "bevel_width",
"window_manager.bevel_shader" => "bevel_shader",
+ "window_manager.control_relief" => "control_relief",
"window_manager.corner_shape" => "corner_shape",
"style.control.ramp.height" => "ramp_height",
"style.layout.column.gap" => "column_gap",
@@ -1526,6 +1527,16 @@ pub fn bar_wall_width() -> f32 {
bevel_width() * 1.75
}
+/// DE-wide default for the controls' relief styling (`window_manager.control_relief`
+/// in config.kdl, default on): raised Button/Toggle/Dropdown plates, recessed
+/// TextBox/Slider wells, recessed MenuBar/StatusBar bands. Widgets read this at
+/// construction; the per-widget `with_raised` / `with_recessed` / `with_recess`
+/// builders override it either way. `0` reverts the whole DE to the flat look.
+pub fn control_relief() -> bool {
+ lazy_init_style_registry();
+ get_style_registry().read().unwrap().get_float("control_relief").map(|v| v != 0.0).unwrap_or(true)
+}
+
pub fn toggle_corner_radius() -> f32 {
lazy_init_style_registry();
get_style_registry().read().unwrap().get_float("toggle_corner_radius").unwrap_or(4.0)
diff --git a/src/main.rs b/src/main.rs
index 46f8fb6..efbdd65 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -141,23 +141,22 @@ impl Application for DemoApp {
) -> Self {
cce_ui::scale::set_scale_factor(1.0);
Self {
- button: Button::new(0.0, 0.0, 0.0, 0.0).with_label("Click me").with_raised(true),
- toggle: Toggle::new().with_raised(true),
+ // Relief styling (raised buttons/toggles/dropdowns, recessed
+ // wells) is the `control_relief` config default — no opt-in.
+ button: Button::new(0.0, 0.0, 0.0, 0.0).with_label("Click me"),
+ toggle: Toggle::new(),
// Slider `value` is NORMALIZED 0..1; `with_range` only scales the readout
// (`get_scaled_value`). Wheel nudging is an explicit opt-in.
slider: Slider::new()
.with_range(0.0, 100.0)
.with_value(0.4)
- .with_scroll(true)
- .with_recessed(true),
+ .with_scroll(true),
name_box: TextBox::new(String::new())
- .with_placeholder("Type a name...")
- .with_recessed(true),
+ .with_placeholder("Type a name..."),
theme_dropdown: Dropdown::new(
vec!["Forest".into(), "Ocean".into(), "Ember".into()],
0,
- )
- .with_raised(true),
+ ),
toggle_on: false,
clicks: 0,
status: "Ready.".to_string(),
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index 988707d..14e1412 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -72,7 +72,7 @@ impl MenuBar {
curved_circle: None,
blur: false,
color: None,
- recessed: false,
+ recessed: crate::layout::control_relief(),
title: String::new(),
menus: Adapted::new(ButtonStrip::new(x, y, w, h).with_inherit_menubar_font(true)),
menu_items: Vec::new(),
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index 7326375..7b7f43b 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -36,7 +36,7 @@ impl StatusBar {
text_offset_x: None,
text_color: None,
bg_color: None,
- recessed: false,
+ recessed: crate::layout::control_relief(),
})
}
@@ -206,7 +206,9 @@ mod tests {
#[test]
fn manual_host_text_pipeline() {
let mut fs = glyphon::FontSystem::new();
- let mut bar = StatusBar::new().with_text("hello").with_text_offset_x(15.0);
+ // Pin the flat style: the bg-quad bridge under test is skipped by the
+ // config-default recessed band.
+ let mut bar = StatusBar::new().with_text("hello").with_text_offset_x(15.0).with_recess(false);
WidgetHost::set_rect(&mut bar, 0.0, 570.0, 800.0, 30.0);
assert!(bar.text_buf.is_none(), "no buffer before prepare_text");
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index e2ec697..61bcc79 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -66,7 +66,7 @@ impl Button {
justify: Justification::Center,
label: None,
hovered: false,
- raised: false,
+ raised: crate::layout::control_relief(),
}
}
@@ -439,7 +439,9 @@ mod tests {
#[test]
fn geometry_and_label_parity() {
let ctx = UiContext::new();
- let b = Button::new(0.0, 0.0, 100.0, 24.0).with_label("Go");
+ // Pin the flat style: this test is about the legacy quad-bridge paths,
+ // which the config-default raised plate bypasses entirely.
+ let b = Button::new(0.0, 0.0, 100.0, 24.0).with_label("Go").with_raised(false);
let radius = crate::layout::button_corner_radius();
let rounded = WidgetHost::all_rounded_quads(&b, &ctx);
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index 61d43ff..2daed8d 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -240,7 +240,7 @@ impl Toggle {
hovered: false,
focused: false,
justify: Justification::Center,
- raised: false,
+ raised: crate::layout::control_relief(),
})
}
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index d4b087b..6007e8f 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -130,7 +130,7 @@ impl Dropdown {
label: None,
hovered: false,
corner_frame: None,
- raised: false,
+ raised: crate::layout::control_relief(),
})
}
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index 5e17aff..24e721a 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -70,7 +70,7 @@ impl Slider {
editor_state: TextEditorState::new(String::new()),
just_changed: false,
label: None,
- recessed: false,
+ recessed: crate::layout::control_relief(),
})
}
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index 65b67da..aa5d8fd 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -125,7 +125,7 @@ impl TextBox {
label: None,
hovered: false,
rect: Rect { x: 0.0, y: 0.0, width: 0.0, height: 0.0 },
- recessed: false,
+ recessed: crate::layout::control_relief(),
})
}