diff --git a/editor/src/communication/dispatcher.rs b/editor/src/communication/dispatcher.rs index ec75305a6..60354e7ab 100644 --- a/editor/src/communication/dispatcher.rs +++ b/editor/src/communication/dispatcher.rs @@ -10,7 +10,7 @@ use std::collections::VecDeque; #[derive(Debug, Default)] pub struct Dispatcher { - message_queue: VecDeque, + message_queues: Vec>, pub responses: Vec, message_handlers: DispatcherMessageHandlers, } @@ -38,8 +38,9 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[ ArtboardMessageDiscriminant::RenderArtboards, ))), MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::FolderChanged)), - MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerDetails), + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure), + MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateActiveDocument), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateOpenDocumentsList), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad), MessageDiscriminant::Tool(ToolMessageDiscriminant::DocumentIsDirty), @@ -54,17 +55,31 @@ impl Dispatcher { pub fn handle_message>(&mut self, message: T) { use Message::*; - self.message_queue.push_back(message.into()); + self.message_queues.push(VecDeque::from_iter([message.into()])); - while let Some(message) = self.message_queue.pop_front() { - // Skip processing of this message if it will be processed later - if SIDE_EFFECT_FREE_MESSAGES.contains(&message.to_discriminant()) && self.message_queue.contains(&message) { - continue; + while let Some(message) = self.message_queues.last_mut().and_then(VecDeque::pop_front) { + // If the deepest queue is now empty (after being popped from) then remove it + if self.message_queues.last().filter(|queue| queue.is_empty()).is_some() { + self.message_queues.pop(); + } + + // Skip processing of this message if it will be processed later (at the end of the shallowest level queue) + if SIDE_EFFECT_FREE_MESSAGES.contains(&message.to_discriminant()) { + let already_in_queue = self.message_queues.first().filter(|queue| queue.contains(&message)).is_some(); + if already_in_queue { + continue; + } else if self.message_queues.len() > 1 { + self.message_queues[0].push_back(message); + continue; + } } // Print the message at a verbosity level of `log` self.log_message(&message); + // Create a new queue for the child messages + let mut queue = VecDeque::new(); + // Process the action by forwarding it to the relevant message handler, or saving the FrontendMessage to be sent to the frontend #[remain::sorted] match message { @@ -73,7 +88,7 @@ impl Dispatcher { Dialog(message) => { self.message_handlers .dialog_message_handler - .process_action(message, &self.message_handlers.portfolio_message_handler, &mut self.message_queue); + .process_action(message, &self.message_handlers.portfolio_message_handler, &mut queue); } Frontend(message) => { // Image and font loading should be immediately handled @@ -86,22 +101,22 @@ impl Dispatcher { self.responses.push(message); } Global(message) => { - self.message_handlers.global_message_handler.process_action(message, (), &mut self.message_queue); + self.message_handlers.global_message_handler.process_action(message, (), &mut queue); } InputMapper(message) => { let actions = self.collect_actions(); self.message_handlers .input_mapper_message_handler - .process_action(message, (&self.message_handlers.input_preprocessor_message_handler, actions), &mut self.message_queue); + .process_action(message, (&self.message_handlers.input_preprocessor_message_handler, actions), &mut queue); } InputPreprocessor(message) => { - self.message_handlers.input_preprocessor_message_handler.process_action(message, (), &mut self.message_queue); + self.message_handlers.input_preprocessor_message_handler.process_action(message, (), &mut queue); } - Layout(message) => self.message_handlers.layout_message_handler.process_action(message, (), &mut self.message_queue), + Layout(message) => self.message_handlers.layout_message_handler.process_action(message, (), &mut queue), Portfolio(message) => { self.message_handlers .portfolio_message_handler - .process_action(message, &self.message_handlers.input_preprocessor_message_handler, &mut self.message_queue); + .process_action(message, &self.message_handlers.input_preprocessor_message_handler, &mut queue); } Tool(message) => { self.message_handlers.tool_message_handler.process_action( @@ -111,15 +126,20 @@ impl Dispatcher { &self.message_handlers.input_preprocessor_message_handler, self.message_handlers.portfolio_message_handler.font_cache(), ), - &mut self.message_queue, + &mut queue, ); } Workspace(message) => { self.message_handlers .workspace_message_handler - .process_action(message, &self.message_handlers.input_preprocessor_message_handler, &mut self.message_queue); + .process_action(message, &self.message_handlers.input_preprocessor_message_handler, &mut queue); } } + + // If there are child messages, append the queue to the list of queues + if !queue.is_empty() { + self.message_queues.push(queue); + } } } diff --git a/editor/src/document/portfolio_message_handler.rs b/editor/src/document/portfolio_message_handler.rs index 4b47cb5cc..53f6094ff 100644 --- a/editor/src/document/portfolio_message_handler.rs +++ b/editor/src/document/portfolio_message_handler.rs @@ -85,20 +85,7 @@ impl PortfolioMessageHandler { self.documents.insert(document_id, new_document); - // Send the new list of document tab names - let open_documents = self - .document_ids - .iter() - .filter_map(|id| { - self.documents.get(id).map(|document| FrontendDocumentDetails { - is_saved: document.is_saved(), - id: *id, - name: document.name.clone(), - }) - }) - .collect::>(); - - responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into()); + responses.push_back(PortfolioMessage::UpdateOpenDocumentsList.into()); responses.push_back(PortfolioMessage::SelectDocument { document_id }.into()); } @@ -209,19 +196,7 @@ impl MessageHandler for Port }; // Send the new list of document tab names - let open_documents = self - .document_ids - .iter() - .filter_map(|id| { - self.documents.get(id).map(|doc| FrontendDocumentDetails { - is_saved: doc.is_saved(), - id: *id, - name: doc.name.clone(), - }) - }) - .collect::>(); - - responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into()); + responses.push_back(UpdateOpenDocumentsList.into()); responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: self.active_document_id }.into()); responses.push_back(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id }.into()); responses.push_back(RenderDocument.into()); diff --git a/editor/src/layout/layout_message_handler.rs b/editor/src/layout/layout_message_handler.rs index 098d229bd..497ab2764 100644 --- a/editor/src/layout/layout_message_handler.rs +++ b/editor/src/layout/layout_message_handler.rs @@ -75,6 +75,7 @@ impl MessageHandler for LayoutMessageHandler { self.send_layout(layout_target, responses); } UpdateLayout { layout_target, widget_id, value } => { + self.send_layout(layout_target, responses); let layout = &mut self.layouts[layout_target as usize]; let widget_holder = layout.iter_mut().find(|widget| widget.widget_id == widget_id); if widget_holder.is_none() { @@ -183,7 +184,6 @@ impl MessageHandler for LayoutMessageHandler { } Widget::TextLabel(_) => {} }; - self.send_layout(layout_target, responses); } } } diff --git a/editor/src/viewport_tools/tools/shared/path_outline.rs b/editor/src/viewport_tools/tools/shared/path_outline.rs index ee25ddb6e..207358e6b 100644 --- a/editor/src/viewport_tools/tools/shared/path_outline.rs +++ b/editor/src/viewport_tools/tools/shared/path_outline.rs @@ -113,7 +113,7 @@ impl PathOutline { /// Clears overlays for the seleted paths and removes references pub fn clear_selected(&mut self, responses: &mut VecDeque) { - if let Some(path) = self.selected_overlay_paths.pop() { + while let Some(path) = self.selected_overlay_paths.pop() { let operation = Operation::DeleteLayer { path }; responses.push_back(DocumentMessage::Overlays(operation.into()).into()); }