mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-29 21:06:50 -06:00
Merge fix/680
This commit is contained in:
@@ -496,10 +496,15 @@ fn bump_name(n: &str) -> String {
|
||||
}
|
||||
|
||||
/// The copied form of the selection.
|
||||
pub fn copy_to_clipboard(s: &mut Session, ids: &[NodeId]) -> Result<()> {
|
||||
pub fn copy_to_clipboard(s: &mut Session, cmd: &str, ids: &[NodeId]) -> Result<()> {
|
||||
let ds = s.ds()?;
|
||||
let doc = &ds.doc;
|
||||
let ids = z_sorted(doc, &roots(doc, ids));
|
||||
// Pages are not layers: they can't be pasted anywhere.
|
||||
let layers: Vec<NodeId> = ids.iter().copied().filter(|i| !doc.node(*i).is_some_and(Node::is_page)).collect();
|
||||
if layers.is_empty() && !ids.is_empty() {
|
||||
return Err(EngineError::Disabled(cmd.into(), "pages can't be copied; use page.duplicate".into()));
|
||||
}
|
||||
let ids = z_sorted(doc, &roots(doc, &layers));
|
||||
let mut nodes = Vec::new();
|
||||
let mut images = BTreeMap::new();
|
||||
for i in &ids {
|
||||
@@ -535,14 +540,16 @@ pub fn copy_to_clipboard(s: &mut Session, ids: &[NodeId]) -> Result<()> {
|
||||
|
||||
fn copy(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let ids = req_targets("edit.copy", s, p)?;
|
||||
copy_to_clipboard(s, &ids)?;
|
||||
copy_to_clipboard(s, "edit.copy", &ids)?;
|
||||
Ok(json!({"copied": s.clipboard.nodes.len()}))
|
||||
}
|
||||
|
||||
fn cut(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let ids = req_targets("edit.cut", s, p)?;
|
||||
copy_to_clipboard(s, &ids)?;
|
||||
delete(s, &json!({"ids": ids}))
|
||||
copy_to_clipboard(s, "edit.cut", &ids)?;
|
||||
let doc = s.doc()?;
|
||||
let layers: Vec<NodeId> = ids.into_iter().filter(|i| !doc.node(*i).is_some_and(Node::is_page)).collect();
|
||||
delete(s, &json!({"ids": layers}))
|
||||
}
|
||||
|
||||
/// Paste the clipboard under `parent` with the copied top-left moved to `at` (page coords).
|
||||
|
||||
@@ -1611,6 +1611,8 @@ mod open_issues_tests;
|
||||
#[cfg(test)]
|
||||
mod outline_options_tests;
|
||||
#[cfg(test)]
|
||||
mod page_clipboard_tests;
|
||||
#[cfg(test)]
|
||||
mod page_copy_navigation_tests;
|
||||
#[cfg(test)]
|
||||
mod page_target_tests;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//! `edit.copy` / `edit.cut` skip pages (they aren't layers and can't be pasted), and refuse a
|
||||
//! selection of only pages under their own command id.
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{EngineError, Session};
|
||||
|
||||
#[test]
|
||||
fn copy_and_cut_ignore_pages_so_paste_keeps_the_document_valid() {
|
||||
for cmd in ["edit.copy", "edit.cut"] {
|
||||
let mut s = Session::new();
|
||||
let page = s.page().unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap();
|
||||
match s.execute(cmd, &json!({"ids": [page.0]})) {
|
||||
Err(EngineError::Disabled(id, _)) => assert_eq!(id, cmd),
|
||||
r => panic!("{cmd} on a page: {r:?}"),
|
||||
}
|
||||
let _ = s.execute("edit.paste", &json!({}));
|
||||
let doc = s.doc().unwrap();
|
||||
assert!(doc.validate().is_empty(), "{cmd}: {:?}", doc.validate());
|
||||
assert!(doc.node(page).is_some(), "{cmd} removed the page");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cut_of_a_page_and_a_layer_moves_only_the_layer() {
|
||||
let mut s = Session::new();
|
||||
let page = s.page().unwrap();
|
||||
let r = s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap();
|
||||
let rect = crate::params::id_of(&r["id"]).unwrap();
|
||||
s.execute("edit.cut", &json!({"ids": [page.0, rect.0]})).unwrap();
|
||||
assert!(s.doc().unwrap().node(page).is_some());
|
||||
assert!(s.doc().unwrap().node(rect).is_none());
|
||||
s.execute("edit.paste", &json!({})).unwrap();
|
||||
assert!(s.doc().unwrap().validate().is_empty());
|
||||
}
|
||||
Reference in New Issue
Block a user