From ee5c2621543d46dfb1a75e7bdab8c6026508dc92 Mon Sep 17 00:00:00 2001 From: Taha-Mahmoodi <85902429+Taha-Mahmoodi@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:17:19 +0430 Subject: [PATCH] Canvas: a test drops a library symbol on the canvas and finds it added and placed there in one step Review follow-up (CodeRabbit): the library panel test only checked the drag payload. The new canvas test drops PanelDrag::LibrarySymbol over art and checks that the symbol joins the document's Symbols, an instance is placed with its centre at the drop point in document coordinates and at its natural size, as one Add to Symbols undo step that undo takes back. --- crates/ui-egui/src/canvas.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 7082329ff..081baf746 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -8002,6 +8002,39 @@ mod tests { assert!((c - xf.to_doc(at)).hypot() < 1e-6, "{c:?}"); } + #[test] + fn a_library_symbol_dropped_on_the_canvas_is_added_and_placed_there_in_one_step() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 400, "height": 300})).unwrap(); + // Dropped on art too, it is placed, not applied to the art. + app.session.execute("shape.rectangle", &json!({"x": 200, "y": 150, "width": 100, "height": 60})).unwrap(); + app.session.execute("select.none", &json!({})).unwrap(); + let ctx = egui::Context::default(); + frame(&mut app, &ctx, vec![]); + let xf = Xf::new(app.canvas_rect.unwrap(), app.view().unwrap()); + let undo = app.session.active().unwrap().history.undo.len(); + let at = xf.to_screen(Point::new(250.0, 180.0)); + egui::DragAndDrop::set_payload(&ctx, widgets::PanelDrag::LibrarySymbol { library: "basic-shapes".into(), name: "Star".into() }); + let up = egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed: false, modifiers: Default::default() }; + frame(&mut app, &ctx, vec![egui::Event::PointerMoved(at), up]); + let st = app.session.active().unwrap(); + assert_eq!(st.doc.symbols.iter().map(|s| s.name.as_str()).collect::>(), ["Star"]); + assert_eq!(st.history.undo.len(), undo + 1, "added and placed as one undo step"); + assert_eq!(st.history.undo.last().unwrap().label, "Add to Symbols"); + let placed = st.selection.objects.first().copied().unwrap(); + let n = st.doc.node(placed).unwrap(); + assert!(matches!(&n.kind, NodeKind::SymbolInstance { symbol, .. } if symbol == "Star")); + // The registration point (the centre) is where it was dropped, in document coordinates + // (the pointer's screen position, which rounds 250, 180 a little). + let size = st.doc.unknown.get(vectorcraft_doc::SYMBOL_SIZES).and_then(|m| m.get("Star")).cloned().unwrap(); + let b = n.geometric_bounds().unwrap(); + assert!((b.width() - size[0].as_f64().unwrap()).abs() < 1e-6, "{b:?} {size}"); + assert!((b.center() - xf.to_doc(at)).hypot() < 1e-6 && (b.center() - Point::new(250.0, 180.0)).hypot() < 0.1, "{b:?}"); + app.run("edit.undo", json!({})).unwrap(); + let st = app.session.active().unwrap(); + assert!(st.doc.symbols.is_empty() && st.doc.node(placed).is_none()); + } + #[test] fn a_brush_dropped_on_a_path_is_applied_to_it() { let mut app = VectorcraftApp::new(Session::new(), Default::default());