From 74e4533ae4b5dd34022cfcb87ce3685ac47ea8a6 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Mon, 28 Jul 2025 12:39:09 +0200 Subject: [PATCH 1/5] Add Handler for defered execution of messages --- editor/src/dispatcher.rs | 44 ++----------------- editor/src/messages/defer/defer_message.rs | 10 +++++ .../messages/defer/defer_message_handler.rs | 34 ++++++++++++++ editor/src/messages/defer/mod.rs | 7 +++ .../new_document_dialog_message_handler.rs | 18 +++++--- .../input_preprocessor_message_handler.rs | 1 + editor/src/messages/message.rs | 7 +-- editor/src/messages/mod.rs | 1 + .../document/document_message_handler.rs | 14 +++--- .../portfolio/portfolio_message_handler.rs | 33 +++++++------- editor/src/messages/prelude.rs | 1 + .../graph_modification_utils.rs | 5 ++- .../messages/tool/tool_messages/brush_tool.rs | 5 ++- .../tool/tool_messages/freehand_tool.rs | 9 ++-- .../messages/tool/tool_messages/pen_tool.rs | 6 +-- .../messages/tool/tool_messages/shape_tool.rs | 14 +++--- .../tool/tool_messages/spline_tool.rs | 2 +- .../messages/tool/tool_messages/text_tool.rs | 33 ++++++++------ editor/src/node_graph_executor.rs | 21 ++++++++- 19 files changed, 158 insertions(+), 107 deletions(-) create mode 100644 editor/src/messages/defer/defer_message.rs create mode 100644 editor/src/messages/defer/defer_message_handler.rs create mode 100644 editor/src/messages/defer/mod.rs diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index 573beb7915..dc910aa487 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -5,7 +5,6 @@ use crate::messages::prelude::*; #[derive(Debug, Default)] pub struct Dispatcher { - buffered_queue: Option>>, message_queues: Vec>, pub responses: Vec, pub message_handlers: DispatcherMessageHandlers, @@ -17,6 +16,7 @@ pub struct DispatcherMessageHandlers { app_window_message_handler: AppWindowMessageHandler, broadcast_message_handler: BroadcastMessageHandler, debug_message_handler: DebugMessageHandler, + defer_message_handler: DeferMessageHandler, dialog_message_handler: DialogMessageHandler, globals_message_handler: GlobalsMessageHandler, input_preprocessor_message_handler: InputPreprocessorMessageHandler, @@ -91,14 +91,6 @@ impl Dispatcher { pub fn handle_message>(&mut self, message: T, process_after_all_current: bool) { let message = message.into(); - // Add all additional messages to the buffer if it exists (except from the end buffer message) - if !matches!(message, Message::EndBuffer { .. }) { - if let Some(buffered_queue) = &mut self.buffered_queue { - Self::schedule_execution(buffered_queue, true, [message]); - - return; - } - } // If we are not maintaining the buffer, simply add to the current queue Self::schedule_execution(&mut self.message_queues, process_after_all_current, [message]); @@ -137,6 +129,9 @@ impl Dispatcher { Message::Debug(message) => { self.message_handlers.debug_message_handler.process_message(message, &mut queue, ()); } + Message::Defer(message) => { + self.message_handlers.defer_message_handler.process_message(message, &mut queue, ()); + } Message::Dialog(message) => { let context = DialogMessageContext { portfolio: &self.message_handlers.portfolio_message_handler, @@ -232,37 +227,6 @@ impl Dispatcher { Message::Batched { messages } => { messages.iter().for_each(|message| self.handle_message(message.to_owned(), false)); } - Message::StartBuffer => { - self.buffered_queue = Some(std::mem::take(&mut self.message_queues)); - } - Message::EndBuffer { render_metadata } => { - // Assign the message queue to the currently buffered queue - if let Some(buffered_queue) = self.buffered_queue.take() { - self.cleanup_queues(false); - assert!(self.message_queues.is_empty(), "message queues are always empty when ending a buffer"); - self.message_queues = buffered_queue; - }; - - let graphene_std::renderer::RenderMetadata { - upstream_footprints: footprints, - local_transforms, - first_instance_source_id, - click_targets, - clip_targets, - } = render_metadata; - - // Run these update state messages immediately - let messages = [ - DocumentMessage::UpdateUpstreamTransforms { - upstream_footprints: footprints, - local_transforms, - first_instance_source_id, - }, - DocumentMessage::UpdateClickTargets { click_targets }, - DocumentMessage::UpdateClipTargets { clip_targets }, - ]; - Self::schedule_execution(&mut self.message_queues, false, messages.map(Message::from)); - } } // If there are child messages, append the queue to the list of queues diff --git a/editor/src/messages/defer/defer_message.rs b/editor/src/messages/defer/defer_message.rs new file mode 100644 index 0000000000..8149886b8c --- /dev/null +++ b/editor/src/messages/defer/defer_message.rs @@ -0,0 +1,10 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, Defer)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum DeferMessage { + TriggerGraphRun, + AfterGraphRun { messages: Vec }, + TriggerViewportResize, + AfterViewportResize { messages: Vec }, +} diff --git a/editor/src/messages/defer/defer_message_handler.rs b/editor/src/messages/defer/defer_message_handler.rs new file mode 100644 index 0000000000..263a21a18b --- /dev/null +++ b/editor/src/messages/defer/defer_message_handler.rs @@ -0,0 +1,34 @@ +use crate::messages::prelude::*; + +#[derive(Debug, Default, ExtractField)] +pub struct DeferMessageHandler { + after_graph_run: Vec, + after_viewport_resize: Vec, +} + +#[message_handler_data] +impl MessageHandler for DeferMessageHandler { + fn process_message(&mut self, message: DeferMessage, responses: &mut VecDeque, _: ()) { + match message { + DeferMessage::AfterGraphRun { messages } => { + self.after_graph_run.extend_from_slice(&messages); + } + DeferMessage::AfterViewportResize { messages } => { + self.after_viewport_resize.extend_from_slice(&messages); + } + DeferMessage::TriggerGraphRun => { + for message in self.after_graph_run.drain(..) { + responses.push_front(message); + } + } + DeferMessage::TriggerViewportResize => { + for message in self.after_viewport_resize.drain(..) { + responses.push_front(message); + } + } + } + } + + advertise_actions!(DeferMessageDiscriminant; + ); +} diff --git a/editor/src/messages/defer/mod.rs b/editor/src/messages/defer/mod.rs new file mode 100644 index 0000000000..819bbf48e2 --- /dev/null +++ b/editor/src/messages/defer/mod.rs @@ -0,0 +1,7 @@ +mod defer_message; +mod defer_message_handler; + +#[doc(inline)] +pub use defer_message::{DeferMessage, DeferMessageDiscriminant}; +#[doc(inline)] +pub use defer_message_handler::DeferMessageHandler; diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs index 6121424de3..07b8687d30 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -24,17 +24,23 @@ impl MessageHandler for NewDocumentDialogMessageHa let create_artboard = !self.infinite && self.dimensions.x > 0 && self.dimensions.y > 0; if create_artboard { - responses.add(Message::StartBuffer); - responses.add(GraphOperationMessage::NewArtboard { - id: NodeId::new(), - artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()), + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![ + GraphOperationMessage::NewArtboard { + id: NodeId::new(), + artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()), + } + .into(), + ], }); } // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated - responses.add(Message::StartBuffer); - responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll); + responses.add(DeferMessage::AfterViewportResize { + messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], + }); responses.add(DocumentMessage::DeselectAllLayers); } } 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 1a8962d974..528f780517 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -34,6 +34,7 @@ impl MessageHandler f self.viewport_bounds = bounds; responses.add(NavigationMessage::CanvasPan { delta: DVec2::ZERO }); + responses.add(DeferMessage::TriggerGraphRun); responses.add(NodeGraphMessage::SetGridAlignedEdges); } } diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs index 975ffac05a..ee441f6bfd 100644 --- a/editor/src/messages/message.rs +++ b/editor/src/messages/message.rs @@ -1,5 +1,4 @@ use crate::messages::prelude::*; -use graphene_std::renderer::RenderMetadata; use graphite_proc_macros::*; #[impl_message] @@ -15,6 +14,8 @@ pub enum Message { #[child] Debug(DebugMessage), #[child] + Defer(DeferMessage), + #[child] Dialog(DialogMessage), #[child] Frontend(FrontendMessage), @@ -40,10 +41,6 @@ pub enum Message { Batched { messages: Box<[Message]>, }, - StartBuffer, - EndBuffer { - render_metadata: RenderMetadata, - }, } /// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`. diff --git a/editor/src/messages/mod.rs b/editor/src/messages/mod.rs index 69a3bc23b0..407864c4cb 100644 --- a/editor/src/messages/mod.rs +++ b/editor/src/messages/mod.rs @@ -4,6 +4,7 @@ pub mod animation; pub mod app_window; pub mod broadcast; pub mod debug; +pub mod defer; pub mod dialog; pub mod frontend; pub mod globals; diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 422d5bb111..d78a711b3f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1866,14 +1866,14 @@ impl DocumentMessageHandler { let previous_network = std::mem::replace(&mut self.network_interface, network_interface); - // Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents - responses.add(PortfolioMessage::UpdateOpenDocumentsList); - responses.add(NodeGraphMessage::SelectedNodesUpdated); - responses.add(NodeGraphMessage::ForceRunDocumentGraph); // TODO: Remove once the footprint is used to load the imports/export distances from the edge - responses.add(NodeGraphMessage::UnloadWires); - responses.add(NodeGraphMessage::SetGridAlignedEdges); - responses.add(Message::StartBuffer); + responses.push_front(NodeGraphMessage::UnloadWires.into()); + responses.push_front(NodeGraphMessage::SetGridAlignedEdges.into()); + + // Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents + responses.push_front(NodeGraphMessage::ForceRunDocumentGraph.into()); + responses.push_front(NodeGraphMessage::SelectedNodesUpdated.into()); + responses.push_front(PortfolioMessage::UpdateOpenDocumentsList.into()); Some(previous_network) } pub fn redo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index ff66ceb7c4..49aa153fb2 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -568,8 +568,9 @@ impl MessageHandler> for Portfolio responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: all_new_ids }); - responses.add(Message::StartBuffer); - responses.add(PortfolioMessage::CenterPastedLayers { layers }); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![PortfolioMessage::CenterPastedLayers { layers }.into()], + }); } } } @@ -701,13 +702,13 @@ impl MessageHandler> for Portfolio if create_document { // Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image - responses.add(Message::StartBuffer); - responses.add(DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()], + }); - // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead - // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated - responses.add(Message::StartBuffer); - responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll); + responses.add(DeferMessage::AfterViewportResize { + messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], + }); } } PortfolioMessage::PasteSvg { @@ -733,13 +734,13 @@ impl MessageHandler> for Portfolio if create_document { // Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image - responses.add(Message::StartBuffer); - responses.add(DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()], + }); - // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead - // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated - responses.add(Message::StartBuffer); - responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll); + responses.add(DeferMessage::AfterViewportResize { + messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], + }); } } PortfolioMessage::PrevDocument => { @@ -1019,9 +1020,7 @@ impl PortfolioMessageHandler { /text>"# // It's a mystery why the `/text>` tag above needs to be missing its `<`, but when it exists it prints the `<` character in the text. However this works with it removed. .to_string(); - responses.add(Message::EndBuffer { - render_metadata: graphene_std::renderer::RenderMetadata::default(), - }); + responses.add(DeferMessage::TriggerGraphRun); responses.add(FrontendMessage::UpdateDocumentArtwork { svg: error }); } result diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs index 45bcbb4ffb..5a01deb7a6 100644 --- a/editor/src/messages/prelude.rs +++ b/editor/src/messages/prelude.rs @@ -6,6 +6,7 @@ pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscrimin pub use crate::messages::app_window::{AppWindowMessage, AppWindowMessageDiscriminant, AppWindowMessageHandler}; pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler}; pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler}; +pub use crate::messages::defer::{DeferMessage, DeferMessageDiscriminant, DeferMessageHandler}; pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDialogMessageContext, ExportDialogMessageDiscriminant, ExportDialogMessageHandler}; pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler}; pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageContext, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler}; diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 191eba0878..7adbe09d36 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -153,8 +153,9 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde }); responses.add(NodeGraphMessage::RunDocumentGraph); - responses.add(Message::StartBuffer); - responses.add(PenToolMessage::RecalculateLatestPointsPosition); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![PenToolMessage::RecalculateLatestPointsPosition.into()], + }); } /// Merge the `first_endpoint` with `second_endpoint`. diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index 76061c12b4..b17a2b1778 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -383,8 +383,9 @@ impl Fsm for BrushToolFsmState { else { new_brush_layer(document, responses); responses.add(NodeGraphMessage::RunDocumentGraph); - responses.add(Message::StartBuffer); - responses.add(BrushToolMessage::DragStart); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![BrushToolMessage::DragStart.into()], + }); BrushToolFsmState::Ready } } diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs index 8b0dbb73f3..8663180f88 100644 --- a/editor/src/messages/tool/tool_messages/freehand_tool.rs +++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs @@ -251,9 +251,12 @@ impl Fsm for FreehandToolFsmState { let nodes = vec![(NodeId(0), node)]; let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses); - responses.add(Message::StartBuffer); - tool_options.fill.apply_fill(layer, responses); - tool_options.stroke.apply_stroke(tool_data.weight, layer, responses); + let defered_responses = &mut VecDeque::new(); + tool_options.fill.apply_fill(layer, defered_responses); + tool_options.stroke.apply_stroke(tool_data.weight, layer, defered_responses); + responses.add(DeferMessage::AfterGraphRun { + messages: defered_responses.drain(..).collect(), + }); tool_data.layer = Some(layer); FreehandToolFsmState::Drawing diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 215c90bdc4..82308fd412 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -1257,10 +1257,10 @@ impl PenToolData { self.prior_segments = None; responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); - // This causes the following message to be run only after the next graph evaluation runs and the transforms are updated - responses.add(Message::StartBuffer); // It is necessary to defer this until the transform of the layer can be accurately computed (quite hacky) - responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport }); + responses.add(DeferMessage::AfterGraphRun { + messages: vec![PenToolMessage::AddPointLayerPosition { layer, viewport }.into()], + }); } /// Perform extension of an existing path diff --git a/editor/src/messages/tool/tool_messages/shape_tool.rs b/editor/src/messages/tool/tool_messages/shape_tool.rs index 51feecedfd..4c4ab4e4a1 100644 --- a/editor/src/messages/tool/tool_messages/shape_tool.rs +++ b/editor/src/messages/tool/tool_messages/shape_tool.rs @@ -624,29 +624,33 @@ impl Fsm for ShapeToolFsmState { let nodes = vec![(NodeId(0), node)]; let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, document.new_layer_bounding_artboard(input), responses); - responses.add(Message::StartBuffer); + let defered_responses = &mut VecDeque::new(); match tool_data.current_shape { ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Arc | ShapeType::Polygon | ShapeType::Star => { - responses.add(GraphOperationMessage::TransformSet { + defered_responses.add(GraphOperationMessage::TransformSet { layer, transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position), transform_in: TransformIn::Viewport, skip_rerender: false, }); - tool_options.fill.apply_fill(layer, responses); + tool_options.fill.apply_fill(layer, defered_responses); } ShapeType::Line => { tool_data.line_data.weight = tool_options.line_weight; tool_data.line_data.editing_layer = Some(layer); } } - tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses); + tool_options.stroke.apply_stroke(tool_options.line_weight, layer, defered_responses); - tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses); + tool_options.stroke.apply_stroke(tool_options.line_weight, layer, defered_responses); tool_data.data.layer = Some(layer); + responses.add(DeferMessage::AfterGraphRun { + messages: defered_responses.drain(..).collect(), + }); + ShapeToolFsmState::Drawing(tool_data.current_shape) } (ShapeToolFsmState::Drawing(shape), ShapeToolMessage::PointerMove(modifier)) => { diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index 0a96443ee5..ee8a6485fd 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -360,7 +360,7 @@ impl Fsm for SplineToolFsmState { tool_options.stroke.apply_stroke(tool_data.weight, layer, responses); tool_data.current_layer = Some(layer); - responses.add(Message::StartBuffer); + // responses.add(Message::StartBuffer); SplineToolFsmState::Drawing } diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index cb86fecacb..447a3ae258 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -385,20 +385,25 @@ impl TextToolData { parent: document.new_layer_parent(true), insert_index: 0, }); - responses.add(Message::StartBuffer); - responses.add(GraphOperationMessage::FillSet { - layer: self.layer, - fill: if editing_text.color.is_some() { - Fill::Solid(editing_text.color.unwrap().to_gamma_srgb()) - } else { - Fill::None - }, - }); - responses.add(GraphOperationMessage::TransformSet { - layer: self.layer, - transform: editing_text.transform, - transform_in: TransformIn::Viewport, - skip_rerender: true, + responses.add(DeferMessage::AfterGraphRun { + messages: vec![ + GraphOperationMessage::FillSet { + layer: self.layer, + fill: if editing_text.color.is_some() { + Fill::Solid(editing_text.color.unwrap().to_gamma_srgb()) + } else { + Fill::None + }, + } + .into(), + GraphOperationMessage::TransformSet { + layer: self.layer, + transform: editing_text.transform, + transform_in: TransformIn::Viewport, + skip_rerender: true, + } + .into(), + ], }); self.editing_text = Some(editing_text); diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 55ff001f19..1e8b42f6fb 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -385,9 +385,26 @@ impl NodeGraphExecutor { return Err(format!("Invalid node graph output type: {node_graph_output:#?}")); } }; - responses.add(Message::EndBuffer { - render_metadata: render_output_metadata, + // responses.add(Message::EndBuffer { + // render_metadata: render_output_metadata, + // }); + responses.add(DeferMessage::TriggerGraphRun); + let graphene_std::renderer::RenderMetadata { + upstream_footprints: footprints, + local_transforms, + first_instance_source_id, + click_targets, + clip_targets, + } = render_output_metadata; + + // Run these update state messages immediately + responses.add(DocumentMessage::UpdateUpstreamTransforms { + upstream_footprints: footprints, + local_transforms, + first_instance_source_id, }); + responses.add(DocumentMessage::UpdateClickTargets { click_targets }); + responses.add(DocumentMessage::UpdateClipTargets { clip_targets }); responses.add(DocumentMessage::RenderScrollbars); responses.add(DocumentMessage::RenderRulers); responses.add(OverlaysMessage::Draw); From b799d434faa4b5d99c95a9fb586428137b712222 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Mon, 28 Jul 2025 12:45:51 +0200 Subject: [PATCH 2/5] Cleanup --- editor/src/messages/tool/tool_messages/spline_tool.rs | 2 -- editor/src/node_graph_executor.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index ee8a6485fd..b0bad6b7fa 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -360,8 +360,6 @@ impl Fsm for SplineToolFsmState { tool_options.stroke.apply_stroke(tool_data.weight, layer, responses); tool_data.current_layer = Some(layer); - // responses.add(Message::StartBuffer); - SplineToolFsmState::Drawing } (SplineToolFsmState::Drawing, SplineToolMessage::DragStop) => { diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 1e8b42f6fb..9bedd93702 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -385,9 +385,6 @@ impl NodeGraphExecutor { return Err(format!("Invalid node graph output type: {node_graph_output:#?}")); } }; - // responses.add(Message::EndBuffer { - // render_metadata: render_output_metadata, - // }); responses.add(DeferMessage::TriggerGraphRun); let graphene_std::renderer::RenderMetadata { upstream_footprints: footprints, From 7af1d96c6cdc6ca39899ea0f764b4430caf54984 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Mon, 28 Jul 2025 14:30:00 +0200 Subject: [PATCH 3/5] Track graph execution id to associate messages with their corresponding execution id --- editor/src/dispatcher.rs | 5 ++++- editor/src/messages/defer/defer_message.rs | 6 +++--- .../messages/defer/defer_message_handler.rs | 18 ++++++++++-------- .../new_document_dialog_message_handler.rs | 4 +--- .../src/messages/frontend/frontend_message.rs | 1 - .../input_preprocessor_message_handler.rs | 1 - .../document/document_message_handler.rs | 14 ++++++++++++++ .../portfolio/portfolio_message_handler.rs | 10 ++++------ .../messages/tool/tool_messages/pen_tool.rs | 6 +++--- editor/src/node_graph_executor.rs | 13 ++++++++----- frontend/src/messages.ts | 3 --- frontend/src/state-providers/document.ts | 7 ------- 12 files changed, 47 insertions(+), 41 deletions(-) diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index dc910aa487..4be3e53621 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -51,7 +51,10 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[ MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad), ]; -const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::AnimationFrame))]; +const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[ + MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::AnimationFrame)), + MessageDiscriminant::Animation(AnimationMessageDiscriminant::IncrementFrameCounter), +]; // TODO: Find a way to combine these with the list above. We use strings for now since these are the standard variant names used by multiple messages. But having these also type-checked would be best. const DEBUG_MESSAGE_ENDING_BLOCK_LIST: &[&str] = &["PointerMove", "PointerOutsideViewport", "Overlays", "Draw", "CurrentTime", "Time"]; diff --git a/editor/src/messages/defer/defer_message.rs b/editor/src/messages/defer/defer_message.rs index 8149886b8c..8d9c687aae 100644 --- a/editor/src/messages/defer/defer_message.rs +++ b/editor/src/messages/defer/defer_message.rs @@ -3,8 +3,8 @@ use crate::messages::prelude::*; #[impl_message(Message, Defer)] #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum DeferMessage { - TriggerGraphRun, + TriggerGraphRun(u64), AfterGraphRun { messages: Vec }, - TriggerViewportResize, - AfterViewportResize { messages: Vec }, + TriggerViewportReady, + AfterViewportReady { messages: Vec }, } diff --git a/editor/src/messages/defer/defer_message_handler.rs b/editor/src/messages/defer/defer_message_handler.rs index 263a21a18b..440fffd83c 100644 --- a/editor/src/messages/defer/defer_message_handler.rs +++ b/editor/src/messages/defer/defer_message_handler.rs @@ -2,26 +2,28 @@ use crate::messages::prelude::*; #[derive(Debug, Default, ExtractField)] pub struct DeferMessageHandler { - after_graph_run: Vec, + after_graph_run: Vec<(u64, Message)>, after_viewport_resize: Vec, + current_graph_submission_id: u64, } #[message_handler_data] impl MessageHandler for DeferMessageHandler { fn process_message(&mut self, message: DeferMessage, responses: &mut VecDeque, _: ()) { match message { - DeferMessage::AfterGraphRun { messages } => { - self.after_graph_run.extend_from_slice(&messages); + DeferMessage::AfterGraphRun { mut messages } => { + self.after_graph_run.extend(messages.drain(..).map(|m| (self.current_graph_submission_id, m))); } - DeferMessage::AfterViewportResize { messages } => { + DeferMessage::AfterViewportReady { messages } => { self.after_viewport_resize.extend_from_slice(&messages); } - DeferMessage::TriggerGraphRun => { - for message in self.after_graph_run.drain(..) { - responses.push_front(message); + DeferMessage::TriggerGraphRun(execution_id) => { + self.current_graph_submission_id = execution_id; + for message in self.after_graph_run.extract_if(.., |x| x.0 < self.current_graph_submission_id) { + responses.push_front(message.1); } } - DeferMessage::TriggerViewportResize => { + DeferMessage::TriggerViewportReady => { for message in self.after_viewport_resize.drain(..) { responses.push_front(message); } diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs index 07b8687d30..bab30ab144 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -36,9 +36,7 @@ impl MessageHandler for NewDocumentDialogMessageHa }); } - // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead - // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated - responses.add(DeferMessage::AfterViewportResize { + responses.add(DeferMessage::AfterViewportReady { messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], }); responses.add(DocumentMessage::DeselectAllLayers); diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 2b0a8b7eec..e3290db04f 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -59,7 +59,6 @@ pub enum FrontendMessage { #[serde(rename = "commitDate")] commit_date: String, }, - TriggerDelayedZoomCanvasToFitAll, TriggerDownloadImage { svg: String, name: String, 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 528f780517..1a8962d974 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -34,7 +34,6 @@ impl MessageHandler f self.viewport_bounds = bounds; responses.add(NavigationMessage::CanvasPan { delta: DVec2::ZERO }); - responses.add(DeferMessage::TriggerGraphRun); responses.add(NodeGraphMessage::SetGridAlignedEdges); } } diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index d78a711b3f..a350d803b2 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1435,6 +1435,20 @@ impl MessageHandler> for DocumentMes }, }) } + // Some parts of the editior depend on these bounds to be present + let bounds = if self.graph_view_overlay_open { + self.network_interface.all_nodes_bounding_box(&self.breadcrumb_network_path).cloned() + } else { + self.network_interface.document_bounds_document_space(true) + }; + if bounds.is_some() { + responses.add(DeferMessage::TriggerViewportReady); + } else { + // If we don't have bounds yet, we need wait until the node graph has run once more + responses.add(DeferMessage::AfterGraphRun { + messages: vec![DocumentMessage::PTZUpdate.into()], + }); + } } DocumentMessage::SelectionStepBack => { self.network_interface.selection_step_back(&self.selection_network_path); diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 49aa153fb2..123479efab 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -702,13 +702,12 @@ impl MessageHandler> for Portfolio if create_document { // Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image + responses.add(DeferMessage::AfterViewportReady { + messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], + }); responses.add(DeferMessage::AfterGraphRun { messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()], }); - - responses.add(DeferMessage::AfterViewportResize { - messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], - }); } } PortfolioMessage::PasteSvg { @@ -738,7 +737,7 @@ impl MessageHandler> for Portfolio messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()], }); - responses.add(DeferMessage::AfterViewportResize { + responses.add(DeferMessage::AfterViewportReady { messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], }); } @@ -1020,7 +1019,6 @@ impl PortfolioMessageHandler { /text>"# // It's a mystery why the `/text>` tag above needs to be missing its `<`, but when it exists it prints the `<` character in the text. However this works with it removed. .to_string(); - responses.add(DeferMessage::TriggerGraphRun); responses.add(FrontendMessage::UpdateDocumentArtwork { svg: error }); } result diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 82308fd412..08583a5189 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -1721,9 +1721,9 @@ impl Fsm for PenToolFsmState { let next_point = tool_data.next_point; let start = latest_point.id; - if let Some(layer) = layer { - let mut vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); - + if let Some(layer) = layer + && let Some(mut vector_data) = document.network_interface.compute_modified_vector(layer) + { let closest_point = vector_data.extendable_points(preferences.vector_meshes).filter(|&id| id != start).find(|&id| { vector_data.point_domain.position_from_id(id).map_or(false, |pos| { let dist_sq = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point)); diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 9bedd93702..0b4ceb38b7 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -3,7 +3,7 @@ use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::prelude::*; use glam::{DAffine2, DVec2, UVec2}; use graph_craft::document::value::{RenderOutput, TaggedValue}; -use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, generate_uuid}; +use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graph_craft::wasm_application_io::EditorPreferences; use graphene_std::application_io::TimingInformation; @@ -56,6 +56,7 @@ pub enum NodeGraphUpdate { #[derive(Debug, Default)] pub struct NodeGraphExecutor { runtime_io: NodeRuntimeIO, + current_execution_id: u64, futures: HashMap, node_graph_hash: u64, old_inspect_node: Option, @@ -78,13 +79,15 @@ impl NodeGraphExecutor { futures: Default::default(), runtime_io: NodeRuntimeIO::with_channels(request_sender, response_receiver), node_graph_hash: 0, + current_execution_id: 0, old_inspect_node: None, }; (node_runtime, node_executor) } /// Execute the network by flattening it and creating a borrow stack. - fn queue_execution(&self, render_config: RenderConfig) -> u64 { - let execution_id = generate_uuid(); + fn queue_execution(&mut self, render_config: RenderConfig) -> u64 { + let execution_id = self.current_execution_id; + self.current_execution_id += 1; let request = ExecutionRequest { execution_id, render_config }; self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).expect("Failed to send generation request"); @@ -105,7 +108,7 @@ impl NodeGraphExecutor { #[cfg(test)] pub(crate) fn update_node_graph_instrumented(&mut self, document: &mut DocumentMessageHandler) -> Result { // We should always invalidate the cache. - self.node_graph_hash = generate_uuid(); + self.node_graph_hash = crate::application::generate_uuid(); let mut network = document.network_interface.document_network().clone(); let instrumented = Instrumented::new(&mut network); @@ -280,6 +283,7 @@ impl NodeGraphExecutor { } else { self.process_node_graph_output(node_graph_output, transform, responses)? } + responses.add(DeferMessage::TriggerGraphRun(execution_id)); // Update the spreadsheet on the frontend using the value of the inspect result. if self.old_inspect_node.is_some() { @@ -385,7 +389,6 @@ impl NodeGraphExecutor { return Err(format!("Invalid node graph output type: {node_graph_output:#?}")); } }; - responses.add(DeferMessage::TriggerGraphRun); let graphene_std::renderer::RenderMetadata { upstream_footprints: footprints, local_transforms, diff --git a/frontend/src/messages.ts b/frontend/src/messages.ts index 20a9df9992..5bb11ade09 100644 --- a/frontend/src/messages.ts +++ b/frontend/src/messages.ts @@ -791,8 +791,6 @@ export class TriggerImport extends JsMessage {} export class TriggerPaste extends JsMessage {} -export class TriggerDelayedZoomCanvasToFitAll extends JsMessage {} - export class TriggerDownloadImage extends JsMessage { readonly svg!: string; @@ -1649,7 +1647,6 @@ export const messageMakers: Record = { DisplayRemoveEditableTextbox, SendUIMetadata, TriggerAboutGraphiteLocalizedCommitDate, - TriggerDelayedZoomCanvasToFitAll, TriggerDownloadImage, TriggerDownloadTextFile, TriggerFetchAndOpenDocument, diff --git a/frontend/src/state-providers/document.ts b/frontend/src/state-providers/document.ts index c9ab1f2b5d..2a8afa666e 100644 --- a/frontend/src/state-providers/document.ts +++ b/frontend/src/state-providers/document.ts @@ -13,7 +13,6 @@ import { UpdateWorkingColorsLayout, UpdateNodeGraphControlBarLayout, UpdateGraphViewOverlay, - TriggerDelayedZoomCanvasToFitAll, UpdateGraphFadeArtwork, } from "@graphite/messages"; @@ -94,12 +93,6 @@ export function createDocumentState(editor: Editor) { return state; }); }); - editor.subscriptions.subscribeJsMessage(TriggerDelayedZoomCanvasToFitAll, () => { - // TODO: This is horribly hacky - [0, 1, 10, 50, 100, 200, 300, 400, 500].forEach((delay) => { - setTimeout(() => editor.handle.zoomCanvasToFitAll(), delay); - }); - }); return { subscribe, From 4d1f4b5f7859cab9bb9e934af7348f7b6085377c Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Mon, 28 Jul 2025 19:59:57 +0200 Subject: [PATCH 4/5] Rename ViewportReady -> NavigationReady --- editor/src/messages/defer/defer_message.rs | 4 ++-- editor/src/messages/defer/defer_message_handler.rs | 4 ++-- .../new_document_dialog_message_handler.rs | 2 +- .../messages/portfolio/document/document_message_handler.rs | 4 ++-- editor/src/messages/portfolio/portfolio_message_handler.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/editor/src/messages/defer/defer_message.rs b/editor/src/messages/defer/defer_message.rs index 8d9c687aae..b49eee8159 100644 --- a/editor/src/messages/defer/defer_message.rs +++ b/editor/src/messages/defer/defer_message.rs @@ -5,6 +5,6 @@ use crate::messages::prelude::*; pub enum DeferMessage { TriggerGraphRun(u64), AfterGraphRun { messages: Vec }, - TriggerViewportReady, - AfterViewportReady { messages: Vec }, + TriggerNavigationReady, + AfterNavigationReady { messages: Vec }, } diff --git a/editor/src/messages/defer/defer_message_handler.rs b/editor/src/messages/defer/defer_message_handler.rs index 440fffd83c..598f9646d7 100644 --- a/editor/src/messages/defer/defer_message_handler.rs +++ b/editor/src/messages/defer/defer_message_handler.rs @@ -14,7 +14,7 @@ impl MessageHandler for DeferMessageHandler { DeferMessage::AfterGraphRun { mut messages } => { self.after_graph_run.extend(messages.drain(..).map(|m| (self.current_graph_submission_id, m))); } - DeferMessage::AfterViewportReady { messages } => { + DeferMessage::AfterNavigationReady { messages } => { self.after_viewport_resize.extend_from_slice(&messages); } DeferMessage::TriggerGraphRun(execution_id) => { @@ -23,7 +23,7 @@ impl MessageHandler for DeferMessageHandler { responses.push_front(message.1); } } - DeferMessage::TriggerViewportReady => { + DeferMessage::TriggerNavigationReady => { for message in self.after_viewport_resize.drain(..) { responses.push_front(message); } diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs index bab30ab144..e8e0313c3b 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -36,7 +36,7 @@ impl MessageHandler for NewDocumentDialogMessageHa }); } - responses.add(DeferMessage::AfterViewportReady { + responses.add(DeferMessage::AfterNavigationReady { messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], }); responses.add(DocumentMessage::DeselectAllLayers); diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index a350d803b2..cf8f90534c 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1435,14 +1435,14 @@ impl MessageHandler> for DocumentMes }, }) } - // Some parts of the editior depend on these bounds to be present + // Some parts of the editior (e.g. navigation messages) depend on these bounds to be present let bounds = if self.graph_view_overlay_open { self.network_interface.all_nodes_bounding_box(&self.breadcrumb_network_path).cloned() } else { self.network_interface.document_bounds_document_space(true) }; if bounds.is_some() { - responses.add(DeferMessage::TriggerViewportReady); + responses.add(DeferMessage::TriggerNavigationReady); } else { // If we don't have bounds yet, we need wait until the node graph has run once more responses.add(DeferMessage::AfterGraphRun { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 123479efab..96028179ed 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -702,7 +702,7 @@ impl MessageHandler> for Portfolio if create_document { // Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image - responses.add(DeferMessage::AfterViewportReady { + responses.add(DeferMessage::AfterNavigationReady { messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], }); responses.add(DeferMessage::AfterGraphRun { @@ -737,7 +737,7 @@ impl MessageHandler> for Portfolio messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()], }); - responses.add(DeferMessage::AfterViewportReady { + responses.add(DeferMessage::AfterNavigationReady { messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], }); } From 366c3ff64fbb60f2a6b1833114464b49602f3994 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Tue, 29 Jul 2025 01:22:22 +0200 Subject: [PATCH 5/5] Defer layer deselection --- .../new_document_dialog/new_document_dialog_message_handler.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs index e8e0313c3b..23fb98dea6 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -37,9 +37,8 @@ impl MessageHandler for NewDocumentDialogMessageHa } responses.add(DeferMessage::AfterNavigationReady { - messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()], + messages: vec![DocumentMessage::ZoomCanvasToFitAll.into(), DocumentMessage::DeselectAllLayers.into()], }); - responses.add(DocumentMessage::DeselectAllLayers); } }