From f2f19459736b831418c6f1068084bf7e623720cb Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Wed, 14 Oct 2026 11:36:53 +0200 Subject: [PATCH] Paste in Place: art copied from off the artboards goes back where it was (fixes #1924) --- crates/engine/src/cmd/clipboard.rs | 13 ++++++++++--- crates/engine/src/tests_clipboard.rs | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/cmd/clipboard.rs b/crates/engine/src/cmd/clipboard.rs index 5f1822caf..25ab1d82d 100644 --- a/crates/engine/src/cmd/clipboard.rs +++ b/crates/engine/src/cmd/clipboard.rs @@ -80,7 +80,8 @@ pub struct Clipboard { pub para_styles: Vec, /// Brushes the objects' strokes use. pub brushes: Vec, - /// The artboard the objects were copied from: Paste on All Artboards keeps their offset to it. + /// The artboard the objects were copied from (none when they lie on no artboard): Paste on All + /// Artboards keeps their offset to it. pub source_artboard: Option, /// Per object: the name of the layer it was copied from (Paste Remembers Layers). pub source_layers: Vec>, @@ -109,8 +110,14 @@ impl Clipboard { source_layers.push(anc.iter().rev().skip(1).find_map(|a| d.node(*a).filter(|l| l.is_layer())).and_then(|l| l.name.clone())); } let bounds = nodes.iter().filter_map(Node::visual_bounds).reduce(|a, b| a.union(b)); - let board = bounds.and_then(|b| d.artboard_at(b.center())).unwrap_or(0); - Self { source_artboard: d.artboards.get(board).map(|a| a.rect), source_layers, source_doc: Some(st.uid), ..Self::gather(d, nodes) } + // Art on no artboard has no source artboard: in-place pastes put it back where it was (#1924). + let board = bounds.and_then(|b| d.artboard_at(b.center())); + Self { + source_artboard: board.and_then(|i| d.artboards.get(i)).map(|a| a.rect), + source_layers, + source_doc: Some(st.uid), + ..Self::gather(d, nodes) + } } /// Every object of `src` (each top-level layer's contents) with its resources, for Place and diff --git a/crates/engine/src/tests_clipboard.rs b/crates/engine/src/tests_clipboard.rs index 48c8912bd..589d28b05 100644 --- a/crates/engine/src/tests_clipboard.rs +++ b/crates/engine/src/tests_clipboard.rs @@ -571,6 +571,20 @@ fn in_place_pastes_go_onto_the_artboard_named() { } } +/// Art copied from beside the artboards goes back where it was, whichever artboard is active (#1924). +#[test] +fn in_place_pastes_of_art_off_the_artboards_stay_where_it_was() { + let mut s = Session::new(); + s.execute("file.new", &json!({"width": 200, "height": 100, "artboards": 2})).unwrap(); + let boards: Vec = doc(&s).artboards.iter().map(|a| a.rect).collect(); + let r = rect(&mut s, boards[0].x0 - 100.0, boards[0].y0 + 15.0, 20.0, 20.0); + copy(&mut s, &[r]); + for cmd in ["edit.pasteInPlace", "edit.pasteInFront", "edit.pasteInBack"] { + let ids = ids_of(&s.execute(cmd, &json!({"artboard": 1})).unwrap()); + assert_eq!(doc(&s).bounds_of(&ids, false).unwrap().origin(), Point::new(boards[0].x0 - 100.0, boards[0].y0 + 15.0), "{cmd}"); + } +} + #[test] fn paste_remembers_layers_restores_the_source_layers() { let mut s = session();