Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mouse delta from DeviceEvent #1614

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions eframe/src/native/epi_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down
14 changes: 14 additions & 0 deletions eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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) => {
Expand Down
15 changes: 11 additions & 4 deletions egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#![allow(clippy::manual_range_contains)]

pub use egui;
use egui::Vec2;
pub use winit;

pub mod clipboard;
Expand Down Expand Up @@ -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`].
Expand Down Expand Up @@ -152,6 +160,7 @@ impl State {
}
WindowEvent::CursorMoved { position, .. } => {
self.on_cursor_moved(*position);

egui_ctx.is_using_pointer()
}
WindowEvent::CursorLeft { .. } => {
Expand Down Expand Up @@ -226,10 +235,8 @@ impl State {
};
false
}
_ => {
// dbg!(event);
false
}

_ => false,
}
}

Expand Down
5 changes: 5 additions & 0 deletions egui/src/data/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ pub enum Event {
/// The mouse or touch moved to a new place.
PointerMoved(Pos2),

/// 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),
enomado marked this conversation as resolved.
Show resolved Hide resolved

/// A mouse button was pressed or released (or a touch started or stopped).
PointerButton {
/// Where is the pointer?
Expand Down
19 changes: 19 additions & 0 deletions egui/src/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down Expand Up @@ -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(),
Expand All @@ -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 {
Expand Down Expand Up @@ -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,

_ => {}
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -889,6 +906,7 @@ impl PointerState {
latest_pos,
interact_pos,
delta,
motion,
velocity,
pos_history: _,
down,
Expand All @@ -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
Expand Down
21 changes: 21 additions & 0 deletions egui/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,27 @@ impl Response {
self.drag_released
}

/// 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.ctx.input().pointer.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.ctx.input().pointer.delta()
Comment on lines +293 to +294
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe touch screens should set motion too?

Better yet: RawInput could have motion: Option<Vec2> and then InputState::begin_frame would use it if set, or else fall back to the pointer delta. That way it will work correctly for all existing backends.

} else {
res
}
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not eguis responsibility to have platform-specific code like this. Instead it is up to the integrations to feed egui with the correct input.

In this case the winit backend should feed different data than the web backend. Other integrations needs to do whats right for them.

So if this is called mtion_delta then it should probably use self.ctx.input().pointer.motion() regardless of what the compilation target is.

Also: 'wasm" doesn't mean "web". There are egui users who run egui in wasmtime on desktop.


/// If dragged, how many points were we dragged and in what direction?
pub fn drag_delta(&self) -> Vec2 {
if self.dragged() {
Expand Down
3 changes: 2 additions & 1 deletion egui/src/widgets/drag_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down