git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit711f42d3056015a3a48edda53d2c450604d3963c
parent232a5d8910
authorLucas Galante <[email protected]>
date2026-09-08 12:29
feat(layout): one fallback height for text controls, one for tracks; defaults for the sizeless widgets

The per-control fallbacks were scattered (button 40, toggle 44, dropdown 44,
textbox 44, font selector 44, spinbox 26, colour selector 22, slider 28,
range slider 28, progress bar 24), so a form built from defaults never
lined up and every config had to pin each one. They now come from two named
baselines: DEFAULT_CONTROL_HEIGHT = 24 for the text-bearing controls and
DEFAULT_TRACK_HEIGHT = 16 for the track-shaped ones. A per-control
style.control.<name>.height key stays the deliberate exception.

Widgets that declared no height at all now do, from the same baselines:
ButtonStrip and Breadcrumb are a button row tall (a vertical strip stays
content-sized), UsageBar is a progress-bar track, StatusDot is a 12px
square (StatusDot::SIZE).

Co-Authored-By: Claude Fable 5.1 <[email protected]>

 src/layout.rs                      | 30 ++++++++++++++++++++----------
 src/widget/container/breadcrumb.rs |  7 ++++++-
 src/widget/display/status_dot.rs   | 10 +++++++++-
 src/widget/display/usage_bar.rs    |  7 ++++++-
 src/widget/input/button_strip.rs   |  9 +++++++++
 5 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/src/layout.rs b/src/layout.rs
index 29ded73..c9414ec 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -285,15 +285,25 @@ pub fn parse_font_string(s: &str) -> (String, Option<f32>) {
 }
 
 static SECTION_PADDING: RwLock<f32> = RwLock::new(8.0);
-static SPINBOX_HEIGHT: RwLock<f32> = RwLock::new(26.0);
+/// The height every text-bearing control falls back to when its own
+/// `style.control.<name>.height` is unset: button, toggle (and the checkbox
+/// row), dropdown, textbox (and the keybind recorder), spinbox, font selector,
+/// colour selector, button strip, breadcrumb. One number, so a form built from
+/// defaults lines up; a per-control key is the deliberate exception.
+pub const DEFAULT_CONTROL_HEIGHT: f32 = 24.0;
+/// The same for the track-shaped controls: slider, range slider, progress bar,
+/// usage bar.
+pub const DEFAULT_TRACK_HEIGHT: f32 = 16.0;
+
+static SPINBOX_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
 static SPINBOX_BUTTON_PADDING: RwLock<f32> = RwLock::new(0.0);
-static COLOR_SELECTOR_HEIGHT: RwLock<f32> = RwLock::new(22.0);
-static TEXTBOX_HEIGHT: RwLock<f32> = RwLock::new(44.0);
-static FONT_SELECTOR_HEIGHT: RwLock<f32> = RwLock::new(44.0);
-static SLIDER_HEIGHT: RwLock<f32> = RwLock::new(28.0);
-static PROGRESSBAR_HEIGHT: RwLock<f32> = RwLock::new(24.0);
-static RANGESLIDER_HEIGHT: RwLock<f32> = RwLock::new(28.0);
-static TOGGLE_HEIGHT: RwLock<f32> = RwLock::new(44.0);
+static COLOR_SELECTOR_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
+static TEXTBOX_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
+static FONT_SELECTOR_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
+static SLIDER_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_TRACK_HEIGHT);
+static PROGRESSBAR_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_TRACK_HEIGHT);
+static RANGESLIDER_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_TRACK_HEIGHT);
+static TOGGLE_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
 static COLOR_SELECTOR_FONT: RwLock<String> = RwLock::new(String::new());
 static COLOR_SELECTOR_PREVIEW_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
 static COLOR_SELECTOR_PREVIEW_MARGIN: RwLock<f32> = RwLock::new(0.0);
@@ -309,7 +319,7 @@ static BUTTON_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_HEIGHT: RwLock<f32> = RwLock::new(40.0);
+static BUTTON_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
 static RAMP_HEIGHT: RwLock<f32> = RwLock::new(32.0);
 static BUTTON_STRIP_SPACING: RwLock<f32> = RwLock::new(8.0);
 static SCROLLBAR_WIDTH: RwLock<f32> = RwLock::new(4.0);
