Improve message ordering to use a stack (#707)

* Improve message ordering

* Resovle bug with widgets

* Less code duplication for UpdateOpenDocumentsList

* Fix layer panel
This commit is contained in:
0HyperCube 2022-07-01 19:11:15 +01:00 committed by Keavon Chambers
parent d12d805e2f
commit b2eae904d8
4 changed files with 39 additions and 44 deletions

View File

@ -10,7 +10,7 @@ use std::collections::VecDeque;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Dispatcher { pub struct Dispatcher {
message_queue: VecDeque<Message>, message_queues: Vec<VecDeque<Message>>,
pub responses: Vec<FrontendMessage>, pub responses: Vec<FrontendMessage>,
message_handlers: DispatcherMessageHandlers, message_handlers: DispatcherMessageHandlers,
} }
@ -38,8 +38,9 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
ArtboardMessageDiscriminant::RenderArtboards, ArtboardMessageDiscriminant::RenderArtboards,
))), ))),
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::FolderChanged)), MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::FolderChanged)),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerDetails), MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateActiveDocument),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateOpenDocumentsList), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateOpenDocumentsList),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
MessageDiscriminant::Tool(ToolMessageDiscriminant::DocumentIsDirty), MessageDiscriminant::Tool(ToolMessageDiscriminant::DocumentIsDirty),
@ -54,17 +55,31 @@ impl Dispatcher {
pub fn handle_message<T: Into<Message>>(&mut self, message: T) { pub fn handle_message<T: Into<Message>>(&mut self, message: T) {
use Message::*; 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() { while let Some(message) = self.message_queues.last_mut().and_then(VecDeque::pop_front) {
// Skip processing of this message if it will be processed later // If the deepest queue is now empty (after being popped from) then remove it
if SIDE_EFFECT_FREE_MESSAGES.contains(&message.to_discriminant()) && self.message_queue.contains(&message) { if self.message_queues.last().filter(|queue| queue.is_empty()).is_some() {
continue; 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` // Print the message at a verbosity level of `log`
self.log_message(&message); 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 // Process the action by forwarding it to the relevant message handler, or saving the FrontendMessage to be sent to the frontend
#[remain::sorted] #[remain::sorted]
match message { match message {
@ -73,7 +88,7 @@ impl Dispatcher {
Dialog(message) => { Dialog(message) => {
self.message_handlers self.message_handlers
.dialog_message_handler .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) => { Frontend(message) => {
// Image and font loading should be immediately handled // Image and font loading should be immediately handled
@ -86,22 +101,22 @@ impl Dispatcher {
self.responses.push(message); self.responses.push(message);
} }
Global(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) => { InputMapper(message) => {
let actions = self.collect_actions(); let actions = self.collect_actions();
self.message_handlers self.message_handlers
.input_mapper_message_handler .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) => { 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) => { Portfolio(message) => {
self.message_handlers self.message_handlers
.portfolio_message_handler .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) => { Tool(message) => {
self.message_handlers.tool_message_handler.process_action( self.message_handlers.tool_message_handler.process_action(
@ -111,15 +126,20 @@ impl Dispatcher {
&self.message_handlers.input_preprocessor_message_handler, &self.message_handlers.input_preprocessor_message_handler,
self.message_handlers.portfolio_message_handler.font_cache(), self.message_handlers.portfolio_message_handler.font_cache(),
), ),
&mut self.message_queue, &mut queue,
); );
} }
Workspace(message) => { Workspace(message) => {
self.message_handlers self.message_handlers
.workspace_message_handler .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);
}
} }
} }

View File

@ -85,20 +85,7 @@ impl PortfolioMessageHandler {
self.documents.insert(document_id, new_document); self.documents.insert(document_id, new_document);
// Send the new list of document tab names responses.push_back(PortfolioMessage::UpdateOpenDocumentsList.into());
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::<Vec<_>>();
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
responses.push_back(PortfolioMessage::SelectDocument { document_id }.into()); responses.push_back(PortfolioMessage::SelectDocument { document_id }.into());
} }
@ -209,19 +196,7 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
}; };
// Send the new list of document tab names // Send the new list of document tab names
let open_documents = self responses.push_back(UpdateOpenDocumentsList.into());
.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::<Vec<_>>();
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: self.active_document_id }.into()); responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: self.active_document_id }.into());
responses.push_back(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id }.into()); responses.push_back(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id }.into());
responses.push_back(RenderDocument.into()); responses.push_back(RenderDocument.into());

View File

@ -75,6 +75,7 @@ impl MessageHandler<LayoutMessage, ()> for LayoutMessageHandler {
self.send_layout(layout_target, responses); self.send_layout(layout_target, responses);
} }
UpdateLayout { layout_target, widget_id, value } => { UpdateLayout { layout_target, widget_id, value } => {
self.send_layout(layout_target, responses);
let layout = &mut self.layouts[layout_target as usize]; let layout = &mut self.layouts[layout_target as usize];
let widget_holder = layout.iter_mut().find(|widget| widget.widget_id == widget_id); let widget_holder = layout.iter_mut().find(|widget| widget.widget_id == widget_id);
if widget_holder.is_none() { if widget_holder.is_none() {
@ -183,7 +184,6 @@ impl MessageHandler<LayoutMessage, ()> for LayoutMessageHandler {
} }
Widget::TextLabel(_) => {} Widget::TextLabel(_) => {}
}; };
self.send_layout(layout_target, responses);
} }
} }
} }

View File

@ -113,7 +113,7 @@ impl PathOutline {
/// Clears overlays for the seleted paths and removes references /// Clears overlays for the seleted paths and removes references
pub fn clear_selected(&mut self, responses: &mut VecDeque<Message>) { pub fn clear_selected(&mut self, responses: &mut VecDeque<Message>) {
if let Some(path) = self.selected_overlay_paths.pop() { while let Some(path) = self.selected_overlay_paths.pop() {
let operation = Operation::DeleteLayer { path }; let operation = Operation::DeleteLayer { path };
responses.push_back(DocumentMessage::Overlays(operation.into()).into()); responses.push_back(DocumentMessage::Overlays(operation.into()).into());
} }