mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 19:27:21 -06:00
Artboards: copied artboards take a free id and keep their own guides
Duplicate Artboards, the Artboard tool's Alt-drag (artboard.move with copy) and Paste of a copied artboard gave the new artboard the largest artboard id plus one, saturating. In a document with an artboard id of 4,294,967,295 (u32::MAX), which only a hand-made file has, the copy got that same id. Artboard guides record the id of their artboard. Deleting either of the two artboards with that id then deleted the guides of both, and guide.list reported the copy's guides on the other one. push_artboard_copy now takes the id from Document::next_artboard_id, as artboard.new and Convert to Artboards do. Since the #1718 fix, that function returns the smallest free id when the largest is u32::MAX. In a document whose artboard ids are all below u32::MAX, a copy gets the same id as before. Docs: docs/target-app-parity.md.
This commit is contained in:
@@ -166,7 +166,7 @@ pub(crate) fn copy_artboard(d: &mut vectorcraft_doc::Document, i: usize, dv: Vec
|
||||
/// (`<name> copy 2`…) when that is taken → its index.
|
||||
pub(crate) fn push_artboard_copy(d: &mut vectorcraft_doc::Document, src: &vectorcraft_doc::Artboard, rect: Rect) -> usize {
|
||||
let mut a = src.clone();
|
||||
a.id = d.artboards.iter().map(|a| a.id).max().unwrap_or(0).saturating_add(1);
|
||||
a.id = d.next_artboard_id();
|
||||
let taken = |name: &str| d.artboards.iter().any(|a| a.name == name);
|
||||
a.name = [src.name.clone(), format!("{} copy", src.name)]
|
||||
.into_iter()
|
||||
|
||||
@@ -197,6 +197,48 @@ fn artboard_tool_cut_removes_the_artboard_and_its_art() {
|
||||
assert_eq!((d.artboards.len(), d.node(r).is_some()), (2, true), "the cut is one undo step");
|
||||
}
|
||||
|
||||
/// A copy of an artboard whose id is the largest there is (only a hand-made file has one, #1718)
|
||||
/// takes an id that no other artboard has, as a new artboard does, whether Duplicate Artboards, the
|
||||
/// Artboard tool's Alt-drag (`artboard.move` with `copy`) or Paste makes it. Deleting either
|
||||
/// artboard then leaves the other's guides.
|
||||
#[test]
|
||||
fn copied_artboards_take_a_free_id_and_keep_their_own_guides() {
|
||||
let mut got = vec![];
|
||||
for (cmd, p) in [
|
||||
("artboard.duplicate", json!({"index": 0})),
|
||||
("artboard.move", json!({"index": 0, "dx": 0, "dy": 900, "copy": true})),
|
||||
("edit.paste", json!({})),
|
||||
] {
|
||||
let mut s = Session::new();
|
||||
let mut d = vectorcraft_doc::Document::new(800.0, 600.0);
|
||||
d.artboards[0].id = u32::MAX;
|
||||
s.add_document(d, None);
|
||||
s.execute("guide.add", &json!({"vertical": true, "pos": 100, "artboard": 0})).unwrap();
|
||||
if cmd == "edit.paste" {
|
||||
s.execute("artboard.copy", &json!({"index": 0})).unwrap();
|
||||
}
|
||||
s.execute(cmd, &p).unwrap();
|
||||
// Each pass deletes one artboard (the copy, then the original), adds the artboard ids of
|
||||
// the remaining guides to `kept`, and undoes the delete.
|
||||
let mut kept = vec![];
|
||||
for i in [1, 0] {
|
||||
s.execute("artboard.delete", &json!({"index": i})).unwrap();
|
||||
kept.push(s.doc().unwrap().doc.guides.iter().map(|g| g.artboard).collect::<Vec<_>>());
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
}
|
||||
got.push((cmd, s.doc().unwrap().doc.artboards.iter().map(|a| a.id).collect::<Vec<_>>(), kept));
|
||||
}
|
||||
let max = Some(u32::MAX);
|
||||
assert_eq!(
|
||||
got,
|
||||
[
|
||||
("artboard.duplicate", vec![u32::MAX, 1], vec![vec![max], vec![Some(1)]]),
|
||||
("artboard.move", vec![u32::MAX, 1], vec![vec![max], vec![Some(1)]]),
|
||||
("edit.paste", vec![u32::MAX, 1], vec![vec![max], vec![]]),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swatch_groups_duplicate_sort() {
|
||||
let mut s = session();
|
||||
|
||||
Reference in New Issue
Block a user