@@ -321,7 +331,7 @@ static TREE_OPACITY: RwLock<f32> = RwLock::new(1.0);
 static TREE_BLUR: RwLock<f32> = RwLock::new(0.0);
 
 static PLATE_PADDING: RwLock<f32> = RwLock::new(20.0);
-static DROPDOWN_HEIGHT: RwLock<f32> = RwLock::new(44.0);
+static DROPDOWN_HEIGHT: RwLock<f32> = RwLock::new(DEFAULT_CONTROL_HEIGHT);
 static NESTED_SECTION_LABEL_ALIGNMENT: RwLock<u8> = RwLock::new(0);
 static TOUCHPAD_NATURAL_SCROLL: RwLock<bool> = RwLock::new(false);
 
diff --git a/src/widget/container/breadcrumb.rs b/src/widget/container/breadcrumb.rs
index 5c50f0d..0f8dacc 100644
--- a/src/widget/container/breadcrumb.rs
+++ b/src/widget/container/breadcrumb.rs
@@ -278,7 +278,12 @@ impl Breadcrumb {
     }
 }
 
-impl Layout for Breadcrumb {}
+impl Layout for Breadcrumb {
+    /// The segments are button plates, so the bar is one button row tall.
+    fn intrinsic_size(&self) -> Option<crate::scene::layout::Size> {
+        Some(crate::scene::layout::Size::new(0.0, crate::layout::button_height()))
+    }
+}
 
 impl Paint for Breadcrumb {
     fn color(&self) -> [f32; 4] {
diff --git a/src/widget/display/status_dot.rs b/src/widget/display/status_dot.rs
index 7ed4949..7072ee4 100644
--- a/src/widget/display/status_dot.rs
+++ b/src/widget/display/status_dot.rs
@@ -23,6 +23,9 @@ pub struct StatusDot {
 }
 
 impl StatusDot {
+    /// The dot's default side.
+    pub const SIZE: f32 = 12.0;
+
     pub fn new(status: DotStatus) -> Adapted<StatusDot> {
         Adapted::new(StatusDot { status })
     }
@@ -32,7 +35,12 @@ impl StatusDot {
     }
 }
 
-impl Layout for StatusDot {}
+impl Layout for StatusDot {
+    /// A dot: a fixed small square unless the host sizes it.
+    fn intrinsic_size(&self) -> Option<crate::scene::layout::Size> {
+        Some(crate::scene::layout::Size::new(StatusDot::SIZE, StatusDot::SIZE))
+    }
+}
 
 impl Paint for StatusDot {
     fn color(&self) -> [f32; 4] {
diff --git a/src/widget/display/usage_bar.rs b/src/widget/display/usage_bar.rs
index eeca0ad..57c0a93 100644
--- a/src/widget/display/usage_bar.rs
+++ b/src/widget/display/usage_bar.rs
@@ -37,7 +37,12 @@ impl Adapted<UsageBar> {
     }
 }
 
-impl Layout for UsageBar {}
+impl Layout for UsageBar {
+    /// A track, the progress bar's height.
+    fn intrinsic_size(&self) -> Option<crate::scene::layout::Size> {
+        Some(crate::scene::layout::Size::new(0.0, crate::layout::progressbar_height()))
+    }
+}
 
 impl Paint for UsageBar {
     fn color(&self) -> [f32; 4] {
diff --git a/src/widget/input/button_strip.rs b/src/widget/input/button_strip.rs
index 567876f..8f37aa4 100644
--- a/src/widget/input/button_strip.rs
+++ b/src/widget/input/button_strip.rs
@@ -285,6 +285,15 @@ impl ButtonStrip {
 }
 
 impl crate::widget::Layout for ButtonStrip {
+    /// A horizontal strip is one button row tall; a vertical one is content-sized.
+    fn intrinsic_size(&self) -> Option<crate::scene::layout::Size> {
+        if self.vertical {
+            None
+        } else {
+            Some(crate::scene::layout::Size::new(0.0, crate::layout::button_height()))
+        }
+    }
+
     // The legacy set_rect override: regenerate the rotated tab labels only when the rect
     // actually changed.
     fn rect_assigned(&mut self, rect: crate::scene::layout::Rect) {