Improve logic for when submenus are kept open (#4166)
* Closes https://github.com/emilk/egui/issues/2853 * Closes https://github.com/emilk/egui/issues/4101 * Reverts parts of https://github.com/emilk/egui/pull/3055
This commit is contained in:
parent
f019032033
commit
0afbefc884
|
|
@ -613,30 +613,42 @@ impl MenuState {
|
|||
let pointer = ui.input(|i| i.pointer.clone());
|
||||
let open = self.is_open(sub_id);
|
||||
if self.moving_towards_current_submenu(&pointer) {
|
||||
// We don't close the submenu if the pointer is on its way to hover it.
|
||||
// ensure to repaint once even when pointer is not moving
|
||||
ui.ctx().request_repaint();
|
||||
} else if !open && button.hovered() {
|
||||
let pos = button.rect.right_top();
|
||||
self.open_submenu(sub_id, pos);
|
||||
} else if open
|
||||
&& ui.interact_bg(Sense::hover()).contains_pointer()
|
||||
&& !button.hovered()
|
||||
&& !self.hovering_current_submenu(&pointer)
|
||||
{
|
||||
// We are hovering something else in the menu, so close the submenu.
|
||||
self.close_submenu();
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if `dir` points from `pos` towards left side of `rect`.
|
||||
fn points_at_left_of_rect(pos: Pos2, dir: Vec2, rect: Rect) -> bool {
|
||||
let vel_a = dir.angle();
|
||||
let top_a = (rect.left_top() - pos).angle();
|
||||
let bottom_a = (rect.left_bottom() - pos).angle();
|
||||
bottom_a - vel_a >= 0.0 && top_a - vel_a <= 0.0
|
||||
}
|
||||
|
||||
/// Check if pointer is moving towards current submenu.
|
||||
fn moving_towards_current_submenu(&self, pointer: &PointerState) -> bool {
|
||||
if pointer.is_still() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(sub_menu) = self.current_submenu() {
|
||||
if let Some(pos) = pointer.hover_pos() {
|
||||
return Self::points_at_left_of_rect(pos, pointer.velocity(), sub_menu.read().rect);
|
||||
let rect = sub_menu.read().rect;
|
||||
return rect.intesects_ray(pos, pointer.velocity().normalized());
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Check if pointer is hovering current submenu.
|
||||
fn hovering_current_submenu(&self, pointer: &PointerState) -> bool {
|
||||
if let Some(sub_menu) = self.current_submenu() {
|
||||
if let Some(pos) = pointer.hover_pos() {
|
||||
return sub_menu.read().area_contains(pos);
|
||||
}
|
||||
}
|
||||
false
|
||||
|
|
@ -673,4 +685,8 @@ impl MenuState {
|
|||
self.sub_menu = Some((id, Arc::new(RwLock::new(Self::new(pos)))));
|
||||
}
|
||||
}
|
||||
|
||||
fn close_submenu(&mut self) {
|
||||
self.sub_menu = None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -714,8 +714,13 @@ impl Ui {
|
|||
.rect_contains_pointer(self.layer_id(), self.clip_rect().intersect(rect))
|
||||
}
|
||||
|
||||
/// Is the pointer (mouse/touch) above this [`Ui`]?
|
||||
/// Is the pointer (mouse/touch) above the current [`Ui`]?
|
||||
///
|
||||
/// Equivalent to `ui.rect_contains_pointer(ui.min_rect())`
|
||||
///
|
||||
/// Note that this tests against the _current_ [`Ui::min_rect`].
|
||||
/// If you want to test against the final `min_rect`,
|
||||
/// use [`Self::interact_bg`] instead.
|
||||
pub fn ui_contains_pointer(&self) -> bool {
|
||||
self.rect_contains_pointer(self.min_rect())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -605,6 +605,32 @@ impl Rect {
|
|||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
/// Does this Rect intersect the given ray (where `d` is normalized)?
|
||||
pub fn intesects_ray(&self, o: Pos2, d: Vec2) -> bool {
|
||||
let mut tmin = -f32::INFINITY;
|
||||
let mut tmax = f32::INFINITY;
|
||||
|
||||
if d.x != 0.0 {
|
||||
let tx1 = (self.min.x - o.x) / d.x;
|
||||
let tx2 = (self.max.x - o.x) / d.x;
|
||||
|
||||
tmin = tmin.max(tx1.min(tx2));
|
||||
tmax = tmax.min(tx1.max(tx2));
|
||||
}
|
||||
|
||||
if d.y != 0.0 {
|
||||
let ty1 = (self.min.y - o.y) / d.y;
|
||||
let ty2 = (self.max.y - o.y) / d.y;
|
||||
|
||||
tmin = tmin.max(ty1.min(ty2));
|
||||
tmax = tmax.min(ty1.max(ty2));
|
||||
}
|
||||
|
||||
tmin <= tmax
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Rect {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
||||
|
|
|
|||
Loading…
Reference in New Issue