mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 12:17:14 -06:00
Fix #3705: pastes go inside the object in Draw Inside, and Shift+D no longer stops at Draw Behind
The drawing-modes help page (https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/learn-drawing-basics/drawing-modes-overview.html) has you draw or paste into the selected object in Draw Inside. It also says the modes apply to Paste in Place and Paste on All Artboards but not to Paste in Front or Paste in Back. Cause: only new art (create::insert_look) read the drawing mode. The paste commands (edit::paste_clip) always used the insertion parent, so a paste in Draw Inside landed on the layer above the object, outside the clip. Double-clicking the object first only isolated the bare path, which didn't change where the paste went. Separately, view.drawMode {} went from Draw Behind to Draw Inside whenever one object was selected, then refused it unless the object was a path, compound path or type. So with one group selected (such as the clip group Draw Inside makes), Shift+D and the toolbar button failed every time and stayed in Draw Behind. Change: the clip-group wrapping moves into create::draw_inside_group, which new art and pastes now share. In Draw Inside, Paste, Paste in Place and Paste on All Artboards insert the copies at the top of that group, in the paste's one undo step, ignoring Paste Remembers Layers. In Draw Behind, Paste in Place and Paste on All Artboards go just below the selection, as Paste in Back does. Paste in Front, Paste in Back and pasted artboards keep their placement. Shift+D goes on to Draw Inside only when it can draw into the selection, and otherwise back to Draw Normal. Verification: pasting_in_draw_inside_puts_the_copies_inside_the_object, paste_in_place_in_draw_behind_goes_behind_the_selection and shift_d_goes_past_draw_behind_whatever_is_selected all fail without the change ("Layer" != "Clip Group"; index 3 != 0; the Draw Inside error on a selected group). cargo xtask ci: all 10 steps passed.
This commit is contained in:
committed by
bflatastic
parent
a537a1b5bd
commit
eb4635fd4b
@@ -148,6 +148,120 @@ fn double_clicking_outside_the_draw_inside_object_returns_to_draw_normal() {
|
||||
assert_eq!(double(&mut s, 150.0, 150.0), (DrawMode::Normal, None));
|
||||
}
|
||||
|
||||
/// #3705: in Draw Inside, Paste, Paste in Place and Paste on All Artboards put the copies inside
|
||||
/// the object drawn into, as drawn art goes, each paste one undo step; the first one makes the
|
||||
/// clip group and the next ones add to it, with Paste Remembers Layers on and with the object
|
||||
/// isolated by a double-click too. Paste in Front and Paste in Back keep their places.
|
||||
#[test]
|
||||
fn pasting_in_draw_inside_puts_the_copies_inside_the_object() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 400, "height": 300, "artboards": 2})).unwrap();
|
||||
let a = s.execute("shape.rectangle", &json!({"x": 100, "y": 100, "width": 100, "height": 100})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("shape.ellipse", &json!({"x": 20, "y": 20, "width": 50, "height": 50})).unwrap();
|
||||
s.execute("edit.copy", &json!({})).unwrap();
|
||||
s.execute("select.set", &json!({"ids": [a]})).unwrap();
|
||||
s.execute("view.drawMode", &json!({"mode": "inside"})).unwrap();
|
||||
let parent = |s: &Session, id: u64| s.doc().unwrap().doc.parent_of(NodeId(id));
|
||||
let pasted = |r: Value| r["ids"].as_array().unwrap().iter().map(|v| v.as_u64().unwrap()).collect::<Vec<_>>();
|
||||
let before = s.doc().unwrap().doc.clone();
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
let ids = pasted(s.execute("edit.paste", &json!({"center": [150, 150]})).unwrap());
|
||||
let g = parent(&s, a).unwrap();
|
||||
assert_eq!(s.doc().unwrap().doc.node(g).unwrap().kind_label(), "Clip Group");
|
||||
assert_eq!(parent(&s, ids[0]), Some(g), "the copy is inside the object");
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), undo + 1);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(*s.doc().unwrap().doc, *before, "one undo step takes the copy and the clip group away");
|
||||
s.execute("edit.redo", &json!({})).unwrap();
|
||||
// Paste in Place and Paste on All Artboards (one copy per artboard) go into the same group,
|
||||
// on top of what is in it.
|
||||
let in_place = pasted(s.execute("edit.pasteInPlace", &json!({})).unwrap());
|
||||
let all = pasted(s.execute("edit.pasteOnAllArtboards", &json!({})).unwrap());
|
||||
assert_eq!(all.len(), 2);
|
||||
let children: Vec<u64> = s.doc().unwrap().doc.node(g).unwrap().children().unwrap().iter().map(|n| n.id.0).collect();
|
||||
assert_eq!(children.len(), 6, "{children:?}");
|
||||
assert_eq!(children[1..], [a, ids[0], in_place[0], all[0], all[1]]);
|
||||
// Paste Remembers Layers doesn't take the copy out of the object.
|
||||
s.execute("layer.pasteRemembersLayers", &json!({"on": true})).unwrap();
|
||||
let remembered = pasted(s.execute("edit.paste", &json!({})).unwrap());
|
||||
assert_eq!(parent(&s, remembered[0]), Some(g));
|
||||
// Paste in Front and Paste in Back ignore the drawing mode: next to the selection.
|
||||
s.execute("layer.pasteRemembersLayers", &json!({"on": false})).unwrap();
|
||||
s.execute("select.set", &json!({"ids": [a]})).unwrap();
|
||||
let front = pasted(s.execute("edit.pasteInFront", &json!({})).unwrap());
|
||||
assert_eq!(parent(&s, front[0]), Some(g));
|
||||
let d = &s.doc().unwrap().doc;
|
||||
let at = |id: u64| d.position(NodeId(id)).unwrap().1;
|
||||
assert_eq!(at(front[0]), at(a) + 1, "just above the selected object");
|
||||
// The object isolated (a double-click with the Selection tool) before anything went inside.
|
||||
let mut s = session();
|
||||
let b = s.execute("shape.rectangle", &json!({"x": 100, "y": 100, "width": 100, "height": 100})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("shape.ellipse", &json!({"x": 20, "y": 20, "width": 50, "height": 50})).unwrap();
|
||||
s.execute("edit.copy", &json!({})).unwrap();
|
||||
s.execute("select.set", &json!({"ids": [b]})).unwrap();
|
||||
s.execute("view.drawMode", &json!({"mode": "inside"})).unwrap();
|
||||
s.select_tool("selection", ViewInfo::default()).unwrap();
|
||||
s.pointer(&vectorcraft_tools::PointerEvent::new(vectorcraft_tools::PointerKind::DoubleClick, 150.0, 150.0), ViewInfo::default()).unwrap();
|
||||
assert_eq!(s.doc().unwrap().isolation, Some(NodeId(b)));
|
||||
let ids = pasted(s.execute("edit.paste", &json!({})).unwrap());
|
||||
let g = parent(&s, b).unwrap();
|
||||
assert_eq!((s.doc().unwrap().doc.node(g).unwrap().kind_label(), parent(&s, ids[0])), ("Clip Group", Some(g)));
|
||||
}
|
||||
|
||||
/// In Draw Behind, Paste in Place and Paste on All Artboards put the copies just below the
|
||||
/// selection, as Paste in Back does; Paste puts them on top, as in Draw Normal.
|
||||
#[test]
|
||||
fn paste_in_place_in_draw_behind_goes_behind_the_selection() {
|
||||
let mut s = session();
|
||||
let a = s.execute("shape.rectangle", &json!({"x": 100, "y": 100, "width": 100, "height": 100})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("shape.ellipse", &json!({"x": 20, "y": 20, "width": 50, "height": 50})).unwrap();
|
||||
s.execute("edit.copy", &json!({})).unwrap();
|
||||
s.execute("select.set", &json!({"ids": [a]})).unwrap();
|
||||
s.execute("view.drawMode", &json!({"mode": "behind"})).unwrap();
|
||||
let order = |s: &Session| s.doc().unwrap().doc.layers[0].children().unwrap().iter().map(|n| n.id.0).collect::<Vec<_>>();
|
||||
let first = |r: Value| r["ids"][0].as_u64().unwrap();
|
||||
let placed = first(s.execute("edit.pasteInPlace", &json!({})).unwrap());
|
||||
let o = order(&s);
|
||||
let at = |id: u64| o.iter().position(|x| *x == id).unwrap();
|
||||
assert_eq!(at(placed) + 1, at(a), "just below the selected rectangle: {o:?}");
|
||||
s.execute("select.set", &json!({"ids": [a]})).unwrap();
|
||||
let all = first(s.execute("edit.pasteOnAllArtboards", &json!({})).unwrap());
|
||||
let o = order(&s);
|
||||
let at = |id: u64| o.iter().position(|x| *x == id).unwrap();
|
||||
assert_eq!(at(all) + 1, at(a), "{o:?}");
|
||||
s.execute("select.set", &json!({"ids": [a]})).unwrap();
|
||||
let pasted = first(s.execute("edit.paste", &json!({})).unwrap());
|
||||
assert_eq!(order(&s).last(), Some(&pasted), "Paste: on top");
|
||||
}
|
||||
|
||||
/// #3705: Shift+D (`view.drawMode {}`) goes Draw Normal → Draw Behind → Draw Inside → Draw Normal
|
||||
/// with one path selected, and from Draw Behind back to Draw Normal when Draw Inside can't draw
|
||||
/// into the selection: one group (such as the clip group Draw Inside made), one image, several
|
||||
/// objects or none. It used to stop at Draw Behind with one object selected that isn't a path,
|
||||
/// compound path or type.
|
||||
#[test]
|
||||
fn shift_d_goes_past_draw_behind_whatever_is_selected() {
|
||||
let mut s = session();
|
||||
let a = s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 100, "height": 100})).unwrap()["id"].as_u64().unwrap();
|
||||
let b = s.execute("shape.ellipse", &json!({"x": 120, "y": 0, "width": 50, "height": 50})).unwrap()["id"].as_u64().unwrap();
|
||||
let cycle = |s: &mut Session| (0..3).map(|_| s.execute("view.drawMode", &json!({})).map(|r| r["mode"].clone()).unwrap()).collect::<Vec<_>>();
|
||||
s.execute("select.set", &json!({"ids": [a]})).unwrap();
|
||||
assert_eq!(cycle(&mut s), [json!("behind"), json!("inside"), json!("normal")]);
|
||||
s.execute("select.set", &json!({"ids": [a, b]})).unwrap();
|
||||
assert_eq!(cycle(&mut s), [json!("behind"), json!("normal"), json!("behind")]);
|
||||
s.execute("view.drawMode", &json!({"mode": "normal"})).unwrap();
|
||||
let g = s.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("select.set", &json!({"ids": [g]})).unwrap();
|
||||
assert_eq!(cycle(&mut s), [json!("behind"), json!("normal"), json!("behind")], "one group selected");
|
||||
assert!(s.draw_inside.is_none());
|
||||
s.execute("view.drawMode", &json!({"mode": "normal"})).unwrap();
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
assert_eq!(cycle(&mut s), [json!("behind"), json!("normal"), json!("behind")]);
|
||||
// Asked for by name, Draw Inside is still refused without a path, compound path or type.
|
||||
s.execute("select.set", &json!({"ids": [g]})).unwrap();
|
||||
assert!(s.execute("view.drawMode", &json!({"mode": "inside"})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_for_screens_writes_every_combination() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user