From 8326fffdb0b45a3e57e67671207fcbf30cce1b49 Mon Sep 17 00:00:00 2001 From: YgorSouza <43298013+YgorSouza@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:44:26 +0200 Subject: [PATCH] Add raw mouse wheel event (#2782) * Add raw mouse wheel event The event is sent as it comes from the backend, so it will follow different conventions depending on the target, and it is up to the user code to deal with that. The goal is to allow advanced users to implement alternative UI controls, e.g., using Ctrl to scroll the plot horizontally instead of zooming, or use Shift to scroll faster instead of changing direction. * Change Pixel to Point for consistency Apply suggestions from code review by emilk Co-authored-by: Emil Ernerfeldt * Inline mouse wheel raw event closure It was meant only to be able to use the same variable names without shadowing the rest of the code, but a simple block accomplishes the same thing. * Use wildcard on wheel event match Co-authored-by: Emil Ernerfeldt * Flip mouse wheel delta sign on web to match native * Use wheel event data to generate scroll event To avoid doing the same match and sign conversion twice. --------- Co-authored-by: Emil Ernerfeldt --- crates/eframe/src/web/events.rs | 29 +++++++++++++++++++++-------- crates/egui-winit/src/lib.rs | 20 ++++++++++++++++++++ crates/egui/src/data/input.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index 5489d72af..3208ffe44 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -448,20 +448,33 @@ pub fn install_canvas_events(runner_container: &mut AppRunnerContainer) -> Resul &canvas, "wheel", |event: web_sys::WheelEvent, mut runner_lock| { - let scroll_multiplier = match event.delta_mode() { - web_sys::WheelEvent::DOM_DELTA_PAGE => { - canvas_size_in_points(runner_lock.canvas_id()).y - } - web_sys::WheelEvent::DOM_DELTA_LINE => { + let unit = match event.delta_mode() { + web_sys::WheelEvent::DOM_DELTA_PIXEL => egui::MouseWheelUnit::Point, + web_sys::WheelEvent::DOM_DELTA_LINE => egui::MouseWheelUnit::Line, + web_sys::WheelEvent::DOM_DELTA_PAGE => egui::MouseWheelUnit::Page, + _ => return, + }; + // delta sign is flipped to match native (winit) convention. + let delta = -egui::vec2(event.delta_x() as f32, event.delta_y() as f32); + let modifiers = runner_lock.input.raw.modifiers; + + runner_lock.input.raw.events.push(egui::Event::MouseWheel { + unit, + delta, + modifiers, + }); + + let scroll_multiplier = match unit { + egui::MouseWheelUnit::Page => canvas_size_in_points(runner_lock.canvas_id()).y, + egui::MouseWheelUnit::Line => { #[allow(clippy::let_and_return)] let points_per_scroll_line = 8.0; // Note that this is intentionally different from what we use in winit. points_per_scroll_line } - _ => 1.0, // DOM_DELTA_PIXEL + egui::MouseWheelUnit::Point => 1.0, }; - let mut delta = - -scroll_multiplier * egui::vec2(event.delta_x() as f32, event.delta_y() as f32); + let mut delta = scroll_multiplier * delta; // Report a zoom event in case CTRL (on Windows or Linux) or CMD (on Mac) is pressed. // This if-statement is equivalent to how `Modifiers.command` is determined in diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 9e9d79207..157ee9035 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -548,6 +548,26 @@ impl State { } fn on_mouse_wheel(&mut self, delta: winit::event::MouseScrollDelta) { + { + let (unit, delta) = match delta { + winit::event::MouseScrollDelta::LineDelta(x, y) => { + (egui::MouseWheelUnit::Line, egui::vec2(x, y)) + } + winit::event::MouseScrollDelta::PixelDelta(winit::dpi::PhysicalPosition { + x, + y, + }) => ( + egui::MouseWheelUnit::Point, + egui::vec2(x as f32, y as f32) / self.pixels_per_point(), + ), + }; + let modifiers = self.egui_input.modifiers; + self.egui_input.events.push(egui::Event::MouseWheel { + unit, + delta, + modifiers, + }); + } let delta = match delta { winit::event::MouseScrollDelta::LineDelta(x, y) => { let points_per_scroll_line = 50.0; // Scroll speed decided by consensus: https://github.com/emilk/egui/issues/461 diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 30dab6760..67c1853a4 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -278,6 +278,22 @@ pub enum Event { force: f32, }, + /// A raw mouse wheel event as sent by the backend (minus the z coordinate), + /// for implementing alternative custom controls. + /// Note that the same event can also trigger [`Self::Zoom`] and [`Self::Scroll`], + /// so you probably want to handle only one of them. + MouseWheel { + /// The unit of scrolling: points, lines, or pages. + unit: MouseWheelUnit, + + /// The amount scrolled horizontally and vertically. The amount and direction corresponding + /// to one step of the wheel depends on the platform. + delta: Vec2, + + /// The state of the modifier keys at the time of the event. + modifiers: Modifiers, + }, + /// An assistive technology (e.g. screen reader) requested an action. #[cfg(feature = "accesskit")] AccessKitActionRequest(accesskit::ActionRequest), @@ -891,6 +907,20 @@ pub enum TouchPhase { Cancel, } +/// The unit associated with the numeric value of a mouse wheel event +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum MouseWheelUnit { + /// Number of ui points (logical pixels) + Point, + + /// Number of lines + Line, + + /// Number of pages + Page, +} + impl From for TouchId { fn from(id: u64) -> Self { Self(id)