GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
dropdown/params: pane dropdowns animate, and releases stop leaking through
Three defects stacked into one user-visible bug (picking an entry in the
designer's Open dropdown opened a save chooser instead of loading the file):
1. ParametersBg::tick cascaded to toggles, sliders, ramps and colors but
never to `choices` — and the pane's internal widgets aren't in the host
tree, so the Dropdown's tick-receiver registration points at an id
ctx.tick can't resolve. Net: NO path ever advanced a pane dropdown's
anim_snap. Every params-pane dropdown in every host opened at zero drawn
extent — logically open, invisible, popover_rect a trigger-height sliver
— and the next click toggled it closed. The pane now ticks its choice
rows like the other animated rows.
2. The Dropdown handles presses only, so the paired RELEASE of a consumed
press fell through the host's dispatch to whatever the popover covers —
in the designer, the Save As button row. Releases are now consumed while
the menu is open or closing.
3. (Diagnosis aid, kept:) CCE_PARAM_DEBUG traces the pane's press dispatch —
which branch consumed, and the popover rect at gate time — alongside the
existing CCE_DD_DEBUG/CCE_SCROLL_DEBUG family.
Live-verified in the designer: one click opens the fully drawn menu, one
click on a recent entry loads it (title "Designer - gears"), no chooser.
src/widget/container/parameters_bg.rs | 25 ++++++++++++++++++++++++-
src/widget/input/dropdown.rs | 14 ++++++++++++++
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index 064f171..2b6f23a 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -1533,6 +1533,19 @@ impl Input for ParametersBg {
}
let mut changed = false;
let mut dummy = crate::context::UiContext::new();
+ // Choice rows tick their Dropdowns' open/close animation. This was the
+ // ONLY path that can advance a pane dropdown's anim_snap (the widget's
+ // tick-receiver registration points at an id pane internals never put
+ // in the host tree), and without it every params-pane dropdown opened
+ // at zero drawn extent: logically open, invisible, reporting a sliver
+ // popover rect — and the next click toggled it closed again.
+ for c_opt in &mut self.choices {
+ if let Some(d) = c_opt {
+ if d.tick(dt, &mut dummy) {
+ changed = true;
+ }
+ }
+ }
for cb_opt in &mut self.toggles {
if let Some(cb) = cb_opt {
if cb.tick(dt, &mut dummy) {
@@ -1797,8 +1810,15 @@ impl Input for ParametersBg {
continue;
}
if let Some(d) = d_opt {
+ if std::env::var("CCE_PARAM_DEBUG").is_ok() {
+ eprintln!("[pdbg] press ({px:.0},{py:.0}) choice[{i}] open-priority: popover_rect={:?}", d.popover_rect());
+ }
if d.popover_rect().is_some() {
- if d.mouse_input(button, state, px, py, ui) {
+ let consumed = d.mouse_input(button, state, px, py, ui);
+ if std::env::var("CCE_PARAM_DEBUG").is_ok() {
+ eprintln!("[pdbg] -> open dropdown consumed={consumed}");
+ }
+ if consumed {
if d.take_change() {
if let Some(val) = d.get_value_string() {
self.display_params[i].1 = val;
@@ -1846,6 +1866,9 @@ impl Input for ParametersBg {
} else if p.2 == "button" {
if let Some(b) = &mut self.buttons[i] {
if b.mouse_input(button, state, px, py, ui) {
+ if std::env::var("CCE_PARAM_DEBUG").is_ok() {
+ eprintln!("[pdbg] press ({px:.0},{py:.0}) BUTTON[{i}] '{}' consumed", p.0);
+ }
if b.take_click() {
p.1 = "clicked".to_string();
}
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index 2607396..35d79e0 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -1109,6 +1109,20 @@ impl Input for Dropdown {
fn on_event(&mut self, event: &Event, ectx: &mut EventCtx) -> bool {
self.settle_anim();
match event {
+ Event::MouseButton {
+ button: MouseButton::Left,
+ state: ElementState::Released,
+ ..
+ } => {
+ // While the menu is open (or shrinking closed), the paired
+ // release of any press this dropdown handled must not leak to
+ // widgets stacked beneath the popover: an unconsumed release
+ // falling through the host's dispatch landed on the button
+ // whose row the menu covers — in the designer's params pane,
+ // picking an "Open" entry fired the Save As button underneath
+ // and opened a save chooser on top of the load.
+ self.open || self.closing
+ }
Event::MouseButton {
button: MouseButton::Left,
state: ElementState::Pressed,