diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index d85adaa3a5e..99d2ef14369 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -402,20 +402,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 5ae22a4335e..0c9a9c71635 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -549,6 +549,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 30dab6760d2..67c1853a489 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)