mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 06:08:11 +08:00
Copy and paste layers MVP (#220)
* Initial implementation of copy and paste for layers * Sort layers on copy and add tests * Fix logger init for test * Fix `copy_paste_deleted_layers` test * Readd erroneously removed svg * Make Layer serializable and cleanup * Add test for copy and pasting folders * Cleanup * Rename left_mouseup * Cleanup * Add length check to test * Fix typo * Make mouseup, mousedown more consistent
This commit is contained in:
@@ -76,3 +76,228 @@ impl Dispatcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
message_prelude::{DocumentMessage, Message},
|
||||
misc::test_utils::EditorTestUtils,
|
||||
Editor,
|
||||
};
|
||||
use document_core::{color::Color, Operation};
|
||||
use log::info;
|
||||
|
||||
fn init_logger() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
}
|
||||
|
||||
/// Create an editor instance with three layers
|
||||
/// 1. A red rectangle
|
||||
/// 2. A blue shape
|
||||
/// 3. A green ellipse
|
||||
fn create_editor_with_three_layers() -> Editor {
|
||||
let mut editor = Editor::new(Box::new(|e| {
|
||||
info!("Got frontend message: {:?}", e);
|
||||
}));
|
||||
|
||||
editor.select_primary_color(Color::RED);
|
||||
editor.draw_rect(100, 200, 300, 400);
|
||||
editor.select_primary_color(Color::BLUE);
|
||||
editor.draw_shape(10, 1200, 1300, 400);
|
||||
editor.select_primary_color(Color::GREEN);
|
||||
editor.draw_ellipse(104, 1200, 1300, 400);
|
||||
|
||||
editor
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// - create rect, shape and ellipse
|
||||
/// - copy
|
||||
/// - paste
|
||||
/// - assert that ellipse was copied
|
||||
fn copy_paste_single_layer() {
|
||||
init_logger();
|
||||
let mut editor = create_editor_with_three_layers();
|
||||
|
||||
let document_before_copy = editor.dispatcher.document_message_handler.active_document().document.clone();
|
||||
editor.handle_message(Message::Document(DocumentMessage::CopySelectedLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::PasteLayers)).unwrap();
|
||||
let document_after_copy = editor.dispatcher.document_message_handler.active_document().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();
|
||||
|
||||
assert_eq!(layers_before_copy.len(), 3);
|
||||
assert_eq!(layers_after_copy.len(), 4);
|
||||
|
||||
// Existing layers are unaffected
|
||||
for i in 0..=2 {
|
||||
assert_eq!(layers_before_copy[i], layers_after_copy[i]);
|
||||
}
|
||||
|
||||
// The ellipse was copied
|
||||
assert_eq!(layers_before_copy[2], layers_after_copy[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// - create rect, shape and ellipse
|
||||
/// - select shape
|
||||
/// - copy
|
||||
/// - paste
|
||||
/// - assert that shape was copied
|
||||
fn copy_paste_single_layer_from_middle() {
|
||||
init_logger();
|
||||
let mut editor = create_editor_with_three_layers();
|
||||
|
||||
let document_before_copy = editor.dispatcher.document_message_handler.active_document().document.clone();
|
||||
let shape_id = document_before_copy.root.as_folder().unwrap().layer_ids[1];
|
||||
|
||||
editor.handle_message(Message::Document(DocumentMessage::SelectLayers(vec![vec![shape_id]]))).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::CopySelectedLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::PasteLayers)).unwrap();
|
||||
|
||||
let document_after_copy = editor.dispatcher.document_message_handler.active_document().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();
|
||||
|
||||
assert_eq!(layers_before_copy.len(), 3);
|
||||
assert_eq!(layers_after_copy.len(), 4);
|
||||
|
||||
// Existing layers are unaffected
|
||||
for i in 0..=2 {
|
||||
assert_eq!(layers_before_copy[i], layers_after_copy[i]);
|
||||
}
|
||||
|
||||
// The shape was copied
|
||||
assert_eq!(layers_before_copy[1], layers_after_copy[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_paste_folder() {
|
||||
init_logger();
|
||||
let mut editor = create_editor_with_three_layers();
|
||||
|
||||
const FOLDER_INDEX: usize = 3;
|
||||
const ELLIPSE_INDEX: usize = 2;
|
||||
const SHAPE_INDEX: usize = 1;
|
||||
const RECT_INDEX: usize = 0;
|
||||
|
||||
const LINE_INDEX: usize = 0;
|
||||
const PEN_INDEX: usize = 1;
|
||||
|
||||
editor.handle_message(Message::Document(DocumentMessage::AddFolder(vec![]))).unwrap();
|
||||
|
||||
let document_before_added_shapes = editor.dispatcher.document_message_handler.active_document().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.
|
||||
// This has not been done yet as the line and pen tool are not yet able to add layers to the currently selected folder
|
||||
editor
|
||||
.handle_message(Message::Document(DocumentMessage::DispatchOperation(Operation::AddLine {
|
||||
path: vec![folder_id],
|
||||
insert_index: 0,
|
||||
transform: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
style: Default::default(),
|
||||
})))
|
||||
.unwrap();
|
||||
|
||||
editor
|
||||
.handle_message(Message::Document(DocumentMessage::DispatchOperation(Operation::AddPen {
|
||||
path: vec![folder_id],
|
||||
insert_index: 0,
|
||||
transform: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
style: Default::default(),
|
||||
points: vec![(10.0, 20.0), (30.0, 40.0)],
|
||||
})))
|
||||
.unwrap();
|
||||
|
||||
editor.handle_message(Message::Document(DocumentMessage::SelectLayers(vec![vec![folder_id]]))).unwrap();
|
||||
|
||||
let document_before_copy = editor.dispatcher.document_message_handler.active_document().document.clone();
|
||||
|
||||
editor.handle_message(Message::Document(DocumentMessage::CopySelectedLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::DeleteSelectedLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::PasteLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::PasteLayers)).unwrap();
|
||||
|
||||
let document_after_copy = editor.dispatcher.document_message_handler.active_document().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();
|
||||
|
||||
assert_eq!(layers_before_copy.len(), 4);
|
||||
assert_eq!(layers_after_copy.len(), 5);
|
||||
|
||||
let rect_before_copy = &layers_before_copy[RECT_INDEX];
|
||||
let ellipse_before_copy = &layers_before_copy[ELLIPSE_INDEX];
|
||||
let shape_before_copy = &layers_before_copy[SHAPE_INDEX];
|
||||
let folder_before_copy = &layers_before_copy[FOLDER_INDEX];
|
||||
let line_before_copy = folder_before_copy.as_folder().unwrap().layers()[LINE_INDEX].clone();
|
||||
let pen_before_copy = folder_before_copy.as_folder().unwrap().layers()[PEN_INDEX].clone();
|
||||
|
||||
assert_eq!(&layers_after_copy[0], rect_before_copy);
|
||||
assert_eq!(&layers_after_copy[1], shape_before_copy);
|
||||
assert_eq!(&layers_after_copy[2], ellipse_before_copy);
|
||||
assert_eq!(&layers_after_copy[3], folder_before_copy);
|
||||
assert_eq!(&layers_after_copy[4], folder_before_copy);
|
||||
|
||||
// Check the layers inside the two folders
|
||||
let first_folder_layers_after_copy = layers_after_copy[3].as_folder().unwrap().layers();
|
||||
let second_folder_layers_after_copy = layers_after_copy[4].as_folder().unwrap().layers();
|
||||
|
||||
assert_eq!(first_folder_layers_after_copy.len(), 2);
|
||||
assert_eq!(second_folder_layers_after_copy.len(), 2);
|
||||
|
||||
assert_eq!(first_folder_layers_after_copy[0], line_before_copy);
|
||||
assert_eq!(first_folder_layers_after_copy[1], pen_before_copy);
|
||||
|
||||
assert_eq!(second_folder_layers_after_copy[0], line_before_copy);
|
||||
assert_eq!(second_folder_layers_after_copy[1], pen_before_copy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// - create rect, shape and ellipse
|
||||
/// - select ellipse and rect
|
||||
/// - copy
|
||||
/// - delete
|
||||
/// - create another rect
|
||||
/// - paste
|
||||
/// - paste
|
||||
fn copy_paste_deleted_layers() {
|
||||
init_logger();
|
||||
let mut editor = create_editor_with_three_layers();
|
||||
|
||||
const ELLIPSE_INDEX: usize = 2;
|
||||
const SHAPE_INDEX: usize = 1;
|
||||
const RECT_INDEX: usize = 0;
|
||||
|
||||
let document_before_copy = editor.dispatcher.document_message_handler.active_document().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];
|
||||
|
||||
editor.handle_message(Message::Document(DocumentMessage::SelectLayers(vec![vec![rect_id], vec![ellipse_id]]))).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::CopySelectedLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::DeleteSelectedLayers)).unwrap();
|
||||
editor.draw_rect(0, 800, 12, 200);
|
||||
editor.handle_message(Message::Document(DocumentMessage::PasteLayers)).unwrap();
|
||||
editor.handle_message(Message::Document(DocumentMessage::PasteLayers)).unwrap();
|
||||
|
||||
let document_after_copy = editor.dispatcher.document_message_handler.active_document().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();
|
||||
|
||||
assert_eq!(layers_before_copy.len(), 3);
|
||||
assert_eq!(layers_after_copy.len(), 6);
|
||||
|
||||
let rect_before_copy = &layers_before_copy[RECT_INDEX];
|
||||
let ellipse_before_copy = &layers_before_copy[ELLIPSE_INDEX];
|
||||
|
||||
assert_eq!(layers_after_copy[0], layers_before_copy[SHAPE_INDEX]);
|
||||
assert_eq!(&layers_after_copy[2], rect_before_copy);
|
||||
assert_eq!(&layers_after_copy[3], ellipse_before_copy);
|
||||
assert_eq!(&layers_after_copy[4], rect_before_copy);
|
||||
assert_eq!(&layers_after_copy[5], ellipse_before_copy);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user