mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-28 20:36:55 -06:00
Place files dropped together on the canvas side by side
Fixes #886 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
a1369310d4
commit
7d0ecd2294
@@ -699,6 +699,33 @@ fn dropping_a_native_file_on_canvas_keeps_its_receiving_document_after_tab_switc
|
||||
assert_eq!(u.app.session.docs.iter().map(|doc| doc.doc.pages.len()).collect::<Vec<_>>(), [2, 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dropping_several_files_on_canvas_places_them_side_by_side() {
|
||||
let dir = Temp::new();
|
||||
let svg = r##"<svg xmlns="http://www.w3.org/2000/svg" width="20" height="10"><rect width="20" height="10" fill="#f00"/></svg>"##;
|
||||
let paths: Vec<_> = ["a.svg", "b.svg", "c.svg"].iter().map(|n| dir.path(n)).collect();
|
||||
for path in &paths {
|
||||
std::fs::write(path, svg).unwrap();
|
||||
}
|
||||
let mut u = Ui::new(Session::new());
|
||||
u.app.ui.home = false;
|
||||
u.frame(vec![]);
|
||||
let pos = u.app.canvas.rect.center();
|
||||
let files: Vec<egui::DroppedFileHandle> = paths.iter().map(|p| std::sync::Arc::new(Dropped(p.clone())) as egui::DroppedFileHandle).collect();
|
||||
u.frame_raw(egui::RawInput { events: vec![Event::PointerMoved(pos)], dropped_files: files, ..Default::default() });
|
||||
for _ in 0..4 {
|
||||
u.frame(vec![]);
|
||||
}
|
||||
assert!(u.app.ui.pending_opens.is_empty());
|
||||
let doc = u.app.session.doc().unwrap();
|
||||
let page = u.app.session.page().unwrap();
|
||||
let rects: Vec<_> = doc.node(page).unwrap().children.iter().map(|c| doc.world_bounds(*c).unwrap()).collect();
|
||||
assert_eq!(rects.len(), 3);
|
||||
for pair in rects.windows(2) {
|
||||
assert!(pair[1].x0 > pair[0].x1, "left to right with a gap: {rects:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canvas_import_uses_queued_page_and_restores_the_page_selected_while_waiting() {
|
||||
let dir = Temp::new();
|
||||
|
||||
@@ -75,6 +75,9 @@ fn cancel(app: &mut FigApp, message: String) {
|
||||
app.show_error(message);
|
||||
}
|
||||
|
||||
/// Space between files dropped together on the canvas.
|
||||
const IMPORT_GAP: f64 = 20.0;
|
||||
|
||||
/// Frames the card is drawn before the files open: egui lays a new card out invisibly on its first
|
||||
/// frame, so the second one is the first the window shows.
|
||||
const FRAMES_BEFORE_OPENING: u8 = 2;
|
||||
@@ -122,11 +125,26 @@ pub fn pending_opens(app: &mut FigApp, ctx: &egui::Context) {
|
||||
ctx.request_repaint();
|
||||
if app.ui.pending_open_frames >= FRAMES_BEFORE_OPENING && !reading {
|
||||
app.ui.pending_open_frames = 0;
|
||||
for pending in std::mem::take(&mut app.ui.pending_opens) {
|
||||
// Files dropped together land side by side: each starts where the previous one ends.
|
||||
let mut next_x: Option<f64> = None;
|
||||
for mut pending in std::mem::take(&mut app.ui.pending_opens) {
|
||||
let command = pending.command;
|
||||
if run_pending(app, pending).is_some() && command == "file.open" {
|
||||
let canvas = command == "file.import" && pending.params.get("x").is_some();
|
||||
if canvas && let Some(x) = next_x {
|
||||
pending.params["x"] = json!(x);
|
||||
}
|
||||
let page = pending.target.as_ref().map(|t| (t.uid, t.page));
|
||||
let result = run_pending(app, pending);
|
||||
if result.is_some() && command == "file.open" {
|
||||
app.ui.home = false;
|
||||
}
|
||||
if canvas {
|
||||
let right = result.as_ref().and_then(|r| r.get("id")?.as_u64()).and_then(|id| {
|
||||
let doc = &app.session.docs.iter().find(|d| Some(d.uid) == page.map(|p| p.0))?.doc;
|
||||
doc.world_bounds(NodeId(id)).map(|b| b.x1)
|
||||
});
|
||||
next_x = right.map(|r| r + IMPORT_GAP).or(next_x);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user