diff --git a/crates/ui-egui/src/panels.rs b/crates/ui-egui/src/panels.rs index c4a6f4d3a..230ac14fe 100644 --- a/crates/ui-egui/src/panels.rs +++ b/crates/ui-egui/src/panels.rs @@ -135,8 +135,9 @@ pub(crate) fn project_drop_items(app: &EffectcraftApp, dragged: u64, target: Opt selected.iter().map(|id| id.0).collect() } else { // One unselected item goes through as is, so a folder or data file still gets the - // engine's error instead of a silent no-op. - return vec![dragged]; + // engine's error instead of a silent no-op. The composition the drop lands in is the + // one case that never reaches it, selected or not (#2589). + return if Some(ItemId(dragged)) == target { Vec::new() } else { vec![dragged] }; }; candidates .into_iter() diff --git a/crates/ui-egui/tests/it/ui_self_drop.rs b/crates/ui-egui/tests/it/ui_self_drop.rs index a371cc80b..f8a44de83 100644 --- a/crates/ui-egui/tests/it/ui_self_drop.rs +++ b/crates/ui-egui/tests/it/ui_self_drop.rs @@ -60,7 +60,8 @@ fn a_selection_holding_the_drop_target_does_not_fail_the_drop() { assert!(!h.state().ui.status.contains("contain itself"), "the drop did not fail: {}", h.state().ui.status); } -/// Dragging the composition's own row onto its Timeline adds nothing and reports nothing. +/// Dragging the composition's own row onto its Timeline adds nothing and reports nothing, whether +/// the row was selected first or the drag started on an unselected row (#2589). #[test] fn the_composition_dropped_on_itself_adds_nothing() { let (mut h, main, _clip) = harness(); @@ -72,4 +73,16 @@ fn the_composition_dropped_on_itself_adds_nothing() { drag(&mut h, from, row.center()); assert_eq!(stack(&h), before, "nothing is added"); assert!(!h.state().ui.status.contains("contain itself"), "no error: {}", h.state().ui.status); + + // The same row dragged while something else is selected: the early return for a single + // unselected item must not hand the composition to the engine either. + let (mut h, main, clip) = harness(); + h.state_mut().session.execute("project.select", json!({"items": [clip]})).unwrap(); + h.run_steps(2); + let before = stack(&h); + let from = rect(&h, &format!("project.item.{main}.name")).center(); + let row = rect(&h, &format!("timeline.layer.{}.row", layer_id(&h, "Bottom"))); + drag(&mut h, from, row.center()); + assert_eq!(stack(&h), before, "nothing is added from an unselected row either"); + assert!(!h.state().ui.status.contains("contain itself"), "no error: {}", h.state().ui.status); }