Welcome screen, refactor to allow zero documents, and add TS typing to widgets (#702)

* unfinished implementation

* Add frontend for the empty panel screen

* Add an icon for Folder based on NodeFolder

* fixed messages causing peicees of ui not to render on new document

* Standardize nextTick syntax

* WIP generisization of component subscriptions (not compiling yet)

* Fix crash when loading font and there is no active document

* Only advertise tool actions with a document

* Fix failure to create new document

* Initalise the properties panel

* Fix highlight tab, canvas jump, warns and layer tree

* Fix tests

* Possibly fix some things?

* Move WorkingColors layout definition to backend

* Standardize action macro formatting

* Provide typing for widgets in TS/Vue and associated cleanup

* Fix viewport positioning initialization

* Fix menu bar init at startup not document creation

* Fix no viewport bounds bug

* Change !=0 to >0

* Simplify the init system

Closes #656

Co-authored-by: Keavon Chambers <keavon@keavon.com>
Co-authored-by: 0hypercube <0hypercube@gmail.com>
This commit is contained in:
mfish33
2022-07-22 16:09:13 -06:00
committed by Keavon Chambers
co-authored by Keavon Chambers 0hypercube
parent b4b667ded6
commit a0c22d20b6
77 changed files with 1859 additions and 1136 deletions
+53 -31
View File
@@ -1,4 +1,5 @@
use super::broadcast_message_handler::BroadcastMessageHandler;
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
use crate::document::PortfolioMessageHandler;
use crate::global::GlobalMessageHandler;
use crate::input::{InputMapperMessageHandler, InputPreprocessorMessageHandler};
@@ -7,6 +8,8 @@ use crate::message_prelude::*;
use crate::viewport_tools::tool_message_handler::ToolMessageHandler;
use crate::workspace::WorkspaceMessageHandler;
use graphene::layers::text_layer::Font;
use std::collections::VecDeque;
#[derive(Debug, Default)]
@@ -42,8 +45,6 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::FolderChanged)),
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateActiveDocument),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateOpenDocumentsList),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerSignal(BroadcastSignalDiscriminant::DocumentIsDirty)),
];
@@ -87,6 +88,18 @@ impl Dispatcher {
match message {
#[remain::unsorted]
NoOp => {}
#[remain::unsorted]
Init => {
// Display the menu bar at the top of the window
let message = MenuBarMessage::SendLayout.into();
queue.push_back(message);
// Load the default font
let font = Font::new(DEFAULT_FONT_FAMILY.into(), DEFAULT_FONT_STYLE.into());
let message = FrontendMessage::TriggerFontLoad { font, is_default: true }.into();
queue.push_back(message);
}
Broadcast(message) => self.message_handlers.broadcast_message_handler.process_action(message, (), &mut queue),
Dialog(message) => {
self.message_handlers
@@ -94,14 +107,16 @@ impl Dispatcher {
.process_action(message, &self.message_handlers.portfolio_message_handler, &mut queue);
}
Frontend(message) => {
// Image and font loading should be immediately handled
if let FrontendMessage::UpdateImageData { .. } | FrontendMessage::TriggerFontLoad { .. } = message {
// Handle these messages immediately by returning early
if let FrontendMessage::UpdateImageData { .. } | FrontendMessage::TriggerFontLoad { .. } | FrontendMessage::TriggerRefreshBoundsOfViewports = message {
self.responses.push(message);
return;
}
// `FrontendMessage`s are saved and will be sent to the frontend after the message queue is done being processed
self.responses.push(message);
// Return early to avoid running the code after the match block
return;
} else {
// `FrontendMessage`s are saved and will be sent to the frontend after the message queue is done being processed
self.responses.push(message);
}
}
Global(message) => {
self.message_handlers.global_message_handler.process_action(message, (), &mut queue);
@@ -122,15 +137,19 @@ impl Dispatcher {
.process_action(message, &self.message_handlers.input_preprocessor_message_handler, &mut queue);
}
Tool(message) => {
self.message_handlers.tool_message_handler.process_action(
message,
(
self.message_handlers.portfolio_message_handler.active_document(),
&self.message_handlers.input_preprocessor_message_handler,
self.message_handlers.portfolio_message_handler.font_cache(),
),
&mut queue,
);
if let Some(document) = self.message_handlers.portfolio_message_handler.active_document() {
self.message_handlers.tool_message_handler.process_action(
message,
(
document,
&self.message_handlers.input_preprocessor_message_handler,
self.message_handlers.portfolio_message_handler.font_cache(),
),
&mut queue,
);
} else {
log::warn!("Called ToolMessage without an active document.\nGot {:?}", message);
}
}
Workspace(message) => {
self.message_handlers
@@ -153,7 +172,9 @@ impl Dispatcher {
list.extend(self.message_handlers.input_preprocessor_message_handler.actions());
list.extend(self.message_handlers.input_mapper_message_handler.actions());
list.extend(self.message_handlers.global_message_handler.actions());
list.extend(self.message_handlers.tool_message_handler.actions());
if self.message_handlers.portfolio_message_handler.active_document().is_some() {
list.extend(self.message_handlers.tool_message_handler.actions());
}
list.extend(self.message_handlers.portfolio_message_handler.actions());
list
}
@@ -192,6 +213,7 @@ mod test {
set_uuid_seed(0);
let mut editor = Editor::new();
editor.new_document();
editor.select_primary_color(Color::RED);
editor.draw_rect(100., 200., 300., 400.);
editor.select_primary_color(Color::BLUE);
@@ -211,14 +233,14 @@ mod test {
init_logger();
let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
editor.handle_message(PortfolioMessage::PasteIntoFolder {
clipboard: Clipboard::Internal,
folder_path: vec![],
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let layers_before_copy = document_before_copy.root.as_folder().unwrap().layers();
let layers_after_copy = document_after_copy.root.as_folder().unwrap().layers();
@@ -245,7 +267,7 @@ mod test {
init_logger();
let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let shape_id = document_before_copy.root.as_folder().unwrap().layer_ids[1];
editor.handle_message(DocumentMessage::SetSelectedLayers {
@@ -258,7 +280,7 @@ mod test {
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let layers_before_copy = document_before_copy.root.as_folder().unwrap().layers();
let layers_after_copy = document_after_copy.root.as_folder().unwrap().layers();
@@ -290,7 +312,7 @@ mod test {
editor.handle_message(DocumentMessage::CreateEmptyFolder { container_path: vec![] });
let document_before_added_shapes = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_before_added_shapes = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let folder_id = document_before_added_shapes.root.as_folder().unwrap().layer_ids[FOLDER_INDEX];
// TODO: This adding of a Line and Pen should be rewritten using the corresponding functions in EditorTestUtils.
@@ -314,7 +336,7 @@ mod test {
replacement_selected_layers: vec![vec![folder_id]],
});
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
editor.handle_message(DocumentMessage::DeleteSelectedLayers);
@@ -329,7 +351,7 @@ mod test {
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let layers_before_copy = document_before_copy.root.as_folder().unwrap().layers();
let layers_after_copy = document_after_copy.root.as_folder().unwrap().layers();
@@ -380,7 +402,7 @@ mod test {
const SHAPE_INDEX: usize = 1;
const RECT_INDEX: usize = 0;
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let rect_id = document_before_copy.root.as_folder().unwrap().layer_ids[RECT_INDEX];
let ellipse_id = document_before_copy.root.as_folder().unwrap().layer_ids[ELLIPSE_INDEX];
@@ -401,7 +423,7 @@ mod test {
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().graphene_document.clone();
let layers_before_copy = document_before_copy.root.as_folder().unwrap().layers();
let layers_after_copy = document_after_copy.root.as_folder().unwrap().layers();
@@ -431,7 +453,7 @@ mod test {
fn map_to_vec(paths: Vec<&[LayerId]>) -> Vec<Vec<LayerId>> {
paths.iter().map(|layer| layer.to_vec()).collect::<Vec<_>>()
}
let sorted_layers = map_to_vec(editor.dispatcher.message_handlers.portfolio_message_handler.active_document().all_layers_sorted());
let sorted_layers = map_to_vec(editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().all_layers_sorted());
println!("Sorted layers: {:?}", sorted_layers);
let verify_order = |handler: &mut DocumentMessageHandler| {
@@ -447,15 +469,15 @@ mod test {
});
editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: 1 });
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap());
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: -1 });
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap());
assert_eq!(all, selected.into_iter().chain(non_selected.into_iter()).collect::<Vec<_>>());
editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: isize::MAX });
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap());
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
}
+2
View File
@@ -22,6 +22,8 @@ where
pub enum Message {
#[remain::unsorted]
NoOp,
#[remain::unsorted]
Init,
#[child]
Broadcast(BroadcastMessage),
#[child]