Skip to content

Commit 3349ecd

Browse files
committed
Improve Frontend -> Backend user input system
Includes refactor that sends coordinates of the document viewports to the backend so input is sent relative to the application window Closes #124
1 parent 7906478 commit 3349ecd

File tree

9 files changed

+259
-119
lines changed

9 files changed

+259
-119
lines changed

editor/src/document/document_file.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
284284
}
285285
CommitTransaction => self.document_backup = None,
286286
ExportDocument => {
287-
let bbox = self.document.visible_layers_bounding_box().unwrap_or([DVec2::ZERO, ipp.viewport_size]);
287+
let bbox = self.document.visible_layers_bounding_box().unwrap_or([DVec2::ZERO, ipp.viewport_bounds.size()]);
288288
let size = bbox[1] - bbox[0];
289289
let name = match self.name.ends_with(FILE_SAVE_SUFFIX) {
290290
true => self.name.clone().replace(FILE_SAVE_SUFFIX, FILE_EXPORT_SUFFIX),

editor/src/document/movement_handler.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::LayerData;
55
use crate::message_prelude::*;
66
use crate::{
77
consts::{VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_WHEEL_RATE},
8-
input::{mouse::ViewportPosition, InputPreprocessor},
8+
input::{mouse::ViewportBounds, mouse::ViewportPosition, InputPreprocessor},
99
};
1010
use glam::DVec2;
1111
use graphene::document::Document;
@@ -42,8 +42,8 @@ pub struct MovementMessageHandler {
4242
}
4343

4444
impl MovementMessageHandler {
45-
fn create_document_transform_from_layerdata(&self, layerdata: &LayerData, viewport_size: &ViewportPosition, responses: &mut VecDeque<Message>) {
46-
let half_viewport = *viewport_size / 2.;
45+
fn create_document_transform_from_layerdata(&self, layerdata: &LayerData, viewport_bounds: &ViewportBounds, responses: &mut VecDeque<Message>) {
46+
let half_viewport = viewport_bounds.size() / 2.;
4747
let scaled_half_viewport = half_viewport / layerdata.scale;
4848
responses.push_back(
4949
DocumentOperation::SetLayerTransform {
@@ -89,10 +89,10 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
8989
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
9090

9191
layerdata.translation += transformed_delta;
92-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
92+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
9393
}
9494
if self.rotating {
95-
let half_viewport = ipp.viewport_size / 2.;
95+
let half_viewport = ipp.viewport_bounds.size() / 2.;
9696
let rotation = {
9797
let start_vec = self.mouse_pos - half_viewport;
9898
let end_vec = ipp.mouse.position - half_viewport;
@@ -109,7 +109,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
109109
}
110110
.into(),
111111
);
112-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
112+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
113113
}
114114
if self.zooming {
115115
let difference = self.mouse_pos.y as f64 - ipp.mouse.position.y as f64;
@@ -118,44 +118,44 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
118118
let new = (layerdata.scale * amount).clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
119119
layerdata.scale = new;
120120
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
121-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
121+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
122122
}
123123
self.mouse_pos = ipp.mouse.position;
124124
}
125125
SetCanvasZoom(new) => {
126126
layerdata.scale = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
127127
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
128-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
128+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
129129
}
130130
IncreaseCanvasZoom => {
131131
layerdata.scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > layerdata.scale).unwrap_or(&layerdata.scale);
132132
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
133-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
133+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
134134
}
135135
DecreaseCanvasZoom => {
136136
layerdata.scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < layerdata.scale).unwrap_or(&layerdata.scale);
137137
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
138-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
138+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
139139
}
140140
WheelCanvasZoom => {
141141
let scroll = ipp.mouse.scroll_delta.scroll_delta();
142142
let mouse = ipp.mouse.position;
143-
let viewport_size = ipp.viewport_size;
143+
let viewport_bounds = ipp.viewport_bounds.size();
144144
let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE;
145145
if ipp.mouse.scroll_delta.y > 0 {
146146
zoom_factor = 1. / zoom_factor
147147
};
148-
let new_viewport_size = viewport_size * (1. / zoom_factor);
149-
let delta_size = viewport_size - new_viewport_size;
150-
let mouse_percent = mouse / viewport_size;
148+
let new_viewport_bounds = viewport_bounds * (1. / zoom_factor);
149+
let delta_size = viewport_bounds - new_viewport_bounds;
150+
let mouse_percent = mouse / viewport_bounds;
151151
let delta = (delta_size * -2.) * (mouse_percent - DVec2::splat(0.5));
152152

153153
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
154154
let new = (layerdata.scale * zoom_factor).clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
155155
layerdata.scale = new;
156156
layerdata.translation += transformed_delta;
157157
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
158-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
158+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
159159
}
160160
WheelCanvasTranslate { use_y_as_x } => {
161161
let delta = match use_y_as_x {
@@ -164,19 +164,19 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
164164
} * VIEWPORT_SCROLL_RATE;
165165
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
166166
layerdata.translation += transformed_delta;
167-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
167+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
168168
}
169169
SetCanvasRotation(new) => {
170170
layerdata.rotation = new;
171-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
171+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
172172
responses.push_back(FrontendMessage::SetCanvasRotation { new_radians: new }.into());
173173
}
174174
ZoomCanvasToFitAll => {
175175
if let Some([pos1, pos2]) = document.visible_layers_bounding_box() {
176176
let pos1 = document.root.transform.inverse().transform_point2(pos1);
177177
let pos2 = document.root.transform.inverse().transform_point2(pos2);
178178
let v1 = document.root.transform.inverse().transform_point2(DVec2::ZERO);
179-
let v2 = document.root.transform.inverse().transform_point2(ipp.viewport_size);
179+
let v2 = document.root.transform.inverse().transform_point2(ipp.viewport_bounds.size());
180180

181181
let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5);
182182
let size = (pos2 - pos1) / (v2 - v1);
@@ -186,7 +186,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
186186
layerdata.translation += center;
187187
layerdata.scale *= new_scale;
188188
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
189-
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_size, responses);
189+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
190190
}
191191
}
192192
}

