Skip to content

Commit 881ec0b

Browse files
Split out viewport handling into its own message handler (#3331)
* extract viewport handeling * fix web overlays * some cleanup * remove some physical conversions * fix resize snapping * fixup * apply some review feedback * make viewport api more ergonomic * fix * fix web overlay canvas clear size * clear workaround for canvas * rename trigger message --------- Co-authored-by: Dennis Kobert <dennis@kobert.dev>
1 parent 3490111 commit 881ec0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1326
-607
lines changed

editor/src/dispatcher.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct DispatcherMessageHandlers {
2626
pub portfolio_message_handler: PortfolioMessageHandler,
2727
preferences_message_handler: PreferencesMessageHandler,
2828
tool_message_handler: ToolMessageHandler,
29+
viewport_message_handler: ViewportMessageHandler,
2930
}
3031

3132
impl DispatcherMessageHandlers {
@@ -146,7 +147,6 @@ impl Dispatcher {
146147
let context = DialogMessageContext {
147148
portfolio: &self.message_handlers.portfolio_message_handler,
148149
preferences: &self.message_handlers.preferences_message_handler,
149-
viewport_bounds: &self.message_handlers.input_preprocessor_message_handler.viewport_bounds,
150150
};
151151
self.message_handlers.dialog_message_handler.process_message(message, &mut queue, context);
152152
}
@@ -169,9 +169,14 @@ impl Dispatcher {
169169
Message::InputPreprocessor(message) => {
170170
let keyboard_platform = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
171171

172-
self.message_handlers
173-
.input_preprocessor_message_handler
174-
.process_message(message, &mut queue, InputPreprocessorMessageContext { keyboard_platform });
172+
self.message_handlers.input_preprocessor_message_handler.process_message(
173+
message,
174+
&mut queue,
175+
InputPreprocessorMessageContext {
176+
keyboard_platform,
177+
viewport: &self.message_handlers.viewport_message_handler,
178+
},
179+
);
175180
}
176181
Message::KeyMapping(message) => {
177182
let input = &self.message_handlers.input_preprocessor_message_handler;
@@ -195,6 +200,7 @@ impl Dispatcher {
195200
let reset_node_definitions_on_open = self.message_handlers.portfolio_message_handler.reset_node_definitions_on_open;
196201
let timing_information = self.message_handlers.animation_message_handler.timing_information();
197202
let animation = &self.message_handlers.animation_message_handler;
203+
let viewport = &self.message_handlers.viewport_message_handler;
198204

199205
self.message_handlers.portfolio_message_handler.process_message(
200206
message,
@@ -207,6 +213,7 @@ impl Dispatcher {
207213
reset_node_definitions_on_open,
208214
timing_information,
209215
animation,
216+
viewport,
210217
},
211218
);
212219
}
@@ -230,10 +237,14 @@ impl Dispatcher {
230237
persistent_data: &self.message_handlers.portfolio_message_handler.persistent_data,
231238
node_graph: &self.message_handlers.portfolio_message_handler.executor,
232239
preferences: &self.message_handlers.preferences_message_handler,
240+
viewport: &self.message_handlers.viewport_message_handler,
233241
};
234242

235243
self.message_handlers.tool_message_handler.process_message(message, &mut queue, context);
236244
}
245+
Message::Viewport(message) => {
246+
self.message_handlers.viewport_message_handler.process_message(message, &mut queue, ());
247+
}
237248
Message::NoOp => {}
238249
Message::Batched { messages } => {
239250
messages.into_iter().for_each(|message| self.handle_message(message, false));

editor/src/messages/dialog/dialog_message_handler.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
use super::new_document_dialog::NewDocumentDialogMessageContext;
21
use super::simple_dialogs::{self, AboutGraphiteDialog, ComingSoonDialog, DemoArtworkDialog, LicensesDialog};
32
use crate::messages::dialog::simple_dialogs::LicensesThirdPartyDialog;
4-
use crate::messages::input_mapper::utility_types::input_mouse::ViewportBounds;
53
use crate::messages::layout::utility_types::widget_prelude::*;
64
use crate::messages::prelude::*;
75

86
#[derive(ExtractField)]
97
pub struct DialogMessageContext<'a> {
108
pub portfolio: &'a PortfolioMessageHandler,
11-
pub viewport_bounds: &'a ViewportBounds,
129
pub preferences: &'a PreferencesMessageHandler,
1310
}
1411

@@ -23,15 +20,11 @@ pub struct DialogMessageHandler {
2320
#[message_handler_data]
2421
impl MessageHandler<DialogMessage, DialogMessageContext<'_>> for DialogMessageHandler {
2522
fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque<Message>, context: DialogMessageContext) {
26-
let DialogMessageContext {
27-
portfolio,
28-
preferences,
29-
viewport_bounds,
30-
} = context;
23+
let DialogMessageContext { portfolio, preferences } = context;
3124

3225
match message {
3326
DialogMessage::ExportDialog(message) => self.export_dialog.process_message(message, responses, ExportDialogMessageContext { portfolio }),
34-
DialogMessage::NewDocumentDialog(message) => self.new_document_dialog.process_message(message, responses, NewDocumentDialogMessageContext { viewport_bounds }),
27+
DialogMessage::NewDocumentDialog(message) => self.new_document_dialog.process_message(message, responses, ()),
3528
DialogMessage::PreferencesDialog(message) => self.preferences_dialog.process_message(message, responses, PreferencesDialogMessageContext { preferences }),
3629

3730
DialogMessage::CloseAllDocumentsWithConfirmation => {

editor/src/messages/dialog/new_document_dialog/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ mod new_document_dialog_message_handler;
44
#[doc(inline)]
55
pub use new_document_dialog_message::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant};
66
#[doc(inline)]
7-
pub use new_document_dialog_message_handler::{NewDocumentDialogMessageContext, NewDocumentDialogMessageHandler};
7+
pub use new_document_dialog_message_handler::NewDocumentDialogMessageHandler;

editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1+
use crate::messages::layout::utility_types::widget_prelude::*;
12
use crate::messages::prelude::*;
2-
use crate::messages::{input_mapper::utility_types::input_mouse::ViewportBounds, layout::utility_types::widget_prelude::*};
33
use glam::{IVec2, UVec2};
44
use graph_craft::document::NodeId;
55

6-
#[derive(ExtractField)]
7-
pub struct NewDocumentDialogMessageContext<'a> {
8-
pub viewport_bounds: &'a ViewportBounds,
9-
}
10-
116
/// A dialog to allow users to set some initial options about a new document.
127
#[derive(Debug, Clone, Default, ExtractField)]
138
pub struct NewDocumentDialogMessageHandler {
@@ -17,8 +12,8 @@ pub struct NewDocumentDialogMessageHandler {
1712
}
1813

1914
#[message_handler_data]
20-
impl<'a> MessageHandler<NewDocumentDialogMessage, NewDocumentDialogMessageContext<'a>> for NewDocumentDialogMessageHandler {
21-
fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque<Message>, context: NewDocumentDialogMessageContext<'a>) {
15+
impl<'a> MessageHandler<NewDocumentDialogMessage, ()> for NewDocumentDialogMessageHandler {
16+
fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque<Message>, _: ()) {
2217
match message {
2318
NewDocumentDialogMessage::Name { name } => self.name = name,
2419
NewDocumentDialogMessage::Infinite { infinite } => self.infinite = infinite,
@@ -35,12 +30,9 @@ impl<'a> MessageHandler<NewDocumentDialogMessage, NewDocumentDialogMessageContex
3530
});
3631
responses.add(NavigationMessage::CanvasPan { delta: self.dimensions.as_dvec2() });
3732
responses.add(NodeGraphMessage::RunDocumentGraph);
38-
// If we already have bounds, we won't receive a viewport bounds update so we just fabricate one ourselves
39-
if *context.viewport_bounds != ViewportBounds::default() {
40-
responses.add(InputPreprocessorMessage::BoundsOfViewports {
41-
bounds_of_viewports: vec![context.viewport_bounds.clone()],
42-
});
43-
}
33+
34+
responses.add(ViewportMessage::RepropagateUpdate);
35+
4436
responses.add(DeferMessage::AfterNavigationReady {
4537
messages: vec![DocumentMessage::ZoomCanvasToFitAll.into(), DocumentMessage::DeselectAllLayers.into()],
4638
});

editor/src/messages/frontend/frontend_message.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,12 @@ pub enum FrontendMessage {
350350
UpdateViewportHolePunch {
351351
active: bool,
352352
},
353+
UpdateViewportPhysicalBounds {
354+
x: f64,
355+
y: f64,
356+
width: f64,
357+
height: f64,
358+
},
353359
#[cfg(not(target_family = "wasm"))]
354360
RenderOverlays {
355361
#[serde(skip, default = "OverlayContext::default")]

editor/src/messages/input_mapper/utility_types/input_mouse.rs

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,13 @@ use crate::messages::prelude::*;
33
use bitflags::bitflags;
44
use glam::DVec2;
55
use std::collections::VecDeque;
6+
use std::hash::{Hash, Hasher};
67

78
// Origin is top left
89
pub type DocumentPosition = DVec2;
910
pub type ViewportPosition = DVec2;
1011
pub type EditorPosition = DVec2;
1112

12-
#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
13-
pub struct ViewportBounds {
14-
pub top_left: DVec2,
15-
pub bottom_right: DVec2,
16-
}
17-
18-
impl ViewportBounds {
19-
pub fn from_slice(slice: &[f64]) -> Self {
20-
Self {
21-
top_left: DVec2::from_slice(&slice[0..2]),
22-
bottom_right: DVec2::from_slice(&slice[2..4]),
23-
}
24-
}
25-
26-
pub fn size(&self) -> DVec2 {
27-
(self.bottom_right - self.top_left).ceil()
28-
}
29-
30-
pub fn center(&self) -> DVec2 {
31-
(self.bottom_right - self.top_left).ceil() / 2.
32-
}
33-
34-
pub fn in_bounds(&self, position: ViewportPosition) -> bool {
35-
position.x >= 0. && position.y >= 0. && position.x <= self.bottom_right.x && position.y <= self.bottom_right.y
36-
}
37-
}
38-
39-
use std::hash::{Hash, Hasher};
40-
4113
#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize)]
4214
pub struct ScrollDelta {
4315
pub x: f64,
@@ -113,9 +85,9 @@ impl EditorMouseState {
11385
}
11486
}
11587

116-
pub fn to_mouse_state(&self, active_viewport_bounds: &ViewportBounds) -> MouseState {
88+
pub fn to_mouse_state(&self, viewport: &ViewportMessageHandler) -> MouseState {
11789
MouseState {
118-
position: self.editor_position - active_viewport_bounds.top_left,
90+
position: (viewport.logical(self.editor_position) - viewport.offset()).into(),
11991
mouse_keys: self.mouse_keys,
12092
scroll_delta: self.scroll_delta,
12193
}

editor/src/messages/input_preprocessor/input_preprocessor_message.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
2-
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ViewportBounds};
2+
use crate::messages::input_mapper::utility_types::input_mouse::EditorMouseState;
33
use crate::messages::prelude::*;
44

55
#[impl_message(Message, InputPreprocessor)]
66
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
77
pub enum InputPreprocessorMessage {
8-
BoundsOfViewports { bounds_of_viewports: Vec<ViewportBounds> },
98
DoubleClick { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
109
KeyDown { key: Key, key_repeat: bool, modifier_keys: ModifierKeys },
1110
KeyUp { key: Key, key_repeat: bool, modifier_keys: ModifierKeys },

editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates, ModifierKeys};
2-
use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState, ViewportBounds};
2+
use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState};
33
use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo;
44
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
55
use crate::messages::prelude::*;
6-
use glam::DVec2;
76
use std::time::Duration;
87

98
#[derive(ExtractField)]
10-
pub struct InputPreprocessorMessageContext {
9+
pub struct InputPreprocessorMessageContext<'a> {
1110
pub keyboard_platform: KeyboardPlatformLayout,
11+
pub viewport: &'a ViewportMessageHandler,
1212
}
1313

1414
#[derive(Debug, Default, ExtractField)]
@@ -17,38 +17,18 @@ pub struct InputPreprocessorMessageHandler {
1717
pub time: u64,
1818
pub keyboard: KeyStates,
1919
pub mouse: MouseState,
20-
pub viewport_bounds: ViewportBounds,
2120
}
2221

2322
#[message_handler_data]
24-
impl MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext> for InputPreprocessorMessageHandler {
25-
fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque<Message>, context: InputPreprocessorMessageContext) {
26-
let InputPreprocessorMessageContext { keyboard_platform } = context;
23+
impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext<'a>> for InputPreprocessorMessageHandler {
24+
fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque<Message>, context: InputPreprocessorMessageContext<'a>) {
25+
let InputPreprocessorMessageContext { keyboard_platform, viewport } = context;
2726

2827
match message {
29-
InputPreprocessorMessage::BoundsOfViewports { bounds_of_viewports } => {
30-
assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported");
31-
32-
for bounds in bounds_of_viewports {
33-
// TODO: Extend this to multiple viewports instead of setting it to the value of this last loop iteration
34-
self.viewport_bounds = bounds;
35-
36-
responses.add(NavigationMessage::CanvasPan { delta: DVec2::ZERO });
37-
responses.add(NodeGraphMessage::SetGridAlignedEdges);
38-
}
39-
responses.add(DeferMessage::AfterGraphRun {
40-
messages: vec![
41-
DeferMessage::AfterGraphRun {
42-
messages: vec![DeferMessage::TriggerNavigationReady.into()],
43-
}
44-
.into(),
45-
],
46-
});
47-
}
4828
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => {
4929
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
5030

51-
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
31+
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
5232
self.mouse.position = mouse_state.position;
5333

5434
for key in mouse_state.mouse_keys {
@@ -81,15 +61,15 @@ impl MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext> f
8161
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => {
8262
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
8363

84-
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
64+
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
8565
self.mouse.position = mouse_state.position;
8666

8767
self.translate_mouse_event(mouse_state, true, responses);
8868
}
8969
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
9070
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
9171

92-
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
72+
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
9373
self.mouse.position = mouse_state.position;
9474

9575
responses.add(InputMapperMessage::PointerMove);
@@ -100,15 +80,15 @@ impl MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext> f
10080
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
10181
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
10282

103-
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
83+
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
10484
self.mouse.position = mouse_state.position;
10585

10686
self.translate_mouse_event(mouse_state, false, responses);
10787
}
10888
InputPreprocessorMessage::PointerShake { editor_mouse_state, modifier_keys } => {
10989
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
11090

111-
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
91+
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
11292
self.mouse.position = mouse_state.position;
11393

11494
responses.add(InputMapperMessage::PointerShake);
@@ -121,7 +101,7 @@ impl MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext> f
121101
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
122102
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
123103

124-
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
104+
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
125105
self.mouse.position = mouse_state.position;
126106
self.mouse.scroll_delta = mouse_state.scroll_delta;
127107

@@ -202,11 +182,6 @@ impl InputPreprocessorMessageHandler {
202182
responses.add(InputMapperMessage::KeyDown(key));
203183
}
204184
}
205-
206-
pub fn document_bounds(&self) -> [DVec2; 2] {
207-
// IPP bounds are relative to the entire application
208-
[(0., 0.).into(), self.viewport_bounds.bottom_right - self.viewport_bounds.top_left]
209-
}
210185
}
211186

212187
#[cfg(test)]
@@ -232,6 +207,7 @@ mod test {
232207

233208
let context = InputPreprocessorMessageContext {
234209
keyboard_platform: KeyboardPlatformLayout::Standard,
210+
viewport: &ViewportMessageHandler::default(),
235211
};
236212
input_preprocessor.process_message(message, &mut responses, context);
237213

@@ -251,6 +227,7 @@ mod test {
251227

252228
let context = InputPreprocessorMessageContext {
253229
keyboard_platform: KeyboardPlatformLayout::Standard,
230+
viewport: &ViewportMessageHandler::default(),
254231
};
255232
input_preprocessor.process_message(message, &mut responses, context);
256233

@@ -270,6 +247,7 @@ mod test {
270247

271248
let context = InputPreprocessorMessageContext {
272249
keyboard_platform: KeyboardPlatformLayout::Standard,
250+
viewport: &ViewportMessageHandler::default(),
273251
};
274252
input_preprocessor.process_message(message, &mut responses, context);
275253

@@ -291,6 +269,7 @@ mod test {
291269

292270
let context = InputPreprocessorMessageContext {
293271
keyboard_platform: KeyboardPlatformLayout::Standard,
272+
viewport: &ViewportMessageHandler::default(),
294273
};
295274
input_preprocessor.process_message(message, &mut responses, context);
296275

@@ -311,6 +290,7 @@ mod test {
311290

312291
let context = InputPreprocessorMessageContext {
313292
keyboard_platform: KeyboardPlatformLayout::Standard,
293+
viewport: &ViewportMessageHandler::default(),
314294
};
315295
input_preprocessor.process_message(message, &mut responses, context);
316296

editor/src/messages/message.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub enum Message {
3333
Preferences(PreferencesMessage),
3434
#[child]
3535
Tool(ToolMessage),
36+
#[child]
37+
Viewport(ViewportMessage),
3638

3739
// Messages
3840
Batched {

editor/src/messages/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ pub mod portfolio;
1616
pub mod preferences;
1717
pub mod prelude;
1818
pub mod tool;
19+
pub mod viewport;

0 commit comments

Comments
 (0)