Fix `Response::interact` and `Ui:interact_with_hovered` (#4013)

These broke in 0.26

* #3989
* #4006
This commit is contained in:
Emil Ernerfeldt 2024-02-10 10:48:00 +01:00 committed by GitHub
parent 808dc0103a
commit 5bf44f8850
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 5 deletions

View File

@ -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;
}

View File

@ -607,7 +607,7 @@ impl Response {
self.rect,
sense,
self.enabled,
self.hovered,
self.contains_pointer,
)
}

View File

@ -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);
}
}

View File

@ -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);