From 8a880d6d0f851eb06f750364b4c796c0d2853bbc Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 26 Mar 2024 11:12:49 +0100 Subject: [PATCH] Add `Area::sense` and improve hit-testing of buttons in menus (#4234) Previously, putting the cursor in the gap between two menu buttons would not hover any of the buttons, but the click-sensitive menu itself. Now the menu is no longer click-sensitive. --- crates/egui/src/containers/area.rs | 30 ++++++++++++++++++++++-------- crates/egui/src/menu.rs | 3 ++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/crates/egui/src/containers/area.rs b/crates/egui/src/containers/area.rs index c66be433..0c73ddf9 100644 --- a/crates/egui/src/containers/area.rs +++ b/crates/egui/src/containers/area.rs @@ -61,6 +61,7 @@ impl State { #[derive(Clone, Copy, Debug)] pub struct Area { pub(crate) id: Id, + sense: Option, movable: bool, interactable: bool, enabled: bool, @@ -78,6 +79,7 @@ impl Area { pub fn new(id: Id) -> Self { Self { id, + sense: None, movable: true, interactable: true, constrain: false, @@ -114,7 +116,7 @@ impl Area { self } - /// moveable by dragging the area? + /// Moveable by dragging the area? #[inline] pub fn movable(mut self, movable: bool) -> Self { self.movable = movable; @@ -139,6 +141,15 @@ impl Area { self } + /// Explicitly set a sense. + /// + /// If not set, this will default to `Sense::drag()` if movable, `Sense::click()` if interactable, and `Sense::hover()` otherwise. + #[inline] + pub fn sense(mut self, sense: Sense) -> Self { + self.sense = Some(sense); + self + } + /// `order(Order::Foreground)` for an Area that should always be on top #[inline] pub fn order(mut self, order: Order) -> Self { @@ -255,6 +266,7 @@ impl Area { pub(crate) fn begin(self, ctx: &Context) -> Prepared { let Self { id, + sense, movable, order, interactable, @@ -299,13 +311,15 @@ impl Area { // interact right away to prevent frame-delay let mut move_response = { let interact_id = layer_id.id.with("move"); - let sense = if movable { - Sense::drag() - } else if interactable { - Sense::click() // allow clicks to bring to front - } else { - Sense::hover() - }; + let sense = sense.unwrap_or_else(|| { + if movable { + Sense::drag() + } else if interactable { + Sense::click() // allow clicks to bring to front + } else { + Sense::hover() + } + }); let move_response = ctx.create_widget(WidgetRect { id: interact_id, diff --git a/crates/egui/src/menu.rs b/crates/egui/src/menu.rs index d551cd5b..84fd1b2e 100644 --- a/crates/egui/src/menu.rs +++ b/crates/egui/src/menu.rs @@ -149,7 +149,8 @@ pub(crate) fn menu_ui<'c, R>( .order(Order::Foreground) .fixed_pos(pos) .constrain_to(ctx.screen_rect()) - .interactable(true); + .interactable(true) + .sense(Sense::hover()); let area_response = area.show(ctx, |ui| { set_menu_style(ui.style_mut());