diff --git a/crates/ui-egui/src/dock_ui.rs b/crates/ui-egui/src/dock_ui.rs index b66267d4d..acb7cd389 100644 --- a/crates/ui-egui/src/dock_ui.rs +++ b/crates/ui-egui/src/dock_ui.rs @@ -530,6 +530,11 @@ impl EffectcraftApp { let typing = ctx.egui_wants_keyboard_input(); let events = events.into_iter().filter(|event| !typing && !matches!(event, egui::Event::Text(_) | egui::Event::Ime(_))); self.forwarded.events.extend(events); + // A floating window's drop names the panel under its pointer, which the main window's + // pointer can never hit (#2661). + if files.iter().any(|window| matches!(window.panel, PanelKind::Timeline)) { + self.forwarded.dropped_on_timeline = true; + } self.forwarded.files.extend(files.into_iter().flat_map(|window| window.dropped)); if !self.forwarded.events.is_empty() || !self.forwarded.files.is_empty() { ctx.request_repaint(); diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index ad1842e3d..ca8c1fb01 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -442,6 +442,10 @@ impl FileDialogsUp { pub(crate) struct ForwardedInput { pub(crate) events: Vec, pub(crate) files: Vec, + /// Files handed over by a floating window whose panel under the pointer was the Timeline. The + /// paths lose the window they came from, so this keeps the one thing the import still needs + /// (#2661); each drop clears it. + pub(crate) dropped_on_timeline: bool, } /// Record the scale the viewer drew at (called by the viewer panel each pass). diff --git a/crates/ui-egui/src/prefs_live.rs b/crates/ui-egui/src/prefs_live.rs index cc283635f..32465a423 100644 --- a/crates/ui-egui/src/prefs_live.rs +++ b/crates/ui-egui/src/prefs_live.rs @@ -63,6 +63,10 @@ pub fn dropped_files(app: &mut EffectcraftApp, ui: &egui::Ui, bounds: Rect) { errors.push(crate::i18n::tr_args("Skipped {} dropped file(s) without a local path. Use File ▸ Import ▸ File…", &[&skipped])); } + // Taken once per drop, before any early return, so a project-only drop cannot leave it set + // for the next one (#2661). + let handed_by_a_floating_window = std::mem::take(&mut app.forwarded.dropped_on_timeline); + let (proj, rest): (Vec, Vec) = paths.into_iter().partition(|p| { let l = p.to_ascii_lowercase(); l.ends_with(".ecproj") || l.ends_with(".ecprojx") @@ -88,7 +92,8 @@ pub fn dropped_files(app: &mut EffectcraftApp, ui: &egui::Ui, bounds: Rect) { // Dropping a file on the Timeline adds it to the composition the panel shows, as it does // on the viewer (#2588); the import decides the layer's position. - let over_timeline = ctx.input(|i| i.pointer.hover_pos()).is_some_and(|p| { + let over_timeline = handed_by_a_floating_window + || ctx.input(|i| i.pointer.hover_pos()).is_some_and(|p| { app.auto .elements .iter()