editor/src/input/input_preprocessor.rs

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::usize;
22

33
use super::keyboard::{Key, KeyStates};
4-
use super::mouse::{MouseKeys, MouseState, ScrollDelta, ViewportPosition};
4+
use super::mouse::{EditorMouseState, MouseKeys, MouseState, ViewportBounds};
55
use crate::message_prelude::*;
66
use bitflags::bitflags;
77

@@ -11,13 +11,13 @@ pub use graphene::DocumentResponse;
1111
#[impl_message(Message, InputPreprocessor)]
1212
#[derive(PartialEq, Clone, Debug)]
1313
pub enum InputPreprocessorMessage {
14-
MouseDown(MouseState, ModifierKeys),
15-
MouseUp(MouseState, ModifierKeys),
16-
MouseMove(ViewportPosition, ModifierKeys),
17-
MouseScroll(ScrollDelta, ModifierKeys),
14+
MouseDown(EditorMouseState, ModifierKeys),
15+
MouseUp(EditorMouseState, ModifierKeys),
16+
MouseMove(EditorMouseState, ModifierKeys),
17+
MouseScroll(EditorMouseState, ModifierKeys),
1818
KeyUp(Key, ModifierKeys),
1919
KeyDown(Key, ModifierKeys),
20-
ViewportResize(ViewportPosition),
20+
BoundsOfViewports(Vec<ViewportBounds>),
2121
}
2222

