From 449729f1e1a2c0f45d24df1ac9a469f6eded9018 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Mon, 3 Jun 2024 01:09:22 -0700 Subject: [PATCH] Fix crash and clean up frontend -> backend input handling code (#1770) --- .../input_mapper/utility_types/input_mouse.rs | 82 ++++++++----------- .../input_preprocessor_message_handler.rs | 12 ++- .../navigation/navigation_message_handler.rs | 2 +- editor/src/test_utils.rs | 2 +- frontend/wasm/src/editor_api.rs | 2 +- 5 files changed, 47 insertions(+), 53 deletions(-) diff --git a/editor/src/messages/input_mapper/utility_types/input_mouse.rs b/editor/src/messages/input_mapper/utility_types/input_mouse.rs index ce15dea9..62229305 100644 --- a/editor/src/messages/input_mapper/utility_types/input_mouse.rs +++ b/editor/src/messages/input_mapper/utility_types/input_mouse.rs @@ -3,7 +3,6 @@ use crate::messages::prelude::*; use bitflags::bitflags; use glam::DVec2; - use std::collections::VecDeque; // Origin is top left @@ -37,16 +36,35 @@ impl ViewportBounds { } } -#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] +use std::hash::{Hash, Hasher}; + +#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize)] pub struct ScrollDelta { - // TODO: Switch these to `f64` values (not trivial because floats don't provide PartialEq, Eq, and Hash) - pub x: i32, - pub y: i32, - pub z: i32, + pub x: f64, + pub y: f64, + pub z: f64, +} + +impl PartialEq for ScrollDelta { + fn eq(&self, other: &Self) -> bool { + self.x == other.x && self.y == other.y && self.z == other.z + } +} + +impl Eq for ScrollDelta {} + +impl Hash for ScrollDelta { + fn hash(&self, state: &mut H) { + let no_negative_zero = |value: f64| if value == 0. { 0. } else { value }; + + no_negative_zero(self.x).to_bits().hash(state); + no_negative_zero(self.y).to_bits().hash(state); + no_negative_zero(self.z).to_bits().hash(state); + } } impl ScrollDelta { - pub fn new(x: i32, y: i32, z: i32) -> Self { + pub fn new(x: f64, y: f64, z: f64) -> Self { Self { x, y, z } } @@ -56,10 +74,11 @@ impl ScrollDelta { pub fn scroll_delta(&self) -> f64 { let (dx, dy) = (self.x, self.y); - dy.signum() as f64 * ((dy * dy + i32::min(dy.abs(), dx.abs()).pow(2)) as f64).sqrt() + dy.signum() as f64 * ((dy * dy + f64::min(dy.abs(), dx.abs()).powi(2)) as f64).sqrt() } } +// TODO: Document the difference between this and EditorMouseState #[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] pub struct MouseState { pub position: ViewportPosition, @@ -68,28 +87,6 @@ pub struct MouseState { } impl MouseState { - pub fn new() -> Self { - Self::default() - } - - pub fn from_position(x: f64, y: f64) -> Self { - Self { - position: (x, y).into(), - mouse_keys: MouseKeys::default(), - scroll_delta: ScrollDelta::default(), - } - } - - pub fn from_keys_and_editor_position(keys: u8, position: ViewportPosition) -> Self { - let mouse_keys = MouseKeys::from_bits(keys).expect("Invalid modifier keys"); - - Self { - position, - mouse_keys, - scroll_delta: ScrollDelta::default(), - } - } - pub fn finish_transaction(&self, drag_start: DVec2, responses: &mut VecDeque) { match drag_start.distance(self.position) <= DRAG_THRESHOLD { true => responses.add(DocumentMessage::AbortTransaction), @@ -98,6 +95,7 @@ impl MouseState { } } +// TODO: Document the difference between this and MouseState #[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] pub struct EditorMouseState { pub editor_position: EditorPosition, @@ -106,20 +104,8 @@ pub struct EditorMouseState { } impl EditorMouseState { - pub fn new() -> Self { - Self::default() - } - - pub fn from_editor_position(x: f64, y: f64) -> Self { - Self { - editor_position: (x, y).into(), - mouse_keys: MouseKeys::default(), - scroll_delta: ScrollDelta::default(), - } - } - pub fn from_keys_and_editor_position(keys: u8, editor_position: EditorPosition) -> Self { - let mouse_keys = MouseKeys::from_bits(keys).expect("Invalid modifier keys"); + let mouse_keys = MouseKeys::from_bits(keys).expect("Invalid decoding of MouseKeys"); Self { editor_position, @@ -138,12 +124,16 @@ impl EditorMouseState { } bitflags! { + /// Based on . #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[repr(transparent)] pub struct MouseKeys: u8 { - const LEFT = 0b0000_0001; - const RIGHT = 0b0000_0010; - const MIDDLE = 0b0000_0100; + const NONE = 0b0000_0000; + const LEFT = 0b0000_0001; + const RIGHT = 0b0000_0010; + const MIDDLE = 0b0000_0100; + const BACK = 0b0000_1000; + const FORWARD = 0b0001_0000; } } diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs index 3742636b..2da166bf 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -181,7 +181,7 @@ impl InputPreprocessorMessageHandler { #[cfg(test)] mod test { use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys}; - use crate::messages::input_mapper::utility_types::input_mouse::EditorMouseState; + use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta}; use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; use crate::messages::prelude::*; @@ -189,7 +189,11 @@ mod test { fn process_action_mouse_move_handle_modifier_keys() { let mut input_preprocessor = InputPreprocessorMessageHandler::default(); - let editor_mouse_state = EditorMouseState::from_editor_position(4., 809.); + let editor_mouse_state = EditorMouseState { + editor_position: (4., 809.).into(), + mouse_keys: MouseKeys::default(), + scroll_delta: ScrollDelta::default(), + }; let modifier_keys = ModifierKeys::ALT; let message = InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }; @@ -208,7 +212,7 @@ mod test { fn process_action_mouse_down_handle_modifier_keys() { let mut input_preprocessor = InputPreprocessorMessageHandler::default(); - let editor_mouse_state = EditorMouseState::new(); + let editor_mouse_state = EditorMouseState::default(); let modifier_keys = ModifierKeys::CONTROL; let message = InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys }; @@ -227,7 +231,7 @@ mod test { fn process_action_mouse_up_handle_modifier_keys() { let mut input_preprocessor = InputPreprocessorMessageHandler::default(); - let editor_mouse_state = EditorMouseState::new(); + let editor_mouse_state = EditorMouseState::default(); let modifier_keys = ModifierKeys::SHIFT; let message = InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys }; diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index e240a115..f26c78c0 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -145,7 +145,7 @@ impl MessageHandler> for Navigation NavigationMessage::CanvasZoomMouseWheel => { let scroll = ipp.mouse.scroll_delta.scroll_delta(); let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE; - if ipp.mouse.scroll_delta.y > 0 { + if ipp.mouse.scroll_delta.y > 0. { zoom_factor = 1. / zoom_factor } zoom_factor *= Self::clamp_zoom(ptz.zoom * zoom_factor, document_bounds, old_zoom, ipp); diff --git a/editor/src/test_utils.rs b/editor/src/test_utils.rs index a00cee7f..b85ee297 100644 --- a/editor/src/test_utils.rs +++ b/editor/src/test_utils.rs @@ -73,7 +73,7 @@ impl EditorTestUtils for Editor { } fn move_mouse(&mut self, x: f64, y: f64) { - let mut editor_mouse_state = EditorMouseState::new(); + let mut editor_mouse_state = EditorMouseState::default(); editor_mouse_state.editor_position = ViewportPosition::new(x, y); let modifier_keys = ModifierKeys::default(); self.input(InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }); diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index e2b63b9c..fdef25e4 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -355,7 +355,7 @@ impl EditorHandle { /// Mouse scrolling within the screenspace bounds of the viewport #[wasm_bindgen(js_name = onWheelScroll)] - pub fn on_wheel_scroll(&self, x: f64, y: f64, mouse_keys: u8, wheel_delta_x: i32, wheel_delta_y: i32, wheel_delta_z: i32, modifiers: u8) { + pub fn on_wheel_scroll(&self, x: f64, y: f64, mouse_keys: u8, wheel_delta_x: f64, wheel_delta_y: f64, wheel_delta_z: f64, modifiers: u8) { let mut editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); editor_mouse_state.scroll_delta = ScrollDelta::new(wheel_delta_x, wheel_delta_y, wheel_delta_z);