Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Response::interact and Ui:interact_with_hovered #4013

Merged
merged 6 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ impl Response {
self.rect,
sense,
self.enabled,
self.hovered,
self.contains_pointer,
)
}

Expand Down
16 changes: 16 additions & 0 deletions crates/egui/src/sense.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
12 changes: 11 additions & 1 deletion crates/egui_demo_lib/src/demo/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ pub struct InputTest {
#[cfg_attr(feature = "serde", serde(skip))]
history: [DeduplicatedHistory; 4],

late_interaction: bool,

show_hovers: bool,
}

Expand Down Expand Up @@ -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.");
Expand All @@ -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);
Expand Down
Loading