2323
bitflags! {
@@ -34,7 +34,7 @@ bitflags! {
3434
pub struct InputPreprocessor {
3535
pub keyboard: KeyStates,
3636
pub mouse: MouseState,
37-
pub viewport_size: ViewportPosition,
37+
pub viewport_bounds: ViewportBounds,
3838
}
3939

4040
enum KeyPosition {
@@ -45,28 +45,43 @@ enum KeyPosition {
4545
impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessor {
4646
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
4747
match message {
48-
InputPreprocessorMessage::MouseMove(pos, modifier_keys) => {
48+
InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys) => {
4949
self.handle_modifier_keys(modifier_keys, responses);
50-
self.mouse.position = pos;
50+
51+
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
52+
self.mouse.position = mouse_state.position;
53+
5154
responses.push_back(InputMapperMessage::PointerMove.into());
5255
}
53-
InputPreprocessorMessage::MouseScroll(delta, modifier_keys) => {
54-
self.handle_modifier_keys(modifier_keys, responses);
55-
self.mouse.scroll_delta = delta;
56-
responses.push_back(InputMapperMessage::MouseScroll.into());
57-
}
58-
InputPreprocessorMessage::MouseDown(state, modifier_keys) => {
56+
InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys) => {
5957
self.handle_modifier_keys(modifier_keys, responses);
60-
if let Some(message) = self.translate_mouse_event(state, KeyPosition::Pressed) {
58+
59+
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
60+
self.mouse.position = mouse_state.position;
61+
62+
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Pressed) {
6163
responses.push_back(message);
6264
}
6365
}
64-
InputPreprocessorMessage::MouseUp(state, modifier_keys) => {
66+
InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys) => {
6567
self.handle_modifier_keys(modifier_keys, responses);
66-
if let Some(message) = self.translate_mouse_event(state, KeyPosition::Released) {
68+
69+
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
70+
self.mouse.position = mouse_state.position;
71+
72+
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Released) {
6773
responses.push_back(message);
6874
}
6975
}
76+
InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys) => {
77+
self.handle_modifier_keys(modifier_keys, responses);
78+
79+
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
80+
self.mouse.position = mouse_state.position;
81+
self.mouse.scroll_delta = mouse_state.scroll_delta;
82+
83+
responses.push_back(InputMapperMessage::MouseScroll.into());
84+
}
7085
InputPreprocessorMessage::KeyDown(key, modifier_keys) => {
7186
self.handle_modifier_keys(modifier_keys, responses);
7287
self.keyboard.set(key as usize);
@@ -77,15 +92,24 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessor {
7792
self.keyboard.unset(key as usize);
7893
responses.push_back(InputMapperMessage::KeyUp(key).into());
7994
}
80-
InputPreprocessorMessage::ViewportResize(size) => {
81-
responses.push_back(
82-
graphene::Operation::TransformLayer {
83-
path: vec![],
84-
transform: glam::DAffine2::from_translation((size - self.viewport_size) / 2.).to_cols_array(),
85-
}
86-
.into(),
87-
);
88-
self.viewport_size = size;
95+
InputPreprocessorMessage::BoundsOfViewports(bounds_of_viewports) => {
96+
for bounds in bounds_of_viewports {
97+
let new_size = bounds.size();
98+
let existing_size = self.viewport_bounds.size();
99+
100+
let translation = (new_size - existing_size) / 2.;
101+
102+
// TODO: Extend this to multiple viewports instead of setting it to the value of this last loop iteration
103+
self.viewport_bounds = bounds;
104+
105+
responses.push_back(
106+
graphene::Operation::TransformLayer {
107+
path: vec![],
108+
transform: glam::DAffine2::from_translation(translation).to_cols_array(),
109+
}
110+
.into(),
111+
);
112+
}
89113
}
90114
};
91115
}
@@ -136,12 +160,16 @@ impl InputPreprocessor {
136160

137161
#[cfg(test)]
138162
mod test {
163+
use crate::input::mouse::ViewportPosition;
164+
139165
use super::*;
140166

141167
#[test]
142168
fn process_action_mouse_move_handle_modifier_keys() {
143169
let mut input_preprocessor = InputPreprocessor::default();
144-
let message = InputPreprocessorMessage::MouseMove((4., 809.).into(), ModifierKeys::ALT);
170+
let mut editor_mouse_state = EditorMouseState::new();
171+
editor_mouse_state.editor_position = ViewportPosition::new(4., 809.);
172+
let message = InputPreprocessorMessage::MouseMove(editor_mouse_state, ModifierKeys::ALT);
145173
let mut responses = VecDeque::new();
146174

147175
input_preprocessor.process_action(message, (), &mut responses);
@@ -153,7 +181,7 @@ mod test {
153181
#[test]
154182
fn process_action_mouse_down_handle_modifier_keys() {
155183
let mut input_preprocessor = InputPreprocessor::default();
156-
let message = InputPreprocessorMessage::MouseDown(MouseState::new(), ModifierKeys::CONTROL);
184+
let message = InputPreprocessorMessage::MouseDown(EditorMouseState::new(), ModifierKeys::CONTROL);
157185
let mut responses = VecDeque::new();
158186

159187
input_preprocessor.process_action(message, (), &mut responses);
@@ -165,7 +193,7 @@ mod test {
165193
#[test]
166194
fn process_action_mouse_up_handle_modifier_keys() {
167195
let mut input_preprocessor = InputPreprocessor::default();
168-
let message = InputPreprocessorMessage::MouseUp(MouseState::new(), ModifierKeys::SHIFT);
196+
let message = InputPreprocessorMessage::MouseUp(EditorMouseState::new(), ModifierKeys::SHIFT);
169197
let mut responses = VecDeque::new();
170198

171199
input_preprocessor.process_action(message, (), &mut responses);

editor/src/input/mouse.rs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@ use glam::DVec2;
33

44
// Origin is top left
55
pub type ViewportPosition = DVec2;
6+
pub type EditorPosition = DVec2;
7+
8+
#[derive(PartialEq, Clone, Debug, Default)]
9+
pub struct ViewportBounds {
10+
pub top_left: DVec2,
11+
pub bottom_right: DVec2,
12+
}
13+
14+
impl ViewportBounds {
15+
pub fn from_slice(slice: &[f64]) -> Self {
16+
Self {
17+
top_left: DVec2::from_slice(&slice[0..2]),
18+
bottom_right: DVec2::from_slice(&slice[2..4]),
19+
}
20+
}
21+
22+
pub fn size(&self) -> DVec2 {
23+
DVec2::new(self.bottom_right.x - self.top_left.x, self.bottom_right.y - self.top_left.y)
24+
}
25+
}
626

727
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
828
pub struct ScrollDelta {
@@ -35,15 +55,15 @@ impl MouseState {
3555
Self::default()
3656
}
3757

38-
pub fn from_pos(x: f64, y: f64) -> Self {
58+
pub fn from_position(x: f64, y: f64) -> Self {
3959
Self {
4060
position: (x, y).into(),
4161
mouse_keys: MouseKeys::default(),
4262
scroll_delta: ScrollDelta::default(),
4363
}
4464
}
4565

46-
pub fn from_u8_pos(keys: u8, position: ViewportPosition) -> Self {
66+
pub fn from_keys_and_editor_position(keys: u8, position: ViewportPosition) -> Self {
4767
let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys");
4868
Self {
4969
position,
@@ -52,6 +72,45 @@ impl MouseState {
5272
}
5373
}
5474
}
75+
76+
#[derive(Debug, Copy, Clone, Default, PartialEq)]
77+
pub struct EditorMouseState {
78+
pub editor_position: EditorPosition,
79+
pub mouse_keys: MouseKeys,
80+
pub scroll_delta: ScrollDelta,
81+
}
82+
83+
impl EditorMouseState {
84+
pub fn new() -> Self {
85+
Self::default()
86+
}
87+
88+
pub fn from_editor_position(x: f64, y: f64) -> Self {
89+
Self {
90+
editor_position: (x, y).into(),
91+
mouse_keys: MouseKeys::default(),
92+
scroll_delta: ScrollDelta::default(),
93+
}
94+
}
95+
96+
pub fn from_keys_and_editor_position(keys: u8, editor_position: EditorPosition) -> Self {
97+
let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys");
98+
Self {
99+
editor_position,
100+
mouse_keys,
101+
scroll_delta: ScrollDelta::default(),
102+
}
103+
}
104+
105+
pub fn to_mouse_state(&self, active_viewport_bounds: &ViewportBounds) -> MouseState {
106+
MouseState {
107+
position: self.editor_position - active_viewport_bounds.top_left,
108+
mouse_keys: self.mouse_keys,
109+
scroll_delta: self.scroll_delta,
110+
}
111+
}
112+
}
113+
55114
bitflags! {
56115
#[derive(Default)]
57116
#[repr(transparent)]

0 commit comments

Comments
 (0)