From 5bf44f885056fe3132ddcff1f0c9e8c2b1c04279 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 10 Feb 2024 10:48:00 +0100 Subject: [PATCH] Fix `Response::interact` and `Ui:interact_with_hovered` (#4013) These broke in 0.26 * #3989 * #4006 --- crates/egui/src/context.rs | 30 +++++++++++++++++++++++--- crates/egui/src/response.rs | 2 +- crates/egui/src/sense.rs | 16 ++++++++++++++ crates/egui_demo_lib/src/demo/tests.rs | 12 ++++++++++- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 54f01e99..0749a1c6 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -234,7 +234,18 @@ impl WidgetRects { /// Insert the given widget rect in the given layer. pub fn insert(&mut self, layer_id: LayerId, widget_rect: WidgetRect) { - self.by_layer.entry(layer_id).or_default().push(widget_rect); + let layer_widgets = self.by_layer.entry(layer_id).or_default(); + + if let Some(last) = layer_widgets.last_mut() { + if last.id == widget_rect.id { + // e.g. calling `response.interact(…)` right after interacting. + last.sense |= widget_rect.sense; + last.rect = last.rect.union(widget_rect.rect); + return; + } + } + + layer_widgets.push(widget_rect); } } @@ -1089,7 +1100,19 @@ impl Context { let clicked_elsewhere = res.clicked_elsewhere(); self.write(|ctx| { - let input = &ctx.viewports.entry(ctx.viewport_id()).or_default().input; + let viewport = ctx.viewports.entry(ctx.viewport_id()).or_default(); + + // We need to remember this widget. + // `widget_contains_pointer` also does this, but in case of e.g. `Response::interact`, + // that won't be called. + // We add all widgets here, even non-interactive ones, + // because we need this list not only for checking for blocking widgets, + // but also to know when we have reached the widget we are checking for cover. + viewport + .layer_rects_this_frame + .insert(layer_id, WidgetRect { id, rect, sense }); + + let input = &viewport.input; let memory = &mut ctx.memory; if sense.focusable { @@ -2292,9 +2315,10 @@ impl Context { let pointer_pos = viewport.input.pointer.interact_pos(); if let Some(pointer_pos) = pointer_pos { if let Some(rects) = viewport.layer_rects_prev_frame.by_layer.get(&layer_id) { + // Iterate backwards, i.e. topmost widgets first. for blocking in rects.iter().rev() { if blocking.id == id { - // There are no earlier widgets before this one, + // We've checked all widgets there were added after this one last frame, // which means there are no widgets covering us. break; } diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 76cfb824..2cef7849 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -607,7 +607,7 @@ impl Response { self.rect, sense, self.enabled, - self.hovered, + self.contains_pointer, ) } diff --git a/crates/egui/src/sense.rs b/crates/egui/src/sense.rs index 236437d8..53baa3ec 100644 --- a/crates/egui/src/sense.rs +++ b/crates/egui/src/sense.rs @@ -85,3 +85,19 @@ impl Sense { self.click || self.drag } } + +impl std::ops::BitOr for Sense { + type Output = Self; + + #[inline] + fn bitor(self, rhs: Self) -> Self { + self.union(rhs) + } +} + +impl std::ops::BitOrAssign for Sense { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = self.union(rhs); + } +} diff --git a/crates/egui_demo_lib/src/demo/tests.rs b/crates/egui_demo_lib/src/demo/tests.rs index 3ff3e034..12df32d8 100644 --- a/crates/egui_demo_lib/src/demo/tests.rs +++ b/crates/egui_demo_lib/src/demo/tests.rs @@ -357,6 +357,8 @@ pub struct InputTest { #[cfg_attr(feature = "serde", serde(skip))] history: [DeduplicatedHistory; 4], + late_interaction: bool, + show_hovers: bool, } @@ -394,6 +396,8 @@ impl super::View for InputTest { ui.checkbox(&mut self.show_hovers, "Show hover state"); }); + ui.checkbox(&mut self.late_interaction, "Use Response::interact"); + ui.label("This tests how egui::Response reports events.\n\ The different buttons are sensitive to different things.\n\ Try interacting with them with any mouse button by clicking, double-clicking, triple-clicking, or dragging them."); @@ -409,7 +413,13 @@ impl super::View for InputTest { .enumerate() { columns[i].push_id(i, |ui| { - let response = ui.add(egui::Button::new(sense_name).sense(sense)); + let response = if self.late_interaction { + let first_response = + ui.add(egui::Button::new(sense_name).sense(egui::Sense::hover())); + first_response.interact(sense) + } else { + ui.add(egui::Button::new(sense_name).sense(sense)) + }; let info = response_summary(&response, self.show_hovers); self.history[i].add(info.trim().to_owned()); self.history[i].ui(ui);