Browse Source

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 <emil.ernerfeldt@gmail.com>

* 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 <emil.ernerfeldt@gmail.com>

* 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 <emil.ernerfeldt@gmail.com>
pull/2905/head
YgorSouza 2 years ago
committed by GitHub
parent
commit
8326fffdb0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      crates/eframe/src/web/events.rs
  2. 20
      crates/egui-winit/src/lib.rs
  3. 30
      crates/egui/src/data/input.rs

29
crates/eframe/src/web/events.rs

@ -448,20 +448,33 @@ pub fn install_canvas_events(runner_container: &mut AppRunnerContainer) -> Resul
&canvas, &canvas,
"wheel", "wheel",
|event: web_sys::WheelEvent, mut runner_lock| { |event: web_sys::WheelEvent, mut runner_lock| {
let scroll_multiplier = match event.delta_mode() { let unit = match event.delta_mode() {
web_sys::WheelEvent::DOM_DELTA_PAGE => { web_sys::WheelEvent::DOM_DELTA_PIXEL => egui::MouseWheelUnit::Point,
canvas_size_in_points(runner_lock.canvas_id()).y web_sys::WheelEvent::DOM_DELTA_LINE => egui::MouseWheelUnit::Line,
} web_sys::WheelEvent::DOM_DELTA_PAGE => egui::MouseWheelUnit::Page,
web_sys::WheelEvent::DOM_DELTA_LINE => { _ => 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)] #[allow(clippy::let_and_return)]
let points_per_scroll_line = 8.0; // Note that this is intentionally different from what we use in winit. let points_per_scroll_line = 8.0; // Note that this is intentionally different from what we use in winit.
points_per_scroll_line points_per_scroll_line
} }
_ => 1.0, // DOM_DELTA_PIXEL egui::MouseWheelUnit::Point => 1.0,
}; };
let mut delta = let mut delta = scroll_multiplier * delta;
-scroll_multiplier * egui::vec2(event.delta_x() as f32, event.delta_y() as f32);
// Report a zoom event in case CTRL (on Windows or Linux) or CMD (on Mac) is pressed. // 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 // This if-statement is equivalent to how `Modifiers.command` is determined in

20
crates/egui-winit/src/lib.rs

@ -548,6 +548,26 @@ impl State {
} }
fn on_mouse_wheel(&mut self, delta: winit::event::MouseScrollDelta) { 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 { let delta = match delta {
winit::event::MouseScrollDelta::LineDelta(x, y) => { 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 let points_per_scroll_line = 50.0; // Scroll speed decided by consensus: https://github.com/emilk/egui/issues/461

30
crates/egui/src/data/input.rs

@ -278,6 +278,22 @@ pub enum Event {
force: f32, 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. /// An assistive technology (e.g. screen reader) requested an action.
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
AccessKitActionRequest(accesskit::ActionRequest), AccessKitActionRequest(accesskit::ActionRequest),
@ -891,6 +907,20 @@ pub enum TouchPhase {
Cancel, 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<u64> for TouchId { impl From<u64> for TouchId {
fn from(id: u64) -> Self { fn from(id: u64) -> Self {
Self(id) Self(id)

Loading…
Cancel
Save