Place: a grid previews the cells it places on a rotated spread

The preview divided the dragged rectangle on the canvas and the release divided it on the spread, so on a rotated spread two columns previewed across the canvas and landed down it. The preview now takes the release's cells and shows each where it lands on the canvas.
This commit is contained in:
texjer committed 2026-11-04 19:36:38 -05:00
1 parent e4f82e243e
commit d721ef9f62
2 files changed
+46 -4

No files matched your search

+9 -4
View File
@@ -197,11 +197,16 @@ impl Tool for PlaceGun {
// no frame is drawn yet, the loaded cursor shows what lands.
let click = (self.cur - a).hypot() < cx.tol(3.0);
// A grid draws its cells; one too small for them falls back to the single frame, as the
// release does.
if !click {
let cells = grid_cells(designcraft_geom::Rect::from_points(a, self.cur), self.columns, self.rows);
// release does. The cells are the release's, worked out on the spread: on a rotated spread
// its columns don't run across the canvas.
if !click && let Some((sr, sa)) = cx.layout.spread_at(a) {
let cells = grid_cells(designcraft_geom::Rect::from_points(sa, cx.layout.to_spread(sr, self.cur)), self.columns, self.rows);
if !cells.is_empty() {
return cells.into_iter().map(crate::Overlay::Marquee).collect();
let on_canvas = |x: f64, y: f64| cx.layout.to_canvas(sr, Point::new(x, y));
return cells
.into_iter()
.map(|c| crate::Overlay::Marquee(designcraft_geom::Rect::from_points(on_canvas(c.x0, c.y0), on_canvas(c.x1, c.y1))))
.collect();
}
}
let Some(size) = cx.loaded else {
+37
View File
@@ -2441,3 +2441,40 @@ fn place_gun_grid_too_small_for_its_cells_previews_and_places_one_frame() {
assert_eq!(out, single_out);
assert!(matches!(out.as_slice(), [Action::Exec(cmd, _)] if cmd == "place.drop"), "{out:?}");
}
/// On a rotated spread a place-cursor grid previews the cells it places: worked out on the spread,
/// then shown on the canvas, so two columns on the spread don't preview as two across the canvas.
#[test]
fn place_gun_grid_preview_matches_the_release_on_a_rotated_spread() {
let mut d = Document::new(&NewDocument::default());
std::sync::Arc::make_mut(&mut d.spreads[0]).pages[0].view_rotation = 1;
let (s, c, l) = (Selection::default(), Cache::new(), CanvasLayout::new(&d, false));
let cx = ctx(&d, &s, &c, &l);
let (start, end) = (Point::new(10.0, 10.0), Point::new(210.0, 110.0));
let (spread, a) = l.spread_at(start).unwrap();
let b = l.to_spread(spread, end);
let mut t = create("placeGun");
let _ = t.pointer(&cx, &PointerEvent::new(PointerKind::Down, start.x, start.y));
let _ = t.pointer(&cx, &PointerEvent::new(PointerKind::Drag, end.x, end.y));
assert_eq!(t.key(&cx, ToolKey::Right, Mods::default()), vec![Action::Handled]);
let shown = t.overlays(&cx);
let out = t.pointer(&cx, &PointerEvent::new(PointerKind::Up, end.x, end.y));
assert!(matches!(out.as_slice(), [Action::Exec(cmd, p)] if cmd == "place.grid" && p["columns"] == 2), "{out:?}");
// Two columns on the spread, 6 pt apart, each shown where its corners land on the canvas.
let r = Rect::from_points(a, b);
let w = (r.width() - 6.0) / 2.0;
let expected: Vec<Overlay> = [r.x0, r.x0 + w + 6.0]
.into_iter()
.map(|x| Overlay::Marquee(Rect::from_points(l.to_canvas(spread, Point::new(x, r.y0)), l.to_canvas(spread, Point::new(x + w, r.y1)))))
.collect();
assert_eq!(shown.len(), 2, "{shown:?}");
for (got, want) in shown.iter().zip(&expected) {
let (Overlay::Marquee(got), Overlay::Marquee(want)) = (got, want) else { panic!("{got:?}") };
for (g, w) in [(got.x0, want.x0), (got.y0, want.y0), (got.x1, want.x1), (got.y1, want.y1)] {
assert!((g - w).abs() < 1e-6, "{shown:?} against {expected:?}");
}
}
// A quarter turn: the columns stack down the canvas.
let (Overlay::Marquee(first), Overlay::Marquee(second)) = (&shown[0], &shown[1]) else { panic!("{shown:?}") };
assert!((first.x0 - second.x0).abs() < 1e-6, "{shown:?}");
}