diff --git a/crates/ui-egui/src/board_connect_tests.rs b/crates/ui-egui/src/board_connect_tests.rs index 7d109dbb3..b6466a9ff 100644 --- a/crates/ui-egui/src/board_connect_tests.rs +++ b/crates/ui-egui/src/board_connect_tests.rs @@ -236,3 +236,42 @@ fn letting_a_handle_go_over_a_panel_makes_nothing() { u.frame(vec![]); assert_eq!(u.app.session.doc().unwrap().ids().count(), before, "nothing made"); } + +/// A handle let go over the floating toolbar at the bottom of the canvas makes nothing either +/// (review): the toolbar lies inside the canvas rectangle. +#[test] +fn letting_a_handle_go_over_the_toolbar_makes_nothing() { + let (mut u, a) = board_with_shape(); + u.app.session.execute("select.set", &json!({"ids": [a]})).unwrap(); + u.frame(vec![]); + u.frame(vec![]); + let before = u.app.session.doc().unwrap().ids().count(); + let from = handle(&u, "below").expect("a handle below").center(); + let to = crate::toolbar::pill_rect(u.app.canvas.rect, crate::toolbar::bar_width(&u.app)).center(); + u.drag_to(from, to); + u.button(to, false); + u.frame(vec![]); + assert_eq!(u.app.session.doc().unwrap().ids().count(), before, "nothing made behind the toolbar"); +} + +/// The selection moving to another shape under a drag ends the drag (review): letting go later, +/// even with the first shape selected again, makes nothing. +#[test] +fn a_drag_ends_when_the_selection_moves_to_another_shape() { + let (mut u, a) = board_with_shape(); + let b = id(&u.app.session.execute("board.shape", &json!({"shape": "ellipse", "x": 600, "y": 0, "width": 160, "height": 100})).unwrap()); + u.app.session.execute("select.set", &json!({"ids": [a]})).unwrap(); + u.frame(vec![]); + u.frame(vec![]); + let before = u.app.session.doc().unwrap().ids().count(); + let from = handle(&u, "below").expect("a handle below").center(); + let to = from + egui::vec2(0.0, 160.0); + u.drag_to(from, to); + u.app.session.execute("select.set", &json!({"ids": [b]})).unwrap(); + u.frame(vec![Event::PointerMoved(to)]); + u.app.session.execute("select.set", &json!({"ids": [a]})).unwrap(); + u.frame(vec![Event::PointerMoved(to)]); + u.button(to, false); + u.frame(vec![]); + assert_eq!(u.app.session.doc().unwrap().ids().count(), before, "the drag was over"); +} diff --git a/crates/ui-egui/src/canvas/board_connect.rs b/crates/ui-egui/src/canvas/board_connect.rs index 4ea0d9a4d..b78946ef3 100644 --- a/crates/ui-egui/src/canvas/board_connect.rs +++ b/crates/ui-egui/src/canvas/board_connect.rs @@ -147,11 +147,17 @@ pub fn show(app: &mut FigApp, ctx: &egui::Context) { } // A drag carries the preview: the next one centred on the pointer, or the object under it, // which the connector joins instead. - let Some(Drag { from, side }) = drag.filter(|d| d.from == id) else { return }; + let Some(Drag { from, side }) = drag else { return }; + // The selection moved to another sticky or shape under the drag: it is over too. + if from != id { + ctx.data_mut(|d| d.remove::(drag_id())); + return; + } let Some(pointer) = ctx.input(|i| i.pointer.latest_pos()) else { return }; let over = object_under(app, from, pointer); - // Off the canvas (over a panel) there is nothing to show and nothing to make. - let on_canvas = app.canvas.rect.contains(pointer); + // Off the canvas (over a panel) or over the floating toolbar there is nothing to show and + // nothing to make. + let on_canvas = app.canvas.rect.contains(pointer) && !toolbar.contains(pointer); if on_canvas { drag_preview(app, ctx, (b, next, side), pointer, over); }