mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-14 19:27:07 -04:00
Integration: #869 Alt-drag copies a page in one command and one undo step (layout.pages.duplicateSpread takes to)
(cherry picked from commit 7889b25a379fdf27dd128bc49512bc3c0cbfcbfd)
This commit is contained in:
1 parent
15fccae6b8
commit
f4efb7cc5c
3 files changed
+61
-14
No files matched your search
@@ -140,13 +140,18 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Duplicate Spread",
|
||||
["Layout", "Pages"],
|
||||
None,
|
||||
"{spread, atEnd?: bool (Duplicate Spread at End of Document; the Pages panel's New Page button takes a dropped page there)} → {page: the copy's first page (0-based)} — the spread's pages (size, margins, columns, guides, liquid rule) and items",
|
||||
"{spread, atEnd?: bool (Duplicate Spread at End of Document; the Pages panel's New Page button takes a dropped page there), to?: page index the copied pages move to, in the same undo step (the Pages panel's Alt-drag)} → {page: the copy's first page (0-based)} — the spread's pages (size, margins, columns, guides, liquid rule) and items",
|
||||
has_doc,
|
||||
|s, p| {
|
||||
let si = p.get("spread").and_then(Value::as_u64).unwrap_or(0) as usize;
|
||||
let at_end = p.get("atEnd").and_then(Value::as_bool).unwrap_or(false);
|
||||
let to = p.get("to").and_then(Value::as_u64).map(|t| t as usize);
|
||||
s.edit(|d, _| {
|
||||
let sp = d.spreads.get(si).cloned().ok_or_else(|| bad("layout.pages.duplicateSpread", "no such spread"))?;
|
||||
// The copies land at `to`..`to + n` of the document with them in it.
|
||||
if to.is_some_and(|t| t > d.page_count()) {
|
||||
return Err(bad("layout.pages.duplicateSpread", "no such page"));
|
||||
}
|
||||
let after = if at_end { d.page_count() - 1 } else { d.first_page_of_spread(si) + sp.pages.len() - 1 };
|
||||
let parent = sp.pages.first().and_then(|p| p.parent);
|
||||
d.insert_pages(Some(after), sp.pages.len(), parent)?;
|
||||
@@ -169,7 +174,21 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
let ids: Vec<_> = sp.items.iter().map(|i| i.id).collect();
|
||||
let (nsi, _) = d.page_loc(after + 1).ok_or_else(|| bad("layout.pages.duplicateSpread", "insert failed"))?;
|
||||
super::object::duplicate_from(d, &src, &ids, designcraft_doc::SpreadRef::Doc(nsi), designcraft_geom::Vec2::ZERO)?;
|
||||
Ok(json!({"page": after + 1}))
|
||||
let first = after + 1;
|
||||
let Some(to) = to else { return Ok(json!({"page": first})) };
|
||||
// Moving a page shifts the ones between; order the moves so each copy keeps
|
||||
// its place among the others.
|
||||
let n = sp.pages.len();
|
||||
if first < to {
|
||||
for k in (0..n).rev() {
|
||||
d.move_page(first + k, to + k)?;
|
||||
}
|
||||
} else {
|
||||
for k in 0..n {
|
||||
d.move_page(first + k, to + k)?;
|
||||
}
|
||||
}
|
||||
Ok(json!({"page": to}))
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
@@ -695,3 +695,31 @@ fn type_tool_frames_snap_to_the_margins() {
|
||||
assert!((r.x0 - margin.x0).abs() < 1e-6 && (r.y0 - margin.y0).abs() < 1e-6, "press point {r:?} vs {margin:?}");
|
||||
assert!((r.x1 - margin.x1).abs() < 1e-6, "right edge {} vs {}", r.x1, margin.x1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicating_a_page_to_an_index_is_one_undo_step() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"facingPages": false})).unwrap();
|
||||
s.execute("layout.pages.insert", &json!({"count": 2})).unwrap();
|
||||
for (page, width) in [(1, 300), (2, 400), (3, 500)] {
|
||||
s.execute("layout.pageSize", &json!({"pages": [page], "width": width, "height": 600})).unwrap();
|
||||
}
|
||||
let widths = |s: &Session| {
|
||||
let d = &s.doc().unwrap().doc;
|
||||
(0..d.page_count()).map(|i| d.page_loc(i).map(|(si, pi)| d.spreads[si].pages[pi].width)).collect::<Option<Vec<_>>>().unwrap()
|
||||
};
|
||||
// Backwards: the last page copied to the front.
|
||||
let r = s.execute("layout.pages.duplicateSpread", &json!({"spread": 2, "to": 0})).unwrap();
|
||||
assert_eq!(r["page"], 0);
|
||||
assert_eq!(widths(&s), [500.0, 300.0, 400.0, 500.0]);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(widths(&s), [300.0, 400.0, 500.0]);
|
||||
// Forwards: the first page copied to the end.
|
||||
s.execute("layout.pages.duplicateSpread", &json!({"spread": 0, "to": 3})).unwrap();
|
||||
assert_eq!(widths(&s), [300.0, 400.0, 500.0, 300.0]);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(widths(&s), [300.0, 400.0, 500.0]);
|
||||
// Past the end: refused, nothing changes.
|
||||
assert!(s.execute("layout.pages.duplicateSpread", &json!({"spread": 0, "to": 4})).is_err());
|
||||
assert_eq!(widths(&s), [300.0, 400.0, 500.0]);
|
||||
}
|
||||
@@ -239,21 +239,21 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) {
|
||||
});
|
||||
});
|
||||
});
|
||||
// Alt-drag (InDesign's Option-drag) copies the page to where it's dropped.
|
||||
let copy = ui.input(|i| i.modifiers.alt);
|
||||
// Alt-drag copies a page that is a spread of its own to where it's dropped, in one undo
|
||||
// step; a page from a larger spread moves as usual.
|
||||
let alt = ui.input(|i| i.modifiers.alt);
|
||||
let copy = |from: usize| {
|
||||
let (si, _) = doc.page_loc(from)?;
|
||||
(alt && doc.spreads.get(si).is_some_and(|s| s.pages.len() == 1)).then_some(si)
|
||||
};
|
||||
match drop {
|
||||
Some((PageDrag::Page(from), to)) if copy => {
|
||||
if let Some((si, _)) = doc.page_loc(from)
|
||||
&& let Ok(r) = app.run("layout.pages.duplicateSpread", json!({"spread": si}))
|
||||
&& let Some(new) = r["page"].as_u64().map(|p| p as usize)
|
||||
&& new != to
|
||||
{
|
||||
let _ = app.run("layout.pages.move", json!({"from": new, "to": to}));
|
||||
Some((PageDrag::Page(from), to)) => {
|
||||
if let Some(si) = copy(from) {
|
||||
let _ = app.run("layout.pages.duplicateSpread", json!({"spread": si, "to": to}));
|
||||
} else if from != to {
|
||||
let _ = app.run("layout.pages.move", json!({"from": from, "to": to}));
|
||||
}
|
||||
}
|
||||
Some((PageDrag::Page(from), to)) if from != to => {
|
||||
let _ = app.run("layout.pages.move", json!({"from": from, "to": to}));
|
||||
}
|
||||
Some((PageDrag::Parent(prefix), to)) => {
|
||||
let _ = app.run("layout.pages.applyParent", json!({"pages": [to], "parent": prefix}));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user