Skip to content

Commit

Permalink
Copy and paste layers MVP (#220)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
tillarnold authored Jul 4, 2021
1 parent 7b65409 commit 20420c1
Show file tree
Hide file tree
Showing 17 changed files with 568 additions and 32 deletions.
142 changes: 131 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions core/document/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ license = "Apache-2.0"

[dependencies]
log = "0.4"
kurbo = "0.8"

kurbo = {version="0.8", features = ["serde"]}
serde = { version = "1.0", features = ["derive"] }
glam = "0.16"
glam = { version = "0.16", features = ["serde"] }
31 changes: 31 additions & 0 deletions core/document/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ impl Document {
self.folder(path)?.layer(id).ok_or(DocumentError::LayerNotFound)
}

/// Given a path to a layer, returns a vector of the indices in the layer tree
/// These indices can be used to order a list of layers
pub fn indices_for_path(&self, mut path: &[LayerId]) -> Result<Vec<usize>, DocumentError> {
let mut root = if self.is_mounted(self.work_mount_path.as_slice(), path) {
path = &path[self.work_mount_path.len()..];
&self.work
} else {
&self.root
}
.as_folder()?;
let mut indices = vec![];
let (path, layer_id) = split_path(path)?;

for id in path {
let pos = root.layer_ids.iter().position(|x| *x == *id).ok_or(DocumentError::LayerNotFound)?;
indices.push(pos);
root = root.folder(*id).ok_or(DocumentError::LayerNotFound)?;
}

indices.push(root.layer_ids.iter().position(|x| *x == layer_id).ok_or(DocumentError::LayerNotFound)?);

Ok(indices)
}

/// Returns a mutable reference to the layer struct at the specified `path`.
/// If you manually edit the layer you have to set the cache_dirty flag yourself.
pub fn layer_mut(&mut self, path: &[LayerId]) -> Result<&mut Layer, DocumentError> {
Expand Down Expand Up @@ -227,6 +251,13 @@ impl Document {
let (path, _) = split_path(path.as_slice()).unwrap_or_else(|_| (&[], 0));
Some(vec![DocumentResponse::DocumentChanged, DocumentResponse::FolderChanged { path: path.to_vec() }])
}
Operation::PasteLayer { path, layer } => {
let folder = self.folder_mut(path)?;
//FIXME: This clone of layer should be avoided somehow
folder.add_layer(layer.clone(), -1).ok_or(DocumentError::IndexOutOfBounds)?;

Some(vec![DocumentResponse::DocumentChanged, DocumentResponse::FolderChanged { path: path.clone() }])
}
Operation::DuplicateLayer { path } => {
let layer = self.layer(&path)?.clone();
let (folder_path, _) = split_path(path.as_slice()).unwrap_or_else(|_| (&[], 0));
Expand Down
3 changes: 2 additions & 1 deletion core/document/src/layers/ellipse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use kurbo::Shape;
use super::style;
use super::LayerData;

use serde::{Deserialize, Serialize};
use std::fmt::Write;

#[derive(Debug, Clone, Copy, PartialEq, Default)]
#[derive(Debug, Clone, Copy, PartialEq, Default, Deserialize, Serialize)]
pub struct Ellipse {}

impl Ellipse {
Expand Down
3 changes: 2 additions & 1 deletion core/document/src/layers/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use crate::{DocumentError, LayerId};

use super::{style, Layer, LayerData, LayerDataTypes};

use serde::{Deserialize, Serialize};
use std::fmt::Write;

#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Folder {
next_assignment_id: LayerId,
pub layer_ids: Vec<LayerId>,
Expand Down
3 changes: 2 additions & 1 deletion core/document/src/layers/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use kurbo::Point;
use super::style;
use super::LayerData;

use serde::{Deserialize, Serialize};
use std::fmt::Write;

#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub struct Line {}

impl Line {
Expand Down
17 changes: 13 additions & 4 deletions core/document/src/layers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod ellipse;
pub use ellipse::Ellipse;

pub mod line;
use glam::{DMat2, DVec2};
use kurbo::BezPath;
pub use line::Line;

Expand All @@ -17,16 +18,16 @@ pub mod shape;
pub use shape::Shape;

pub mod folder;
pub use folder::Folder;

use crate::DocumentError;
pub use folder::Folder;
use serde::{Deserialize, Serialize};

pub trait LayerData {
fn render(&mut self, svg: &mut String, transform: glam::DAffine2, style: style::PathStyle);
fn to_kurbo_path(&mut self, transform: glam::DAffine2, style: style::PathStyle) -> BezPath;
}

#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum LayerDataTypes {
Folder(Folder),
Ellipse(Ellipse),
Expand Down Expand Up @@ -77,11 +78,19 @@ impl LayerDataTypes {
}
}

#[derive(Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(remote = "glam::DAffine2")]
struct DAffine2Ref {
pub matrix2: DMat2,
pub translation: DVec2,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Layer {
pub visible: bool,
pub name: Option<String>,
pub data: LayerDataTypes,
#[serde(with = "DAffine2Ref")]
pub transform: glam::DAffine2,
pub style: style::PathStyle,
pub cache: String,
Expand Down
3 changes: 2 additions & 1 deletion core/document/src/layers/polyline.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use serde::{Deserialize, Serialize};
use std::fmt::Write;

use super::{style, LayerData};

#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct PolyLine {
points: Vec<glam::DVec2>,
}
Expand Down
Loading

0 comments on commit 20420c1

Please sign in to comment.