From 1186f331138af49709d81958523d9326d664f3f4 Mon Sep 17 00:00:00 2001 From: TrueDoctor Date: Tue, 28 Dec 2021 06:17:41 +0100 Subject: [PATCH] Implement multiple clipboards (#425) * Imeplement multiple Clipboards * Cargo fmt * Fix unit tests * Fix console error caused by the Pen Tool (#432) * Fix error in pen tool * Cleanup * Split make operation and remove preview Co-authored-by: Keavon Chambers * Fix line centering (#431) * cargo fmt Co-authored-by: 0HyperCube <78500760+0HyperCube@users.noreply.github.com> --- editor/src/communication/dispatcher.rs | 52 +++++++++++++++---- editor/src/document/document_file.rs | 15 ++++-- .../src/document/document_message_handler.rs | 33 ++++++++---- editor/src/document/mod.rs | 2 +- editor/src/input/input_mapper.rs | 7 +-- 5 files changed, 80 insertions(+), 29 deletions(-) diff --git a/editor/src/communication/dispatcher.rs b/editor/src/communication/dispatcher.rs index 591906e0..a67a44c6 100644 --- a/editor/src/communication/dispatcher.rs +++ b/editor/src/communication/dispatcher.rs @@ -96,7 +96,13 @@ impl Dispatcher { #[cfg(test)] mod test { - use crate::{communication::set_uuid_seed, document::DocumentMessageHandler, message_prelude::*, misc::test_utils::EditorTestUtils, Editor}; + use crate::{ + communication::set_uuid_seed, + document::{Clipboard::*, DocumentMessageHandler}, + message_prelude::*, + misc::test_utils::EditorTestUtils, + Editor, + }; use graphene::{color::Color, Operation}; fn init_logger() { @@ -131,8 +137,12 @@ mod test { let mut editor = create_editor_with_three_layers(); let document_before_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); - editor.handle_message(DocumentsMessage::Copy); - editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); + editor.handle_message(DocumentsMessage::Copy(User)); + editor.handle_message(DocumentsMessage::PasteIntoFolder { + clipboard: User, + path: vec![], + insert_index: -1, + }); let document_after_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); let layers_before_copy = document_before_copy.root.as_folder().unwrap().layers(); @@ -164,8 +174,12 @@ mod test { let shape_id = document_before_copy.root.as_folder().unwrap().layer_ids[1]; editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![shape_id]])); - editor.handle_message(DocumentsMessage::Copy); - editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); + editor.handle_message(DocumentsMessage::Copy(User)); + editor.handle_message(DocumentsMessage::PasteIntoFolder { + clipboard: User, + path: vec![], + insert_index: -1, + }); let document_after_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); @@ -223,10 +237,18 @@ mod test { let document_before_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); - editor.handle_message(DocumentsMessage::Copy); + editor.handle_message(DocumentsMessage::Copy(User)); editor.handle_message(DocumentMessage::DeleteSelectedLayers); - editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); - editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); + editor.handle_message(DocumentsMessage::PasteIntoFolder { + clipboard: User, + path: vec![], + insert_index: -1, + }); + editor.handle_message(DocumentsMessage::PasteIntoFolder { + clipboard: User, + path: vec![], + insert_index: -1, + }); let document_after_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); @@ -284,11 +306,19 @@ mod test { let ellipse_id = document_before_copy.root.as_folder().unwrap().layer_ids[ELLIPSE_INDEX]; editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![rect_id], vec![ellipse_id]])); - editor.handle_message(DocumentsMessage::Copy); + editor.handle_message(DocumentsMessage::Copy(User)); editor.handle_message(DocumentMessage::DeleteSelectedLayers); editor.draw_rect(0., 800., 12., 200.); - editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); - editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); + editor.handle_message(DocumentsMessage::PasteIntoFolder { + clipboard: User, + path: vec![], + insert_index: -1, + }); + editor.handle_message(DocumentsMessage::PasteIntoFolder { + clipboard: User, + path: vec![], + insert_index: -1, + }); let document_after_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); diff --git a/editor/src/document/document_file.rs b/editor/src/document/document_file.rs index c2b7f09b..a553a50b 100644 --- a/editor/src/document/document_file.rs +++ b/editor/src/document/document_file.rs @@ -7,6 +7,7 @@ use super::transform_layer_handler::{TransformLayerMessage, TransformLayerMessag use crate::consts::DEFAULT_DOCUMENT_NAME; use crate::consts::{ASYMPTOTIC_EFFECT, FILE_EXPORT_SUFFIX, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING}; +use crate::document::Clipboard; use crate::input::InputPreprocessor; use crate::message_prelude::*; use crate::EditorError; @@ -541,12 +542,13 @@ impl MessageHandler for DocumentMessageHand let mut new_folder_path = common_prefix.to_vec(); new_folder_path.push(generate_uuid()); - responses.push_back(DocumentsMessage::Copy.into()); + responses.push_back(DocumentsMessage::Copy(Clipboard::System).into()); responses.push_back(DocumentMessage::DeleteSelectedLayers.into()); responses.push_back(DocumentOperation::CreateFolder { path: new_folder_path.clone() }.into()); responses.push_back(DocumentMessage::ToggleLayerExpansion(new_folder_path.clone()).into()); responses.push_back( DocumentsMessage::PasteIntoFolder { + clipboard: Clipboard::System, path: new_folder_path.clone(), insert_index: -1, } @@ -792,9 +794,16 @@ impl MessageHandler for DocumentMessageHand responses.push_back(ToolMessage::SelectedLayersChanged.into()); } MoveSelectedLayersTo { path, insert_index } => { - responses.push_back(DocumentsMessage::Copy.into()); + responses.push_back(DocumentsMessage::Copy(Clipboard::System).into()); responses.push_back(DocumentMessage::DeleteSelectedLayers.into()); - responses.push_back(DocumentsMessage::PasteIntoFolder { path, insert_index }.into()); + responses.push_back( + DocumentsMessage::PasteIntoFolder { + clipboard: Clipboard::System, + path, + insert_index, + } + .into(), + ); } ReorderSelectedLayers(relative_position) => { self.backup(responses); diff --git a/editor/src/document/document_message_handler.rs b/editor/src/document/document_message_handler.rs index a63d5775..13e8fdc7 100644 --- a/editor/src/document/document_message_handler.rs +++ b/editor/src/document/document_message_handler.rs @@ -10,15 +10,25 @@ use std::collections::{HashMap, VecDeque}; use super::DocumentMessageHandler; use crate::consts::DEFAULT_DOCUMENT_NAME; +#[repr(u8)] +#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)] +pub enum Clipboard { + System, + User, + _ClipboardCount, +} +static CLIPBOARD_COUNT: u8 = Clipboard::_ClipboardCount as u8; + #[impl_message(Message, Documents)] #[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] pub enum DocumentsMessage { - Copy, + Copy(Clipboard), PasteIntoFolder { + clipboard: Clipboard, path: Vec, insert_index: isize, }, - Paste, + Paste(Clipboard), SelectDocument(u64), CloseDocument(u64), #[child] @@ -49,7 +59,7 @@ pub struct DocumentsMessageHandler { documents: HashMap, document_ids: Vec, active_document_id: u64, - copy_buffer: Vec, + copy_buffer: Vec>, } impl DocumentsMessageHandler { @@ -139,7 +149,7 @@ impl Default for DocumentsMessageHandler { Self { documents: documents_map, document_ids: vec![starting_key], - copy_buffer: vec![], + copy_buffer: vec![vec![]; CLIPBOARD_COUNT as usize], active_document_id: starting_key, } } @@ -319,19 +329,19 @@ impl MessageHandler for DocumentsMessageHa let prev_id = self.document_ids[prev_index]; responses.push_back(DocumentsMessage::SelectDocument(prev_id).into()); } - Copy => { + Copy(clipboard) => { let paths = self.active_document().selected_layers_sorted(); - self.copy_buffer.clear(); + self.copy_buffer[clipboard as usize].clear(); for path in paths { match self.active_document().graphene_document.layer(&path).map(|t| t.clone()) { Ok(layer) => { - self.copy_buffer.push(layer); + self.copy_buffer[clipboard as usize].push(layer); } Err(e) => warn!("Could not access selected layer {:?}: {:?}", path, e), } } } - Paste => { + Paste(clipboard) => { let document = self.active_document(); let shallowest_common_folder = document .graphene_document @@ -340,13 +350,14 @@ impl MessageHandler for DocumentsMessageHa responses.push_back( PasteIntoFolder { + clipboard, path: shallowest_common_folder.to_vec(), insert_index: -1, } .into(), ); } - PasteIntoFolder { path, insert_index } => { + PasteIntoFolder { clipboard, path, insert_index } => { let paste = |layer: &Layer, responses: &mut VecDeque<_>| { log::trace!("Pasting into folder {:?} as index: {}", path, insert_index); responses.push_back( @@ -359,11 +370,11 @@ impl MessageHandler for DocumentsMessageHa ) }; if insert_index == -1 { - for layer in self.copy_buffer.iter() { + for layer in self.copy_buffer[clipboard as usize].iter() { paste(layer, responses) } } else { - for layer in self.copy_buffer.iter().rev() { + for layer in self.copy_buffer[clipboard as usize].iter().rev() { paste(layer, responses) } } diff --git a/editor/src/document/mod.rs b/editor/src/document/mod.rs index 10d51550..843830cc 100644 --- a/editor/src/document/mod.rs +++ b/editor/src/document/mod.rs @@ -10,7 +10,7 @@ pub use document_file::LayerData; #[doc(inline)] pub use document_file::{AlignAggregate, AlignAxis, DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler, FlipAxis, VectorManipulatorSegment, VectorManipulatorShape}; #[doc(inline)] -pub use document_message_handler::{DocumentsMessage, DocumentsMessageDiscriminant, DocumentsMessageHandler}; +pub use document_message_handler::{Clipboard, DocumentsMessage, DocumentsMessageDiscriminant, DocumentsMessageHandler}; #[doc(inline)] pub use movement_handler::{MovementMessage, MovementMessageDiscriminant}; #[doc(inline)] diff --git a/editor/src/input/input_mapper.rs b/editor/src/input/input_mapper.rs index acb2312d..f5fc3654 100644 --- a/editor/src/input/input_mapper.rs +++ b/editor/src/input/input_mapper.rs @@ -4,6 +4,7 @@ use super::{ keyboard::{Key, KeyStates, NUMBER_OF_KEYS}, InputPreprocessor, }; +use crate::document::Clipboard::*; use crate::message_prelude::*; use crate::tool::ToolType; @@ -133,7 +134,7 @@ impl Default for Mapping { // it as an available action in the respective message handler file (such as the bottom of `document_message_handler.rs`) let mappings = mapping![ // Higher priority than entries in sections below - entry! {action=DocumentsMessage::Paste, key_down=KeyV, modifiers=[KeyControl]}, + entry! {action=DocumentsMessage::Paste(User), key_down=KeyV, modifiers=[KeyControl]}, entry! {action=MovementMessage::EnableSnapping, key_down=KeyShift}, entry! {action=MovementMessage::DisableSnapping, key_up=KeyShift}, // Transform layers @@ -207,7 +208,7 @@ impl Default for Mapping { // Editor Actions entry! {action=FrontendMessage::OpenDocumentBrowse, key_down=KeyO, modifiers=[KeyControl]}, // Document Actions - entry! {action=DocumentsMessage::Paste, key_down=KeyV, modifiers=[KeyControl]}, + entry! {action=DocumentsMessage::Paste(User), key_down=KeyV, modifiers=[KeyControl]}, entry! {action=DocumentMessage::Redo, key_down=KeyZ, modifiers=[KeyControl, KeyShift]}, entry! {action=DocumentMessage::Undo, key_down=KeyZ, modifiers=[KeyControl]}, entry! {action=DocumentMessage::DeselectAllLayers, key_down=KeyA, modifiers=[KeyControl, KeyAlt]}, @@ -252,7 +253,7 @@ impl Default for Mapping { entry! {action=DocumentsMessage::CloseAllDocumentsWithConfirmation, key_down=KeyW, modifiers=[KeyControl, KeyAlt]}, entry! {action=DocumentsMessage::CloseActiveDocumentWithConfirmation, key_down=KeyW, modifiers=[KeyControl]}, entry! {action=DocumentMessage::DuplicateSelectedLayers, key_down=KeyD, modifiers=[KeyControl]}, - entry! {action=DocumentsMessage::Copy, key_down=KeyC, modifiers=[KeyControl]}, + entry! {action=DocumentsMessage::Copy(User), key_down=KeyC, modifiers=[KeyControl]}, entry! {action=DocumentMessage::GroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl]}, // Nudging entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowLeft]},