mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-02 14:38:21 -06:00
ui: the handed-over drop ignores a window that only saw the file hover
Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
This commit is contained in:
co-authored by
DeepSeek V4.1 Flash
parent
440db189a5
commit
ab4e8295c7
@@ -530,9 +530,7 @@ 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)) {
|
||||
if handed_over_to_the_timeline(files.iter().map(|window| (window.panel, !window.dropped.is_empty()))) {
|
||||
self.forwarded.dropped_on_timeline = true;
|
||||
}
|
||||
self.forwarded.files.extend(files.into_iter().flat_map(|window| window.dropped));
|
||||
@@ -867,3 +865,33 @@ impl DockContent<PanelKind> for EffectContent<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a handed-over *drop* named the Timeline. A floating window reports its hovered files
|
||||
/// too, so a drag that only passes over the Timeline window must not count: its flag would survive
|
||||
/// and send the next drop somewhere else. The panel comes from the window, which the main window's
|
||||
/// pointer can never reach (#2661).
|
||||
fn handed_over_to_the_timeline(drops: impl Iterator<Item = (PanelKind, bool)>) -> bool {
|
||||
drops.into_iter().any(|(panel, has_files)| has_files && matches!(panel, PanelKind::Timeline))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// A drop handed over by a floating window says which panel it landed on; only the Timeline
|
||||
/// turns it into a layer instead of a project item. A window that only saw the file hover over
|
||||
/// it carries no files and must not count, or its flag would outlive the drag (#2661).
|
||||
#[test]
|
||||
fn only_a_timeline_drop_is_handed_over_to_the_timeline() {
|
||||
let cases = [
|
||||
(vec![(PanelKind::Timeline, true)], true),
|
||||
(vec![(PanelKind::Project, true)], false),
|
||||
(vec![(PanelKind::Timeline, false)], false),
|
||||
(vec![(PanelKind::Project, true), (PanelKind::Timeline, true)], true),
|
||||
(vec![], false),
|
||||
];
|
||||
for (windows, want) in cases {
|
||||
assert_eq!(handed_over_to_the_timeline(windows.into_iter()), want, "{want}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ 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).
|
||||
// Taken once per drop frame, so a handed-over flag cannot survive into a later, unrelated
|
||||
// drop (#2661).
|
||||
let handed_by_a_floating_window = std::mem::take(&mut app.forwarded.dropped_on_timeline);
|
||||
|
||||
let (proj, rest): (Vec<String>, Vec<String>) = paths.into_iter().partition(|p| {
|
||||
@@ -94,12 +94,12 @@ pub fn dropped_files(app: &mut EffectcraftApp, ui: &egui::Ui, bounds: Rect) {
|
||||
// on the viewer (#2588); the import decides the layer's position.
|
||||
let over_timeline = handed_by_a_floating_window
|
||||
|| ctx.input(|i| i.pointer.hover_pos()).is_some_and(|p| {
|
||||
app.auto
|
||||
.elements
|
||||
.iter()
|
||||
.find(|e| e.id == "panel.Timeline")
|
||||
.is_some_and(|e| Rect::from_min_size(egui::pos2(e.rect[0], e.rect[1]), egui::vec2(e.rect[2], e.rect[3])).contains(p))
|
||||
});
|
||||
app.auto
|
||||
.elements
|
||||
.iter()
|
||||
.find(|e| e.id == "panel.Timeline")
|
||||
.is_some_and(|e| Rect::from_min_size(egui::pos2(e.rect[0], e.rect[1]), egui::vec2(e.rect[2], e.rect[3])).contains(p))
|
||||
});
|
||||
|
||||
let at = if proj.is_empty() && !over_timeline {
|
||||
ctx.input(|i| i.pointer.hover_pos()).filter(|p| viewer.is_some_and(|v| v.contains(*p))).and_then(|p| crate::panels::viewer::screen_to_comp(&ctx, p))
|
||||
|
||||
Reference in New Issue
Block a user