mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 22:35:26 +00:00
Place: drops that arrive before one UI pass stay separate
All pending drops went into one batch, so two single images counted as several: both queued and neither filled the frame it was dropped on. Files of one raw input now share a batch, and each batch is opened on its own.
This commit is contained in:
1 parent
b458bec4c5
commit
267917b8de
3 files changed
+41
-6
No files matched your search
@@ -62,10 +62,11 @@ impl DesignApp {
|
||||
// A drop without pointer events (dragged in from another application) asks the
|
||||
// system now, while the pointer is still where the files were let go.
|
||||
let system = if pointer.is_none() && !raw.dropped_files.is_empty() { self.system_pointer(ctx, raw) } else { None };
|
||||
let batch = self.pending_drops.last().map_or(0, |d| d.batch.wrapping_add(1));
|
||||
for file in std::mem::take(&mut raw.dropped_files) {
|
||||
let path = file.path().to_string_lossy().to_string();
|
||||
if !path.is_empty() {
|
||||
self.pending_drops.push(PendingDrop { path, pointer, system, generation });
|
||||
self.pending_drops.push(PendingDrop { path, pointer, system, batch, generation });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,12 +155,12 @@ impl DesignApp {
|
||||
// suppress later files that belong to the same captured batch.
|
||||
let current = self.input_generation();
|
||||
let drops: Vec<_> = std::mem::take(&mut self.pending_drops).into_iter().filter(|d| d.generation == current).collect();
|
||||
if drops.is_empty() {
|
||||
return;
|
||||
}
|
||||
// Dropped together, they go together: several images load the place cursor at once. Each
|
||||
// file keeps the pointer it was dropped at, or the system's from when it arrived.
|
||||
self.open_dropped_batch(drops.into_iter().map(|d| (d.path, d.pointer.or(d.system))).collect());
|
||||
// file keeps the pointer it was dropped at, or the system's from when it arrived. Separate
|
||||
// drops stay separate, so a single image still fills the frame it was dropped on.
|
||||
for batch in drops.chunk_by(|a, b| a.batch == b.batch) {
|
||||
self.open_dropped_batch(batch.iter().map(|d| (d.path.clone(), d.pointer.or(d.system))).collect());
|
||||
}
|
||||
}
|
||||
|
||||
/// Where the pointer is in the window, asked of the system ([`crate::Services::pointer`]),
|
||||
|
||||
@@ -115,6 +115,9 @@ struct PendingDrop {
|
||||
/// for a drop that brought no pointer events ([`crate::Services::pointer`]). Each drop keeps
|
||||
/// its own, converted with the window's place and the UI scale of that input.
|
||||
system: Option<egui::Pos2>,
|
||||
/// Which drop this file came with: files of one raw input share it, so drops that arrive
|
||||
/// before the same UI pass stay separate.
|
||||
batch: u64,
|
||||
generation: InputGeneration,
|
||||
}
|
||||
|
||||
|
||||
@@ -1011,6 +1011,37 @@ fn a_pointerless_drop_keeps_the_system_pointer_of_its_own_input() {
|
||||
assert!(d.assets[&g.asset].name.contains("drop-own-input"));
|
||||
}
|
||||
|
||||
/// Two drops that arrive before one UI pass stay separate: the first still fills the frame it was
|
||||
/// dropped on, and the second, off any frame, loads the place cursor. Merged, they'd both queue.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[test]
|
||||
fn separate_drops_before_one_pass_are_not_one_batch() {
|
||||
let (mut app, frame, inside, outside) = app_with_drop_frame();
|
||||
let at = std::rc::Rc::new(std::cell::Cell::new(inside));
|
||||
let reported = at.clone();
|
||||
app.services.pointer = Some(Box::new(move || Some(reported.get())));
|
||||
let ctx = egui::Context::default();
|
||||
let window = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1400.0, 900.0));
|
||||
let (first, second) = (dropped_png("separate-drop-a"), dropped_png("separate-drop-b"));
|
||||
let mut raw = pointerless_drop(&first, window);
|
||||
app.raw_input_hook(&ctx, &mut raw);
|
||||
at.set(outside);
|
||||
let mut raw = pointerless_drop(&second, window);
|
||||
app.raw_input_hook(&ctx, &mut raw);
|
||||
assert_eq!(app.pending_drops.len(), 2);
|
||||
ctx.run_ui(raw, |_| app.take_pending_drops()).textures_delta.clear();
|
||||
let _ = std::fs::remove_file(&first);
|
||||
let _ = std::fs::remove_file(&second);
|
||||
let d = &app.session.doc().unwrap().doc;
|
||||
let designcraft_doc::Content::Graphic(g) = &d.item(designcraft_doc::ItemId(frame)).unwrap().content else {
|
||||
panic!("the first drop fills the frame it was dropped on")
|
||||
};
|
||||
assert!(d.assets[&g.asset].name.contains("separate-drop-a"));
|
||||
let loaded = app.session.loaded.as_ref().expect("the second drop loads the place cursor");
|
||||
assert!(d.assets[&loaded.asset].name.contains("separate-drop-b"));
|
||||
assert!(app.session.loaded_queue.is_empty());
|
||||
}
|
||||
|
||||
/// A filled compound path (Object > Compound Paths > Make) is a frame a dropped image fills, as
|
||||
/// in InDesign, through its ring and not its hole.
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user