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 <keavon@keavon.com>

* Fix line centering (#431)

* cargo fmt

Co-authored-by: 0HyperCube <78500760+0HyperCube@users.noreply.github.com>
This commit is contained in:
TrueDoctor
2021-12-27 21:17:41 -08:00
committed by Keavon Chambers
co-authored by Keavon Chambers 0HyperCube
parent e09a606285
commit 1eb83d92c4
5 changed files with 80 additions and 29 deletions
+41 -11
View File
@@ -96,7 +96,13 @@ impl Dispatcher {
#[cfg(test)] #[cfg(test)]
mod 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}; use graphene::{color::Color, Operation};
fn init_logger() { fn init_logger() {
@@ -131,8 +137,12 @@ mod test {
let mut editor = create_editor_with_three_layers(); let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone(); 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(DocumentsMessage::PasteIntoFolder { 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(); 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(); 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]; 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(DocumentMessage::SetSelectedLayers(vec![vec![shape_id]]));
editor.handle_message(DocumentsMessage::Copy); editor.handle_message(DocumentsMessage::Copy(User));
editor.handle_message(DocumentsMessage::PasteIntoFolder { 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(); 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(); 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(DocumentMessage::DeleteSelectedLayers);
editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); editor.handle_message(DocumentsMessage::PasteIntoFolder {
editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); 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(); 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]; 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(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.handle_message(DocumentMessage::DeleteSelectedLayers);
editor.draw_rect(0., 800., 12., 200.); editor.draw_rect(0., 800., 12., 200.);
editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); editor.handle_message(DocumentsMessage::PasteIntoFolder {
editor.handle_message(DocumentsMessage::PasteIntoFolder { path: vec![], insert_index: -1 }); 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(); let document_after_copy = editor.dispatcher.documents_message_handler.active_document().graphene_document.clone();
+12 -3
View File
@@ -7,6 +7,7 @@ use super::transform_layer_handler::{TransformLayerMessage, TransformLayerMessag
use crate::consts::DEFAULT_DOCUMENT_NAME; use crate::consts::DEFAULT_DOCUMENT_NAME;
use crate::consts::{ASYMPTOTIC_EFFECT, FILE_EXPORT_SUFFIX, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING}; 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::input::InputPreprocessor;
use crate::message_prelude::*; use crate::message_prelude::*;
use crate::EditorError; use crate::EditorError;
@@ -541,12 +542,13 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
let mut new_folder_path = common_prefix.to_vec(); let mut new_folder_path = common_prefix.to_vec();
new_folder_path.push(generate_uuid()); 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(DocumentMessage::DeleteSelectedLayers.into());
responses.push_back(DocumentOperation::CreateFolder { path: new_folder_path.clone() }.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(DocumentMessage::ToggleLayerExpansion(new_folder_path.clone()).into());
responses.push_back( responses.push_back(
DocumentsMessage::PasteIntoFolder { DocumentsMessage::PasteIntoFolder {
clipboard: Clipboard::System,
path: new_folder_path.clone(), path: new_folder_path.clone(),
insert_index: -1, insert_index: -1,
} }
@@ -792,9 +794,16 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
responses.push_back(ToolMessage::SelectedLayersChanged.into()); responses.push_back(ToolMessage::SelectedLayersChanged.into());
} }
MoveSelectedLayersTo { path, insert_index } => { 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(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) => { ReorderSelectedLayers(relative_position) => {
self.backup(responses); self.backup(responses);
+22 -11
View File
@@ -10,15 +10,25 @@ use std::collections::{HashMap, VecDeque};
use super::DocumentMessageHandler; use super::DocumentMessageHandler;
use crate::consts::DEFAULT_DOCUMENT_NAME; 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)] #[impl_message(Message, Documents)]
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] #[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum DocumentsMessage { pub enum DocumentsMessage {
Copy, Copy(Clipboard),
PasteIntoFolder { PasteIntoFolder {
clipboard: Clipboard,
path: Vec<LayerId>, path: Vec<LayerId>,
insert_index: isize, insert_index: isize,
}, },
Paste, Paste(Clipboard),
SelectDocument(u64), SelectDocument(u64),
CloseDocument(u64), CloseDocument(u64),
#[child] #[child]
@@ -49,7 +59,7 @@ pub struct DocumentsMessageHandler {
documents: HashMap<u64, DocumentMessageHandler>, documents: HashMap<u64, DocumentMessageHandler>,
document_ids: Vec<u64>, document_ids: Vec<u64>,
active_document_id: u64, active_document_id: u64,
copy_buffer: Vec<Layer>, copy_buffer: Vec<Vec<Layer>>,
} }
impl DocumentsMessageHandler { impl DocumentsMessageHandler {
@@ -139,7 +149,7 @@ impl Default for DocumentsMessageHandler {
Self { Self {
documents: documents_map, documents: documents_map,
document_ids: vec![starting_key], document_ids: vec![starting_key],
copy_buffer: vec![], copy_buffer: vec![vec![]; CLIPBOARD_COUNT as usize],
active_document_id: starting_key, active_document_id: starting_key,
} }
} }
@@ -319,19 +329,19 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
let prev_id = self.document_ids[prev_index]; let prev_id = self.document_ids[prev_index];
responses.push_back(DocumentsMessage::SelectDocument(prev_id).into()); responses.push_back(DocumentsMessage::SelectDocument(prev_id).into());
} }
Copy => { Copy(clipboard) => {
let paths = self.active_document().selected_layers_sorted(); let paths = self.active_document().selected_layers_sorted();
self.copy_buffer.clear(); self.copy_buffer[clipboard as usize].clear();
for path in paths { for path in paths {
match self.active_document().graphene_document.layer(&path).map(|t| t.clone()) { match self.active_document().graphene_document.layer(&path).map(|t| t.clone()) {
Ok(layer) => { 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), Err(e) => warn!("Could not access selected layer {:?}: {:?}", path, e),
} }
} }
} }
Paste => { Paste(clipboard) => {
let document = self.active_document(); let document = self.active_document();
let shallowest_common_folder = document let shallowest_common_folder = document
.graphene_document .graphene_document
@@ -340,13 +350,14 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
responses.push_back( responses.push_back(
PasteIntoFolder { PasteIntoFolder {
clipboard,
path: shallowest_common_folder.to_vec(), path: shallowest_common_folder.to_vec(),
insert_index: -1, insert_index: -1,
} }
.into(), .into(),
); );
} }
PasteIntoFolder { path, insert_index } => { PasteIntoFolder { clipboard, path, insert_index } => {
let paste = |layer: &Layer, responses: &mut VecDeque<_>| { let paste = |layer: &Layer, responses: &mut VecDeque<_>| {
log::trace!("Pasting into folder {:?} as index: {}", path, insert_index); log::trace!("Pasting into folder {:?} as index: {}", path, insert_index);
responses.push_back( responses.push_back(
@@ -359,11 +370,11 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
) )
}; };
if insert_index == -1 { if insert_index == -1 {
for layer in self.copy_buffer.iter() { for layer in self.copy_buffer[clipboard as usize].iter() {
paste(layer, responses) paste(layer, responses)
} }
} else { } else {
for layer in self.copy_buffer.iter().rev() { for layer in self.copy_buffer[clipboard as usize].iter().rev() {
paste(layer, responses) paste(layer, responses)
} }
} }
+1 -1
View File
@@ -10,7 +10,7 @@ pub use document_file::LayerData;
#[doc(inline)] #[doc(inline)]
pub use document_file::{AlignAggregate, AlignAxis, DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler, FlipAxis, VectorManipulatorSegment, VectorManipulatorShape}; pub use document_file::{AlignAggregate, AlignAxis, DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler, FlipAxis, VectorManipulatorSegment, VectorManipulatorShape};
#[doc(inline)] #[doc(inline)]
pub use document_message_handler::{DocumentsMessage, DocumentsMessageDiscriminant, DocumentsMessageHandler}; pub use document_message_handler::{Clipboard, DocumentsMessage, DocumentsMessageDiscriminant, DocumentsMessageHandler};
#[doc(inline)] #[doc(inline)]
pub use movement_handler::{MovementMessage, MovementMessageDiscriminant}; pub use movement_handler::{MovementMessage, MovementMessageDiscriminant};
#[doc(inline)] #[doc(inline)]
+4 -3
View File
@@ -4,6 +4,7 @@ use super::{
keyboard::{Key, KeyStates, NUMBER_OF_KEYS}, keyboard::{Key, KeyStates, NUMBER_OF_KEYS},
InputPreprocessor, InputPreprocessor,
}; };
use crate::document::Clipboard::*;
use crate::message_prelude::*; use crate::message_prelude::*;
use crate::tool::ToolType; 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`) // it as an available action in the respective message handler file (such as the bottom of `document_message_handler.rs`)
let mappings = mapping![ let mappings = mapping![
// Higher priority than entries in sections below // 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::EnableSnapping, key_down=KeyShift},
entry! {action=MovementMessage::DisableSnapping, key_up=KeyShift}, entry! {action=MovementMessage::DisableSnapping, key_up=KeyShift},
// Transform layers // Transform layers
@@ -207,7 +208,7 @@ impl Default for Mapping {
// Editor Actions // Editor Actions
entry! {action=FrontendMessage::OpenDocumentBrowse, key_down=KeyO, modifiers=[KeyControl]}, entry! {action=FrontendMessage::OpenDocumentBrowse, key_down=KeyO, modifiers=[KeyControl]},
// Document Actions // 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::Redo, key_down=KeyZ, modifiers=[KeyControl, KeyShift]},
entry! {action=DocumentMessage::Undo, key_down=KeyZ, modifiers=[KeyControl]}, entry! {action=DocumentMessage::Undo, key_down=KeyZ, modifiers=[KeyControl]},
entry! {action=DocumentMessage::DeselectAllLayers, key_down=KeyA, modifiers=[KeyControl, KeyAlt]}, 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::CloseAllDocumentsWithConfirmation, key_down=KeyW, modifiers=[KeyControl, KeyAlt]},
entry! {action=DocumentsMessage::CloseActiveDocumentWithConfirmation, key_down=KeyW, modifiers=[KeyControl]}, entry! {action=DocumentsMessage::CloseActiveDocumentWithConfirmation, key_down=KeyW, modifiers=[KeyControl]},
entry! {action=DocumentMessage::DuplicateSelectedLayers, key_down=KeyD, 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]}, entry! {action=DocumentMessage::GroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl]},
// Nudging // Nudging
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowLeft]}, entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowLeft]},