From d7e4fcda801aea7d455d1f281afc520375c97879 Mon Sep 17 00:00:00 2001 From: Reinis Mazeiks Date: Thu, 12 May 2022 10:54:38 +0300 Subject: [PATCH] Implement idiomatic accessors for WheelData --- examples/{mouse_event.rs => event_mouse.rs} | 0 examples/event_wheel.rs | 39 +++++++++++++ packages/html/src/events.rs | 56 ++++++++++++++++++- packages/html/src/geometry.rs | 61 +++++++++++++++++++++ packages/tui/src/hooks.rs | 20 +++---- 5 files changed, 165 insertions(+), 11 deletions(-) rename examples/{mouse_event.rs => event_mouse.rs} (100%) create mode 100644 examples/event_wheel.rs diff --git a/examples/mouse_event.rs b/examples/event_mouse.rs similarity index 100% rename from examples/mouse_event.rs rename to examples/event_mouse.rs diff --git a/examples/event_wheel.rs b/examples/event_wheel.rs new file mode 100644 index 000000000..763c64d02 --- /dev/null +++ b/examples/event_wheel.rs @@ -0,0 +1,39 @@ +use dioxus::prelude::*; +use dioxus_core::UiEvent; +use dioxus_html::on::WheelData; + +fn main() { + dioxus::desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let delta = use_state(&cx, || "".to_string()); + + let container_style = r#" + display: flex; + flex-direction: column; + align-items: center; + "#; + let rect_style = r#" + background: deepskyblue; + height: 50vh; + width: 50vw; + "#; + + let handle_event = move |event: UiEvent| { + let wheel_data = event.data; + delta.set(format!("{:?}", wheel_data.delta())); + }; + + cx.render(rsx! ( + div { + style: "{container_style}", + "Scroll mouse wheel over rectangle:", + div { + style: "{rect_style}", + onwheel: handle_event, + } + div {"Delta: {delta}"}, + } + )) +} diff --git a/packages/html/src/events.rs b/packages/html/src/events.rs index 6d7cbe06e..38ae75407 100644 --- a/packages/html/src/events.rs +++ b/packages/html/src/events.rs @@ -5,10 +5,14 @@ use dioxus_core::*; pub mod on { //! Input events and associated data - use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint}; + use crate::geometry::{ + ClientPoint, Coordinates, ElementPoint, LinesVector, PagePoint, PagesVector, PixelsVector, + ScreenPoint, WheelDelta, + }; use crate::input_data::{ decode_mouse_button_set, encode_mouse_button_set, MouseButton, MouseButtonSet, }; + use euclid::UnknownUnit; use keyboard_types::Modifiers; use std::collections::HashMap; @@ -740,12 +744,62 @@ pub mod on { #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] pub struct WheelData { + #[deprecated(since = "0.3.0", note = "use delta() instead")] pub delta_mode: u32, + #[deprecated(since = "0.3.0", note = "use delta() instead")] pub delta_x: f64, + #[deprecated(since = "0.3.0", note = "use delta() instead")] pub delta_y: f64, + #[deprecated(since = "0.3.0", note = "use delta() instead")] pub delta_z: f64, } + impl WheelData { + pub fn new(delta: WheelDelta) -> Self { + let (delta_mode, vector) = match delta { + WheelDelta::Pixels(v) => (0, v.cast_unit::()), + WheelDelta::Lines(v) => (1, v.cast_unit::()), + WheelDelta::Pages(v) => (2, v.cast_unit::()), + }; + + #[allow(deprecated)] + WheelData { + delta_mode, + delta_x: vector.x, + delta_y: vector.y, + delta_z: vector.z, + } + } + + pub fn from_web_attributes( + delta_mode: u32, + delta_x: f64, + delta_y: f64, + delta_z: f64, + ) -> Self { + #[allow(deprecated)] + Self { + delta_mode, + delta_x, + delta_y, + delta_z, + } + } + + #[allow(deprecated)] + pub fn delta(&self) -> WheelDelta { + let x = self.delta_x; + let y = self.delta_y; + let z = self.delta_z; + match self.delta_mode { + 0 => WheelDelta::Pixels(PixelsVector::new(x, y, z)), + 1 => WheelDelta::Lines(LinesVector::new(x, y, z)), + 2 => WheelDelta::Pages(PagesVector::new(x, y, z)), + _ => panic!("Invalid delta mode, {:?}", self.delta_mode), + } + } + } + pub type MediaEvent = UiEvent; #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] diff --git a/packages/html/src/geometry.rs b/packages/html/src/geometry.rs index 5a7c8112e..97ab068d3 100644 --- a/packages/html/src/geometry.rs +++ b/packages/html/src/geometry.rs @@ -25,6 +25,67 @@ pub struct PageSpace; /// A point in PageSpace pub type PagePoint = Point2D; +/// A pixel unit: one unit corresponds to 1 pixel +pub struct Pixels; +/// A vector expressed in Pixels +pub type PixelsVector = Vector3D; + +/// A unit in terms of Lines +/// +/// One unit is relative to the size of one line +pub struct Lines; +/// A vector expressed in Lines +pub type LinesVector = Vector3D; + +/// A unit in terms of Screens: +/// +/// One unit is relative to the size of a page +pub struct Pages; +/// A vector expressed in Pages +pub type PagesVector = Vector3D; + +/// A vector representing the amount the mouse wheel was moved +/// +/// This may be expressed in Pixels, Lines or Pages +#[derive(Copy, Clone, Debug)] +pub enum WheelDelta { + /// Movement in Pixels + Pixels(PixelsVector), + /// Movement in Lines + Lines(LinesVector), + /// Movement in Pages + Pages(PagesVector), +} + +impl WheelDelta { + /// Convenience function for constructing a WheelDelta with pixel units + pub fn pixels(x: f64, y: f64, z: f64) -> Self { + WheelDelta::Pixels(PixelsVector::new(x, y, z)) + } + + /// Convenience function for constructing a WheelDelta with line units + pub fn lines(x: f64, y: f64, z: f64) -> Self { + WheelDelta::Lines(LinesVector::new(x, y, z)) + } + + /// Convenience function for constructing a WheelDelta with page units + pub fn pages(x: f64, y: f64, z: f64) -> Self { + WheelDelta::Pages(PagesVector::new(x, y, z)) + } + + pub fn is_zero(&self) -> bool { + self.strip_units() == Vector3D::new(0., 0., 0.) + } + + pub fn strip_units(&self) -> Vector3D { + match self { + WheelDelta::Pixels(v) => v.cast_unit(), + WheelDelta::Lines(v) => v.cast_unit(), + WheelDelta::Pages(v) => v.cast_unit(), + } + } +} + /// Coordinates of a point in the app's interface pub struct Coordinates { screen: ScreenPoint, diff --git a/packages/tui/src/hooks.rs b/packages/tui/src/hooks.rs index 5481d6b1c..bb32c1375 100644 --- a/packages/tui/src/hooks.rs +++ b/packages/tui/src/hooks.rs @@ -5,7 +5,9 @@ use dioxus_core::*; use fxhash::{FxHashMap, FxHashSet}; use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D}; -use dioxus_html::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint}; +use dioxus_html::geometry::{ + ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint, WheelDelta, +}; use dioxus_html::input_data::keyboard_types::Modifiers; use dioxus_html::input_data::MouseButtonSet as DioxusMouseButtons; use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet}; @@ -248,7 +250,10 @@ impl InnerInputState { // a mouse button is released if a button was down and is now not down let was_released = !(previous_buttons - mouse_data.held_buttons()).is_empty(); - let wheel_delta = self.wheel.as_ref().map_or(0.0, |w| w.delta_y); + let was_scrolled = self + .wheel + .as_ref() + .map_or(false, |data| !data.delta().is_zero()); let wheel_data = &self.wheel; { @@ -412,7 +417,7 @@ impl InnerInputState { { // wheel if let Some(w) = wheel_data { - if wheel_delta != 0.0 { + if was_scrolled { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("wheel") { let node_layout = @@ -638,13 +643,8 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> { }; let get_wheel_data = |up| { - // from https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent - EventData::Wheel(WheelData { - delta_mode: 0x01, - delta_x: 0.0, - delta_y: if up { -1.0 } else { 1.0 }, - delta_z: 0.0, - }) + let y = if up { -1.0 } else { 1.0 }; + EventData::Wheel(WheelData::new(WheelDelta::lines(0., y, 0.))) }; match m.kind {