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.
This commit is contained in:
Emil Ernerfeldt 2024-03-26 11:12:49 +01:00 committed by GitHub
parent 9cfaf8b961
commit 8a880d6d0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 24 additions and 9 deletions

View File

@ -61,6 +61,7 @@ impl State {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Area { pub struct Area {
pub(crate) id: Id, pub(crate) id: Id,
sense: Option<Sense>,
movable: bool, movable: bool,
interactable: bool, interactable: bool,
enabled: bool, enabled: bool,
@ -78,6 +79,7 @@ impl Area {
pub fn new(id: Id) -> Self { pub fn new(id: Id) -> Self {
Self { Self {
id, id,
sense: None,
movable: true, movable: true,
interactable: true, interactable: true,
constrain: false, constrain: false,
@ -114,7 +116,7 @@ impl Area {
self self
} }
/// moveable by dragging the area? /// Moveable by dragging the area?
#[inline] #[inline]
pub fn movable(mut self, movable: bool) -> Self { pub fn movable(mut self, movable: bool) -> Self {
self.movable = movable; self.movable = movable;
@ -139,6 +141,15 @@ impl Area {
self 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 /// `order(Order::Foreground)` for an Area that should always be on top
#[inline] #[inline]
pub fn order(mut self, order: Order) -> Self { pub fn order(mut self, order: Order) -> Self {
@ -255,6 +266,7 @@ impl Area {
pub(crate) fn begin(self, ctx: &Context) -> Prepared { pub(crate) fn begin(self, ctx: &Context) -> Prepared {
let Self { let Self {
id, id,
sense,
movable, movable,
order, order,
interactable, interactable,
@ -299,13 +311,15 @@ impl Area {
// interact right away to prevent frame-delay // interact right away to prevent frame-delay
let mut move_response = { let mut move_response = {
let interact_id = layer_id.id.with("move"); let interact_id = layer_id.id.with("move");
let sense = if movable { let sense = sense.unwrap_or_else(|| {
Sense::drag() if movable {
} else if interactable { Sense::drag()
Sense::click() // allow clicks to bring to front } else if interactable {
} else { Sense::click() // allow clicks to bring to front
Sense::hover() } else {
}; Sense::hover()
}
});
let move_response = ctx.create_widget(WidgetRect { let move_response = ctx.create_widget(WidgetRect {
id: interact_id, id: interact_id,

View File

@ -149,7 +149,8 @@ pub(crate) fn menu_ui<'c, R>(
.order(Order::Foreground) .order(Order::Foreground)
.fixed_pos(pos) .fixed_pos(pos)
.constrain_to(ctx.screen_rect()) .constrain_to(ctx.screen_rect())
.interactable(true); .interactable(true)
.sense(Sense::hover());
let area_response = area.show(ctx, |ui| { let area_response = area.show(ctx, |ui| {
set_menu_style(ui.style_mut()); set_menu_style(ui.style_mut());