GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat(layout): radii configured per rung — style.control.corner_radius
The control rung gets its default: `style.control.corner_radius`
(`control_corner_radius`, default 8, the DE's standard). Every control-scale
radius getter — button, dropdown, font selector, slider, spinbox, textbox,
toggle, and the list and tree wells — falls back to it when the widget's own
`corner_radius` key is unset, so the per-widget keys are overrides rather
than nine separately-defaulted knobs (each used to default to 4, which is how
the ColorSelector's swatch drifted from the field beside it). The pane rung
already fell back to the root's.
Verified: the gallery renders identically in a shadow whose config carries
only the rung key against one carrying every per-widget key; a mapping test
pins `control corner_radius=8 { button corner_radius=10 }` flattening to the
rung key beside the override.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
CLAUDE.md | 14 +++++++++-----
src/layout.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 53 insertions(+), 14 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 3177fe4..71a16af 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -148,11 +148,15 @@ What this buys, and where the code is heading:
FontSelector, Breadcrumb and the ButtonStrip's selected plateau draw through
it; the migration was prim-identical against a dump of every face. A new
control face goes through `ControlPlate`, never a hand-rolled carve.
-- **Radii are configured per rung, overridden per widget.** Today every
- control has its own `corner_radius` key with a separate default, which is how
- the ColorSelector's swatch drifted to 4px while the field beside it used 8.
- The intended shape is a default radius per rung (root, pane, control) with
- the per-widget keys as overrides.
+- **Radii are configured per rung, overridden per widget.** Root:
+ `style.surface.plate.root.corner_radius` (`color::root_plate_corner_radius`).
+ Pane: `plate_corner_radius`, falling back to the root's. Control:
+ `style.control.corner_radius` (`layout::control_corner_radius`, default 8) —
+ every control-scale getter (button, dropdown, font selector, slider,
+ spinbox, textbox, toggle, list and tree wells; the ColorSelector's two via
+ the textbox) falls back to it when the widget's own `corner_radius` key is
+ unset, so a per-widget key is an override, not a requirement. Do not give a
+ new control-scale radius getter a literal default; fall back to the rung.
## The `scene/` core rebuild (read `docs/rfc-core-rebuild.md` before touching it)
diff --git a/src/layout.rs b/src/layout.rs
index 2d86a7e..cd635df 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -67,6 +67,9 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
"style.list.font_color" | "style.data.list.font_color" => "list_font_color",
"style.control.breadcrumb.font" => "breadcrumb_font",
+ // The control rung's default radius: every control-scale
+ // `corner_radius` below falls back to it when its own key is unset.
+ "style.control.corner_radius" => "control_corner_radius",
"style.control.button.padding" => "button_padding",
"style.control.button.height" => "button_height",
"style.control.button.corner_radius" => "button_corner_radius",
@@ -1854,7 +1857,7 @@ pub fn control_relief() -> bool {
pub fn toggle_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("toggle_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("toggle_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_toggle_corner_radius(radius: f32) {
@@ -1894,7 +1897,7 @@ pub fn set_toggle_border_width(width: f32) {
pub fn slider_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("slider_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("slider_corner_radius").unwrap_or_else(control_corner_radius)
}
/// The toggle's render style: `style.control.toggle.style = "slide"` swaps the
@@ -2776,9 +2779,28 @@ pub fn set_color_selector_corner_radius(radius: f32) {
}
}
+/// The control rung's corner radius (`style.control.corner_radius`): the
+/// default every control-scale radius getter falls back to when the widget's
+/// own `corner_radius` key is unset — buttons, dropdowns, font selectors,
+/// sliders, spinboxes, text boxes, toggles, and the list and tree wells. The
+/// per-widget keys are overrides on top of it. See "Plates, wells and seams"
+/// in `CLAUDE.md`; the pane and root rungs are `plate_corner_radius` and
+/// `crate::color::root_plate_corner_radius`.
+pub fn control_corner_radius() -> f32 {
+ lazy_init_style_registry();
+ get_style_registry().read().unwrap().get_float("control_corner_radius").unwrap_or(8.0)
+}
+
+pub fn set_control_corner_radius(radius: f32) {
+ lazy_init_style_registry();
+ if let Ok(mut registry) = get_style_registry().write() {
+ registry.set_float("control_corner_radius", radius);
+ }
+}
+
pub fn button_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("button_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("button_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_button_corner_radius(radius: f32) {
@@ -2790,7 +2812,7 @@ pub fn set_button_corner_radius(radius: f32) {
pub fn spinbox_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("spinbox_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("spinbox_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_spinbox_corner_radius(radius: f32) {
@@ -2940,7 +2962,7 @@ pub fn set_spinbox_button_padding(padding: f32) {
pub fn textbox_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("textbox_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("textbox_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_textbox_corner_radius(radius: f32) {
@@ -2989,7 +3011,7 @@ pub fn set_textbox_multiline_border_width(width: f32) {
pub fn list_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("list_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("list_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_list_corner_radius(radius: f32) {
@@ -3001,7 +3023,7 @@ pub fn set_list_corner_radius(radius: f32) {
pub fn tree_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("tree_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("tree_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_tree_corner_radius(radius: f32) {
@@ -3160,7 +3182,7 @@ pub fn set_graph_connector_activation_radius(radius: f32) {
pub fn font_selector_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("font_selector_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("font_selector_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_font_selector_corner_radius(radius: f32) {
@@ -3172,7 +3194,7 @@ pub fn set_font_selector_corner_radius(radius: f32) {
pub fn dropdown_corner_radius() -> f32 {
lazy_init_style_registry();
- get_style_registry().read().unwrap().get_float("dropdown_corner_radius").unwrap_or(4.0)
+ get_style_registry().read().unwrap().get_float("dropdown_corner_radius").unwrap_or_else(control_corner_radius)
}
pub fn set_dropdown_corner_radius(radius: f32) {
@@ -6111,6 +6133,19 @@ mod tests {
assert!(padding >= 0.0);
}
+ /// The control rung's key flattens to `control_corner_radius`, beside a
+ /// widget's own override — the config shape `control corner_radius=8 { button corner_radius=10 }`.
+ #[test]
+ fn control_rung_radius_flattens_beside_widget_overrides() {
+ let val: serde_json::Value = serde_json::json!({
+ "style": { "control": { "corner_radius": 8, "button": { "corner_radius": 10 } } }
+ });
+ let mut flat = String::new();
+ flatten_json_to_flat_props(&val, "", &mut flat);
+ assert!(flat.lines().any(|l| l.starts_with("control_corner_radius")), "{flat}");
+ assert!(flat.lines().any(|l| l.starts_with("button_corner_radius")), "{flat}");
+ }
+
#[test]
fn test_graph_style_configuration() {
// Trigger load_colors_once first so it doesn't overwrite values later