GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat: Dropdown::is_expanded says whether a dropdown is taking input
open alone stays true through the closing animation. A host that routes
input to a dropdown ahead of what is under it asks is_expanded. CLAUDE.md
also notes that the runner hands a press to a missed popover before the app.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLAUDE.md | 15 +++++++++++++--
src/widget/input/dropdown.rs | 11 +++++++++++
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index f5b2280..173439d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -247,10 +247,21 @@ same flip / slide / shorten rules inside the window; so does any app run with
(down for `dir > 0`), skipping header rows and `-` separators, stopping at either end
rather than wrapping. Both scroll a shortened menu to the row, WITHOUT re-hovering the
row under the pointer the way `scroll_by` does: the keyboard put the highlight there.
-The menu itself still reads no keys — a host that wants a walkable menu (the designer's
-dialog dropdowns) routes Up/Down to `step_hovered` and runs `hovered_item()` on Enter.
+The menu itself still reads no keys — a host that wants a walkable menu routes Up/Down
+to `step_hovered` and runs `hovered_item()` on Enter.
`the_keyboard_steps_the_highlight_over_what_cannot_run` is the test.
+### A dropdown says whether it is taking input (since 2026-10-01)
+
+`Dropdown::is_expanded()` is `open && !closing`: `open` alone stays true through the
+closing animation, while the plate is still drawn but presses and keys are no longer
+the dropdown's. A host that routes input to a dropdown ahead of what is under it (the
+designer's dialog hosts one) asks this. Such a host should also know that the runner
+hands every left press to each registered popover whose hit test MISSES it, before the
+app sees the press (`close_popovers_missed_by_press`) — and a popover covered by an
+outer popover's claim always misses — so the dropdown may already have taken the press
+by the time the app is asked.
+
### A row can open a submenu (since 2026-09-29)
`context_menu::set_row_submenu(idx, SubmenuSpec { options, header_count, sliders })`,
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index eb4a62b..d1ea2e0 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -245,6 +245,15 @@ impl Dropdown {
})
}
+ /// Whether the menu is open and taking input: open and not shrinking
+ /// closed. `open` alone stays true through the closing animation, while
+ /// the plate is still drawn but presses and keys are no longer its — a
+ /// host that routes input to the dropdown ahead of what is under it asks
+ /// this.
+ pub fn is_expanded(&self) -> bool {
+ self.open && !self.closing
+ }
+
/// Set (or clear) the app-owned concentric frame — see the `corner_frame` field docs.
pub fn set_corner_frame(&mut self, frame: Option<((f32, f32, f32, f32), f32, (bool, bool, bool, bool))>) {
self.corner_frame = frame;
@@ -1418,10 +1427,12 @@ mod tests {
assert!(move_changed);
assert_eq!(dd.hovered_item, Some(1));
+ assert!(dd.is_expanded(), "open and taking input");
// 4. Click option B selects it and starts the animated close
let select_changed = dd.mouse_input(MouseButton::Left, ElementState::Pressed, 50.0, 70.0, &mut dummy);
assert!(select_changed);
assert!(dd.closing, "selection starts the animated contraction");
+ assert!(dd.open && !dd.is_expanded(), "drawn while it shrinks, but no longer taking input");
dd.land_anim_for_test();
assert!(!dd.open);
assert_eq!(dd.selected, 1);