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

commit58daa688f59febe1bfac0a7817a9461edf492a0f
parentddced5c623
authorLucas Galante <[email protected]>
date2026-07-07 19:28
feat(scene): Dropdown::intrinsic_size (content-sized leaf set complete)

Dropdown reports intrinsic size from content_width() (widest option + arrow/padding inset) at the configured dropdown height, so it doesn't resize as the selection changes. With Label and Button, this completes the content-sized leaf set; other controls (textbox/slider/spinbox) are grow/fill widgets sized by their container, not content. Test asserts width fits the widest option. 112 tests.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

 src/widget/input/dropdown.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index 7ee8716..66fa8b3 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -298,6 +298,13 @@ impl Element for Dropdown {
         Some(crate::layout::dropdown_height())
     }
 
+    /// Content size for the scene layout engine (Phase 2b): wide enough for the widest option
+    /// (via `content_width`, which already includes the arrow/padding inset), at the configured
+    /// dropdown height — so the control doesn't resize as the selection changes.
+    fn intrinsic_size(&self) -> Option<crate::scene::layout::Size> {
+        Some(crate::scene::layout::Size::new(self.content_width(), crate::layout::dropdown_height()))
+    }
+
     fn rounded_corners(&self) -> (bool, bool, bool, bool) {
         let r = crate::layout::dropdown_corner_radius();
         if r > 0.0 {
@@ -968,5 +975,22 @@ mod tests {
         let size_no_auto = dd_no_auto.measure(LayoutConstraints::new(0.0, 500.0, 24.0, 24.0), &dummy);
         assert_eq!(size_no_auto.width, 0.0);
     }
+
+    #[test]
+    fn intrinsic_size_fits_widest_option() {
+        let wide = Dropdown::new(
+            vec!["Short".to_string(), "A much longer option name".to_string()],
+            0,
+        );
+        let size = wide.intrinsic_size().expect("dropdown reports intrinsic size");
+        assert!(size.width >= wide.content_width(), "width fits the widest option");
+        assert_eq!(size.height, crate::layout::dropdown_height());
+
+        let narrow = Dropdown::new(vec!["Hi".to_string()], 0);
+        assert!(
+            size.width > narrow.intrinsic_size().unwrap().width,
+            "more/longer options measure wider",
+        );
+    }
 }