Fix menus and interactive popups not closing when framerate was low (#4757)

This commit is contained in:
Emil Ernerfeldt 2024-07-02 21:33:22 +02:00 committed by GitHub
parent 8ef0e85b85
commit fcb7764e48
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 25 additions and 5 deletions

View File

@ -726,6 +726,9 @@ pub struct PointerState {
/// Current velocity of pointer. /// Current velocity of pointer.
velocity: Vec2, velocity: Vec2,
/// Current direction of pointer.
direction: Vec2,
/// Recent movement of the pointer. /// Recent movement of the pointer.
/// Used for calculating velocity of pointer. /// Used for calculating velocity of pointer.
pos_history: History<Pos2>, pos_history: History<Pos2>,
@ -774,7 +777,8 @@ impl Default for PointerState {
delta: Vec2::ZERO, delta: Vec2::ZERO,
motion: None, motion: None,
velocity: Vec2::ZERO, velocity: Vec2::ZERO,
pos_history: History::new(0..1000, 0.1), direction: Vec2::ZERO,
pos_history: History::new(2..1000, 0.1),
down: Default::default(), down: Default::default(),
press_origin: None, press_origin: None,
press_start_time: None, press_start_time: None,
@ -889,6 +893,7 @@ impl PointerState {
// When dragging a slider and the mouse leaves the viewport, we still want the drag to work, // When dragging a slider and the mouse leaves the viewport, we still want the drag to work,
// so we don't treat this as a `PointerEvent::Released`. // so we don't treat this as a `PointerEvent::Released`.
// NOTE: we do NOT clear `self.interact_pos` here. It will be cleared next frame. // NOTE: we do NOT clear `self.interact_pos` here. It will be cleared next frame.
self.pos_history.clear();
} }
Event::MouseMoved(delta) => *self.motion.get_or_insert(Vec2::ZERO) += *delta, Event::MouseMoved(delta) => *self.motion.get_or_insert(Vec2::ZERO) += *delta,
_ => {} _ => {}
@ -920,6 +925,8 @@ impl PointerState {
self.last_move_time = time; self.last_move_time = time;
} }
self.direction = self.pos_history.velocity().unwrap_or_default().normalized();
self.started_decidedly_dragging = self.is_decidedly_dragging() && !was_decidedly_dragging; self.started_decidedly_dragging = self.is_decidedly_dragging() && !was_decidedly_dragging;
self self
@ -944,11 +951,22 @@ impl PointerState {
} }
/// Current velocity of pointer. /// Current velocity of pointer.
///
/// This is smoothed over a few frames,
/// but can be ZERO when frame-rate is bad.
#[inline(always)] #[inline(always)]
pub fn velocity(&self) -> Vec2 { pub fn velocity(&self) -> Vec2 {
self.velocity self.velocity
} }
/// Current direction of the pointer.
///
/// This is less sensitive to bad framerate than [`Self::velocity`].
#[inline(always)]
pub fn direction(&self) -> Vec2 {
self.direction
}
/// Where did the current click/drag originate? /// Where did the current click/drag originate?
/// `None` if no mouse button is down. /// `None` if no mouse button is down.
#[inline(always)] #[inline(always)]
@ -1284,6 +1302,7 @@ impl PointerState {
delta, delta,
motion, motion,
velocity, velocity,
direction,
pos_history: _, pos_history: _,
down, down,
press_origin, press_origin,
@ -1304,6 +1323,7 @@ impl PointerState {
"velocity: [{:3.0} {:3.0}] points/sec", "velocity: [{:3.0} {:3.0}] points/sec",
velocity.x, velocity.y velocity.x, velocity.y
)); ));
ui.label(format!("direction: {direction:?}"));
ui.label(format!("down: {down:#?}")); ui.label(format!("down: {down:#?}"));
ui.label(format!("press_origin: {press_origin:?}")); ui.label(format!("press_origin: {press_origin:?}"));
ui.label(format!("press_start_time: {press_start_time:?} s")); ui.label(format!("press_start_time: {press_start_time:?} s"));

View File

@ -683,7 +683,7 @@ impl MenuState {
if let Some(sub_menu) = self.current_submenu() { if let Some(sub_menu) = self.current_submenu() {
if let Some(pos) = pointer.hover_pos() { if let Some(pos) = pointer.hover_pos() {
let rect = sub_menu.read().rect; let rect = sub_menu.read().rect;
return rect.intersects_ray(pos, pointer.velocity().normalized()); return rect.intersects_ray(pos, pointer.direction().normalized());
} }
} }
false false

View File

@ -594,9 +594,9 @@ impl Response {
let is_tooltip_open = self.is_tooltip_open(); let is_tooltip_open = self.is_tooltip_open();
if is_tooltip_open { if is_tooltip_open {
let (pointer_pos, pointer_vel) = self let (pointer_pos, pointer_dir) = self
.ctx .ctx
.input(|i| (i.pointer.hover_pos(), i.pointer.velocity())); .input(|i| (i.pointer.hover_pos(), i.pointer.direction()));
if let Some(pointer_pos) = pointer_pos { if let Some(pointer_pos) = pointer_pos {
if self.rect.contains(pointer_pos) { if self.rect.contains(pointer_pos) {
@ -624,7 +624,7 @@ impl Response {
if let Some(pos) = pointer_pos { if let Some(pos) = pointer_pos {
let pointer_in_area_or_on_the_way_there = rect.contains(pos) let pointer_in_area_or_on_the_way_there = rect.contains(pos)
|| rect.intersects_ray(pos, pointer_vel.normalized()); || rect.intersects_ray(pos, pointer_dir.normalized());
if pointer_in_area_or_on_the_way_there { if pointer_in_area_or_on_the_way_there {
return true; return true;