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 99ec4ef1cc..b9068cbcdb 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() { @@ -384,7 +388,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,