From 2d725d157f0dd1302ec5180e9b5d393695ecbab7 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 22 Jan 2024 11:17:03 +0100 Subject: [PATCH] Add `Response::contains_pointer` (#3859) * Part of https://github.com/emilk/egui/issues/3841 --- crates/egui/src/response.rs | 15 +++++++++++++- .../egui_demo_lib/src/demo/drag_and_drop.rs | 20 +++++++++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 46cff117c9e..605cf95f66a 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -212,7 +212,9 @@ impl Response { /// The pointer is hovering above this widget or the widget was clicked/tapped this frame. /// - /// Note that this is slightly different from checking `response.rect.contains(pointer_pos)`. + /// This will be `false` whenever some other widget is being dragged. + /// + /// Note that this is slightly different from [`Self::contains_pointer`]. /// For one, the hover rectangle is slightly larger, by half of the current item spacing /// (to make it easier to click things). But `hovered` also checks that no other area /// is covering this response rectangle. @@ -221,6 +223,17 @@ impl Response { self.hovered } + /// Returns true if the pointer is contained by the response rect. + /// + /// In contrast to [`Self::hovered`], this can be `true` even if some other widget is being dragged. + /// This means it is useful for styling things like drag-and-drop targets. + /// + /// In contrast to [`Self::hovered`], this is true even when dragging some other widget + /// onto this one. + pub fn contains_pointer(&self) -> bool { + self.ctx.rect_contains_pointer(self.layer_id, self.rect) + } + /// The widget is highlighted via a call to [`Self::highlight`] or [`Context::highlight_widget`]. #[doc(hidden)] pub fn highlighted(&self) -> bool { diff --git a/crates/egui_demo_lib/src/demo/drag_and_drop.rs b/crates/egui_demo_lib/src/demo/drag_and_drop.rs index 7376d9b4fe7..37c21238047 100644 --- a/crates/egui_demo_lib/src/demo/drag_and_drop.rs +++ b/crates/egui_demo_lib/src/demo/drag_and_drop.rs @@ -49,11 +49,14 @@ pub fn drop_target( let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin); let (rect, response) = ui.allocate_at_least(outer_rect.size(), Sense::hover()); - let style = if is_being_dragged && can_accept_what_is_being_dragged && response.hovered() { - ui.visuals().widgets.active - } else { - ui.visuals().widgets.inactive - }; + // NOTE: we use `response.contains_pointer` here instead of `hovered`, because + // `hovered` is always false when another widget is being dragged. + let style = + if is_being_dragged && can_accept_what_is_being_dragged && response.contains_pointer() { + ui.visuals().widgets.active + } else { + ui.visuals().widgets.inactive + }; let mut fill = style.bg_fill; let mut stroke = style.bg_stroke; @@ -149,7 +152,12 @@ impl super::View for DragAndDropDemo { }); let is_being_dragged = ui.memory(|mem| mem.is_anything_being_dragged()); - if is_being_dragged && can_accept_what_is_being_dragged && response.hovered() { + // NOTE: we use `response.contains_pointer` here instead of `hovered`, because + // `hovered` is always false when another widget is being dragged. + if is_being_dragged + && can_accept_what_is_being_dragged + && response.contains_pointer() + { drop_col = Some(col_idx); } }