mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-24 10:09:32 -06:00
Paste path operators below the shapes they act on (#1681)
Pasting Trim Paths, Wiggle Paths or a paint into a shape layer with nothing selected put it on top of Contents, where it acts on no shapes. It now goes to the bottom, as Add places it. Also fixes #1629.
This commit is contained in:
@@ -127,8 +127,9 @@ pub(crate) fn cut_contents(s: &mut Session, items: &[(LayerId, Uid)]) -> Result<
|
||||
}
|
||||
|
||||
/// Edit ▸ Paste with shape items on the clipboard: copies go into each selected shape layer's
|
||||
/// Contents, above its topmost selected item (in that item's group), else on top. Names stay
|
||||
/// unique in their group ("Rectangle 2"…), and the copies are selected.
|
||||
/// Contents, above its topmost selected item (in that item's group), else on top (paints and path
|
||||
/// operations alone: at the bottom). Names stay unique in their group ("Rectangle 2"…), and the
|
||||
/// copies are selected.
|
||||
pub(crate) fn paste_contents(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let c = "edit.paste";
|
||||
let clip = s.state.contents_clipboard.clone();
|
||||
@@ -140,6 +141,7 @@ pub(crate) fn paste_contents(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
return Err(bad(c, "select a shape layer to paste shape items into"));
|
||||
}
|
||||
let sel = selected_contents(s);
|
||||
let acts_on_above = clip.iter().all(|g| !matches!(g.match_id.as_str(), "group" | "rect" | "ellipse" | "star" | "path"));
|
||||
let label = match clip.as_slice() {
|
||||
[g] => format!("Paste {}", g.name),
|
||||
_ => "Paste".to_string(),
|
||||
@@ -154,11 +156,15 @@ pub(crate) fn paste_contents(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let parent = l.props.parent_of(*u)?;
|
||||
Some((parent.uid, parent.children.iter().position(|n| n.uid() == *u)?))
|
||||
});
|
||||
let unselected = spot.is_none();
|
||||
let (parent, at) = match spot {
|
||||
Some((pu, i)) => (l.props.find_group_mut(pu), i),
|
||||
None => (l.props.sub_mut("contents"), 0),
|
||||
};
|
||||
let parent = parent.ok_or_else(|| bad(c, "the layer has no contents"))?;
|
||||
// Trim Paths, Wiggle Paths, fills… act on the items above them (as Add places them),
|
||||
// so with nothing selected they go to the bottom: on top they'd affect nothing (#1681).
|
||||
let at = if unselected && acts_on_above { parent.children.len() } else { at };
|
||||
for (k, g) in clip.iter().enumerate() {
|
||||
let mut g = g.clone();
|
||||
g.reassign_uids(&mut next);
|
||||
|
||||
@@ -1541,6 +1541,21 @@ fn shape_contents_copy_cut_and_paste_between_shape_layers() {
|
||||
assert!(s.execute("edit.paste", json!({})).is_err());
|
||||
}
|
||||
|
||||
/// Pasting Trim Paths into another shape layer with nothing selected puts it below the shapes,
|
||||
/// where it acts on them (it acts on the items above it); on top it would trim nothing (#1681, #1629).
|
||||
#[test]
|
||||
fn pasted_path_operator_goes_below_the_shapes_it_acts_on() {
|
||||
let mut s = comp();
|
||||
let a = s.execute("layer.newShape", json!({"kind": "rect"})).unwrap()["layer"].as_u64().unwrap();
|
||||
let trim = s.execute("layer.addShapeItem", json!({"layer": a, "kind": "trim"})).unwrap()["uid"].as_u64().unwrap();
|
||||
let b = s.execute("layer.newShape", json!({"kind": "star", "name": "B"})).unwrap()["layer"].as_u64().unwrap();
|
||||
s.execute("prop.select", json!({"layer": a, "prop": trim})).unwrap();
|
||||
s.execute("edit.copy", json!({})).unwrap();
|
||||
s.execute("layer.select", json!({"layers": [b]})).unwrap();
|
||||
s.execute("edit.paste", json!({})).unwrap();
|
||||
assert_eq!(contents_names(&s, b), ["Polystar 1", "Trim Paths 1"]);
|
||||
}
|
||||
|
||||
/// Edit ▸ Duplicate with shape items selected duplicates them in their layer, above the
|
||||
/// original and named "Rectangle 2", not the layer (#227).
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user