Fix #693: a click activates its artboard; in-place pastes go onto it

- A press with a selection tool inside an artboard makes it the active one, as
  the Artboard tool's does; before, only the navigator and the Artboards panel
  changed it.
- Paste in Place, in Front and in Back take `artboard` (the UI passes the active
  one): the objects go where they were on the artboard they were copied from,
  on that artboard. Without it, they paste where they were, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-09 13:32:44 +07:00
co-authored by Claude Opus 5.5
parent 843507549f
commit e9bbf43d15
5 changed files with 82 additions and 5 deletions
+37
View File
@@ -864,6 +864,15 @@ pub fn dispatch(app: &mut VectorcraftApp, ev: &PointerEvent, view: vectorcraft_e
{
v.artboard = i;
}
// A press with a selection tool inside an artboard makes it the active one (#693), as the
// Artboard tool's does: Paste in Place and in Front or Back then paste onto it.
if ev.kind == PointerKind::Down
&& vectorcraft_tools::catalog::is_selection_tool(app.session.tool_id())
&& let Some(i) = app.session.active().and_then(|d| d.doc.artboard_at(ev.pos))
&& let Some(v) = app.view_mut()
{
v.artboard = i;
}
apply_requests(app, r);
}
@@ -2051,6 +2060,34 @@ mod tests {
out.textures_delta.clear();
}
/// A click with the Selection tool inside an artboard makes it the active one, and Paste in
/// Place then pastes onto it, where the objects were on their own artboard (#693).
#[test]
fn a_click_activates_its_artboard_and_paste_in_place_goes_onto_it() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 200, "height": 100, "artboards": 3})).unwrap();
let boards: Vec<_> = app.session.active().unwrap().doc.artboards.iter().map(|a| a.rect).collect();
app.session.execute("shape.rectangle", &json!({"x": boards[0].x0 + 10.0, "y": boards[0].y0 + 15.0, "width": 20, "height": 20})).unwrap();
app.run("edit.copy", json!({})).unwrap();
let ctx = egui::Context::default();
frame(&mut app, &ctx, vec![]);
app.select_tool("selection");
let view = app.view_info();
let at = boards[2].center();
for kind in [PointerKind::Down, PointerKind::Up] {
dispatch(&mut app, &PointerEvent { kind, pos: at, mods: Default::default(), pressure: 1.0 }, view);
}
assert_eq!(app.view().unwrap().artboard, 2, "the clicked artboard is the active one");
let ids: Vec<vectorcraft_doc::NodeId> = app.run("edit.pasteInPlace", json!({})).unwrap()["ids"]
.as_array()
.unwrap()
.iter()
.map(|v| vectorcraft_doc::NodeId(v.as_u64().unwrap()))
.collect();
let b = app.session.active().unwrap().doc.bounds_of(&ids, false).unwrap();
assert_eq!((b.x0, b.y0), (boards[2].x0 + 10.0, boards[2].y0 + 15.0));
}
/// Enable Touch Gestures (#585): a two-finger tap undoes and a three-finger one redoes, and the
/// first finger's press (the pointer egui makes of it) draws nothing. Off, a tap does nothing.
#[test]
+8
View File
@@ -534,6 +534,14 @@ impl VectorcraftApp {
{
p.insert("center".into(), serde_json::json!([c.x, c.y]));
}
// In place, in front, in back: onto the active artboard (#693).
if matches!(id, "edit.pasteInPlace" | "edit.pasteInFront" | "edit.pasteInBack")
&& params.get("artboard").is_none()
&& let Some(i) = self.view().map(|v| v.artboard)
&& let Some(p) = params.as_object_mut()
{
p.insert("artboard".into(), serde_json::json!(i));
}
if let Some(r) = dialogs::swatch_conflict::ask(self, id, &params) {
return r;
}