Fix crash and clean up frontend -> backend input handling code (#1770)

This commit is contained in:
Keavon Chambers
2024-06-03 01:09:22 -07:00
committed by GitHub
parent 72ccba09af
commit 449729f1e1
5 changed files with 47 additions and 53 deletions
@@ -3,7 +3,6 @@ use crate::messages::prelude::*;
use bitflags::bitflags; use bitflags::bitflags;
use glam::DVec2; use glam::DVec2;
use std::collections::VecDeque; use std::collections::VecDeque;
// Origin is top left // 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 { pub struct ScrollDelta {
// TODO: Switch these to `f64` values (not trivial because floats don't provide PartialEq, Eq, and Hash) pub x: f64,
pub x: i32, pub y: f64,
pub y: i32, pub z: f64,
pub z: i32, }
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<H: Hasher>(&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 { 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 } Self { x, y, z }
} }
@@ -56,10 +74,11 @@ impl ScrollDelta {
pub fn scroll_delta(&self) -> f64 { pub fn scroll_delta(&self) -> f64 {
let (dx, dy) = (self.x, self.y); 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)] #[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct MouseState { pub struct MouseState {
pub position: ViewportPosition, pub position: ViewportPosition,
@@ -68,28 +87,6 @@ pub struct MouseState {
} }
impl 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<Message>) { pub fn finish_transaction(&self, drag_start: DVec2, responses: &mut VecDeque<Message>) {
match drag_start.distance(self.position) <= DRAG_THRESHOLD { match drag_start.distance(self.position) <= DRAG_THRESHOLD {
true => responses.add(DocumentMessage::AbortTransaction), 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)] #[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct EditorMouseState { pub struct EditorMouseState {
pub editor_position: EditorPosition, pub editor_position: EditorPosition,
@@ -106,20 +104,8 @@ pub struct EditorMouseState {
} }
impl 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 { 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 { Self {
editor_position, editor_position,
@@ -138,12 +124,16 @@ impl EditorMouseState {
} }
bitflags! { bitflags! {
/// Based on <https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons#value>.
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(transparent)] #[repr(transparent)]
pub struct MouseKeys: u8 { pub struct MouseKeys: u8 {
const LEFT = 0b0000_0001; const NONE = 0b0000_0000;
const RIGHT = 0b0000_0010; const LEFT = 0b0000_0001;
const MIDDLE = 0b0000_0100; const RIGHT = 0b0000_0010;
const MIDDLE = 0b0000_0100;
const BACK = 0b0000_1000;
const FORWARD = 0b0001_0000;
} }
} }
@@ -181,7 +181,7 @@ impl InputPreprocessorMessageHandler {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys}; 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::portfolio::utility_types::KeyboardPlatformLayout;
use crate::messages::prelude::*; use crate::messages::prelude::*;
@@ -189,7 +189,11 @@ mod test {
fn process_action_mouse_move_handle_modifier_keys() { fn process_action_mouse_move_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessorMessageHandler::default(); 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 modifier_keys = ModifierKeys::ALT;
let message = InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }; let message = InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys };
@@ -208,7 +212,7 @@ mod test {
fn process_action_mouse_down_handle_modifier_keys() { fn process_action_mouse_down_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessorMessageHandler::default(); let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let editor_mouse_state = EditorMouseState::new(); let editor_mouse_state = EditorMouseState::default();
let modifier_keys = ModifierKeys::CONTROL; let modifier_keys = ModifierKeys::CONTROL;
let message = InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys }; let message = InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys };
@@ -227,7 +231,7 @@ mod test {
fn process_action_mouse_up_handle_modifier_keys() { fn process_action_mouse_up_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessorMessageHandler::default(); let mut input_preprocessor = InputPreprocessorMessageHandler::default();
let editor_mouse_state = EditorMouseState::new(); let editor_mouse_state = EditorMouseState::default();
let modifier_keys = ModifierKeys::SHIFT; let modifier_keys = ModifierKeys::SHIFT;
let message = InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys }; let message = InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys };
@@ -145,7 +145,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageData<'_>> for Navigation
NavigationMessage::CanvasZoomMouseWheel => { NavigationMessage::CanvasZoomMouseWheel => {
let scroll = ipp.mouse.scroll_delta.scroll_delta(); let scroll = ipp.mouse.scroll_delta.scroll_delta();
let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE; 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 = 1. / zoom_factor
} }
zoom_factor *= Self::clamp_zoom(ptz.zoom * zoom_factor, document_bounds, old_zoom, ipp); zoom_factor *= Self::clamp_zoom(ptz.zoom * zoom_factor, document_bounds, old_zoom, ipp);
+1 -1
View File
@@ -73,7 +73,7 @@ impl EditorTestUtils for Editor {
} }
fn move_mouse(&mut self, x: f64, y: f64) { 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); editor_mouse_state.editor_position = ViewportPosition::new(x, y);
let modifier_keys = ModifierKeys::default(); let modifier_keys = ModifierKeys::default();
self.input(InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }); self.input(InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys });
+1 -1
View File
@@ -355,7 +355,7 @@ impl EditorHandle {
/// Mouse scrolling within the screenspace bounds of the viewport /// Mouse scrolling within the screenspace bounds of the viewport
#[wasm_bindgen(js_name = onWheelScroll)] #[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()); 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); editor_mouse_state.scroll_delta = ScrollDelta::new(wheel_delta_x, wheel_delta_y, wheel_delta_z);