From e401fa41495a974090acf3dd5f42cfc5b0d49b55 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Tue, 10 May 2022 19:19:38 +0300 Subject: [PATCH 1/3] Mouse delta from DeviceEvent --- eframe/src/native/epi_integration.rs | 4 ++++ eframe/src/native/run.rs | 14 ++++++++++++++ egui-winit/src/lib.rs | 15 +++++++++++---- egui/src/data/input.rs | 5 +++++ egui/src/input_state.rs | 19 +++++++++++++++++++ egui/src/response.rs | 18 ++++++++++++++++++ egui/src/widgets/drag_value.rs | 3 ++- 7 files changed, 73 insertions(+), 5 deletions(-) diff --git a/eframe/src/native/epi_integration.rs b/eframe/src/native/epi_integration.rs index dd7b729eb4c..b87d671d63b 100644 --- a/eframe/src/native/epi_integration.rs +++ b/eframe/src/native/epi_integration.rs @@ -239,6 +239,10 @@ impl EpiIntegration { self.quit } + pub fn on_mouse_delta(&mut self, delta: (f64, f64)) { + self.egui_winit.on_mouse_delta(delta); + } + pub fn on_event(&mut self, app: &mut dyn epi::App, event: &winit::event::WindowEvent<'_>) { use winit::event::{ElementState, MouseButton, WindowEvent}; diff --git a/eframe/src/native/run.rs b/eframe/src/native/run.rs index 82b7cf47f65..128390f5665 100644 --- a/eframe/src/native/run.rs +++ b/eframe/src/native/run.rs @@ -154,6 +154,13 @@ pub fn run_glow( winit::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(), winit::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(), + winit::event::Event::DeviceEvent { + device_id: _, + event: winit::event::DeviceEvent::MouseMotion { delta }, + } => { + integration.on_mouse_delta(delta); + } + winit::event::Event::WindowEvent { event, .. } => { match &event { winit::event::WindowEvent::Focused(new_focused) => { @@ -303,6 +310,13 @@ pub fn run_wgpu( winit::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(), winit::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(), + winit::event::Event::DeviceEvent { + device_id: _, + event: winit::event::DeviceEvent::MouseMotion { delta }, + } => { + integration.on_mouse_delta(delta); + } + winit::event::Event::WindowEvent { event, .. } => { match &event { winit::event::WindowEvent::Focused(new_focused) => { diff --git a/egui-winit/src/lib.rs b/egui-winit/src/lib.rs index 4286af84c2e..e8ba9710cdb 100644 --- a/egui-winit/src/lib.rs +++ b/egui-winit/src/lib.rs @@ -6,6 +6,7 @@ #![allow(clippy::manual_range_contains)] pub use egui; +use egui::Vec2; pub use winit; pub mod clipboard; @@ -119,6 +120,13 @@ impl State { self.egui_input.take() } + pub fn on_mouse_delta(&mut self, delta: (f64, f64)) { + self.egui_input.events.push(egui::Event::MouseDelta(Vec2 { + x: delta.0 as f32, + y: delta.1 as f32, + })) + } + /// Call this when there is a new event. /// /// The result can be found in [`Self::egui_input`] and be extracted with [`Self::take_egui_input`]. @@ -152,6 +160,7 @@ impl State { } WindowEvent::CursorMoved { position, .. } => { self.on_cursor_moved(*position); + egui_ctx.is_using_pointer() } WindowEvent::CursorLeft { .. } => { @@ -226,10 +235,8 @@ impl State { }; false } - _ => { - // dbg!(event); - false - } + + _ => false, } } diff --git a/egui/src/data/input.rs b/egui/src/data/input.rs index adfa7db9578..23da2753a08 100644 --- a/egui/src/data/input.rs +++ b/egui/src/data/input.rs @@ -177,6 +177,11 @@ pub enum Event { /// The mouse or touch moved to a new place. PointerMoved(Pos2), + /// The mouse delta from winit::DeviceEvent. MouseDelta and PointerMoved can be emmited simultaneously. + /// If MouseDelta accumulated value is zero per frame, then `old_pos-new_pos` will be used as fallback. + /// For now it used in situations when we need delta but mouse pointer is on screen edge. + MouseDelta(Vec2), + /// A mouse button was pressed or released (or a touch started or stopped). PointerButton { /// Where is the pointer? diff --git a/egui/src/input_state.rs b/egui/src/input_state.rs index 6cc7ea13482..e6d9d049292 100644 --- a/egui/src/input_state.rs +++ b/egui/src/input_state.rs @@ -450,6 +450,11 @@ pub struct PointerState { /// How much the pointer moved compared to last frame, in points. delta: Vec2, + /// How much the pointer moved despite on cursor location, window, in unspecified units. + /// Platform specific. + /// See `winit::event::DeviceEvent::MouseMotion` + motion: Vec2, + /// Current velocity of pointer. velocity: Vec2, @@ -490,6 +495,7 @@ impl Default for PointerState { latest_pos: None, interact_pos: None, delta: Vec2::ZERO, + motion: Vec2::ZERO, velocity: Vec2::ZERO, pos_history: History::new(0..1000, 0.1), down: Default::default(), @@ -512,6 +518,7 @@ impl PointerState { let old_pos = self.latest_pos; self.interact_pos = self.latest_pos; + self.motion = Vec2::ZERO; for event in &new.events { match event { @@ -597,6 +604,9 @@ impl PointerState { self.latest_pos = None; // NOTE: we do NOT clear `self.interact_pos` here. It will be cleared next frame. } + + Event::MouseDelta(delta) => self.motion += *delta, + _ => {} } } @@ -636,6 +646,13 @@ impl PointerState { self.delta } + /// Mouse delta, in unspecified units. Works when mouse pointer in screen bounds. + /// Currently on winit only. + #[inline(always)] + pub fn motion(&self) -> Vec2 { + self.motion + } + /// Current velocity of pointer. #[inline(always)] pub fn velocity(&self) -> Vec2 { @@ -889,6 +906,7 @@ impl PointerState { latest_pos, interact_pos, delta, + motion, velocity, pos_history: _, down, @@ -903,6 +921,7 @@ impl PointerState { ui.label(format!("latest_pos: {:?}", latest_pos)); ui.label(format!("interact_pos: {:?}", interact_pos)); ui.label(format!("delta: {:?}", delta)); + ui.label(format!("motion: {:?}", motion)); ui.label(format!( "velocity: [{:3.0} {:3.0}] points/sec", velocity.x, velocity.y diff --git a/egui/src/response.rs b/egui/src/response.rs index 57416154f80..c564a5c711d 100644 --- a/egui/src/response.rs +++ b/egui/src/response.rs @@ -277,6 +277,24 @@ impl Response { self.drag_released } + /// Mouse dragged, nevertheless it's stuck on screen's edge or not. + pub fn motion_delta(&self) -> Vec2 { + #[cfg(target_family = "wasm")] + return self.drag_delta(); + + #[cfg(not(target_family = "wasm"))] + { + let res = self.ctx.input().pointer.motion(); + + if res == Vec2::ZERO { + // in a case of touchscreen or whatever + self.drag_delta() + } else { + res + } + } + } + /// If dragged, how many points were we dragged and in what direction? pub fn drag_delta(&self) -> Vec2 { if self.dragged() { diff --git a/egui/src/widgets/drag_value.rs b/egui/src/widgets/drag_value.rs index d81f6d026e9..c7f3d6c22fc 100644 --- a/egui/src/widgets/drag_value.rs +++ b/egui/src/widgets/drag_value.rs @@ -234,7 +234,8 @@ impl<'a> Widget for DragValue<'a> { } else if response.dragged() { ui.output().cursor_icon = CursorIcon::ResizeHorizontal; - let mdelta = response.drag_delta(); + let mdelta = response.motion_delta(); + let delta_points = mdelta.x - mdelta.y; // Increase to the right and up let speed = if is_slow_speed { speed / 10.0 } else { speed }; From 183b134e975f6d2d481c399077e4199c82433f6a Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sat, 21 May 2022 16:59:23 +0300 Subject: [PATCH 2/3] better docs --- egui/src/data/input.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/egui/src/data/input.rs b/egui/src/data/input.rs index 23da2753a08..9063d8b9d5e 100644 --- a/egui/src/data/input.rs +++ b/egui/src/data/input.rs @@ -177,9 +177,9 @@ pub enum Event { /// The mouse or touch moved to a new place. PointerMoved(Pos2), - /// The mouse delta from winit::DeviceEvent. MouseDelta and PointerMoved can be emmited simultaneously. - /// If MouseDelta accumulated value is zero per frame, then `old_pos-new_pos` will be used as fallback. - /// For now it used in situations when we need delta but mouse pointer is on screen edge. + /// Can be used as mouse delta when mouse pointer is on screen edge, like in some CAD systems. + // Currently uses only `winit::DeviceEvent` + /// `MouseDelta` and `PointerMoved` can be emmited simultaneously. MouseDelta(Vec2), /// A mouse button was pressed or released (or a touch started or stopped). From a65acd11ebb44e29281002b1e0b7822582c28a7f Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sat, 21 May 2022 17:49:29 +0300 Subject: [PATCH 3/3] better docs --- egui/src/response.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/egui/src/response.rs b/egui/src/response.rs index c564a5c711d..dae05f20c4a 100644 --- a/egui/src/response.rs +++ b/egui/src/response.rs @@ -278,9 +278,12 @@ impl Response { } /// Mouse dragged, nevertheless it's stuck on screen's edge or not. + /// The idea of this method is to overcome limitations of computing delta from `old-new`, + /// which does not work when mouse is stuck on screen corner. + /// On platform where it is not supported in fallbacks to `pointer.delta()` pub fn motion_delta(&self) -> Vec2 { #[cfg(target_family = "wasm")] - return self.drag_delta(); + return self.ctx.input().pointer.delta(); #[cfg(not(target_family = "wasm"))] { @@ -288,7 +291,7 @@ impl Response { if res == Vec2::ZERO { // in a case of touchscreen or whatever - self.drag_delta() + self.ctx.input().pointer.delta() } else { res }