vectorcraft/crates/engine/src/tests_printtiling.rs

163 lines
8.7 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! View → Show Print Tiling (`view.printTiling`, `print.tiling`) and the Print Tiling tool
//! (`print.tiling.set`): the pages drawn are print.preview's, and where the tool puts them is
//! saved with the print settings.
use serde_json::{Value, json};
use vectorcraft_tools::{PointerEvent, PointerKind};
use super::*;
use crate::tooling::ViewInfo;
/// A 300 × 200 document with a rectangle.
fn session() -> Session {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 300, "height": 200})).unwrap();
s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 100, "height": 50})).unwrap();
s
}
fn rect(v: &Value) -> [f64; 4] {
let a: Vec<f64> = v.as_array().unwrap().iter().map(|x| x.as_f64().unwrap()).collect();
[a[0], a[1], a[2], a[3]]
}
fn close(a: [f64; 4], b: [f64; 4]) -> bool {
a.iter().zip(b).all(|(x, y)| (x - y).abs() < 1e-6)
}
/// `t` (a print.preview transform) applied to `(x, y)`.
fn apply(t: &Value, (x, y): (f64, f64)) -> (f64, f64) {
let c: Vec<f64> = t.as_array().unwrap().iter().map(|v| v.as_f64().unwrap()).collect();
(c[0] * x + c[2] * y + c[4], c[1] * x + c[3] * y + c[5])
}
fn tiling(s: &mut Session, settings: Value) -> Value {
s.execute("print.tiling", &json!({ "settings": settings })).unwrap()
}
#[test]
fn show_print_tiling_is_a_per_document_view_toggle() {
let mut s = session();
let undo = s.doc().unwrap().history.undo.len();
assert_eq!(s.execute("view.printTiling", &json!({})).unwrap()["on"], true);
assert!(s.doc().unwrap().print_tiling);
assert_eq!(s.execute("view.printTiling", &json!({})).unwrap()["on"], false);
assert_eq!(s.execute("view.printTiling", &json!({"on": true})).unwrap()["on"], true);
assert_eq!(s.doc().unwrap().history.undo.len(), undo, "a view toggle is no undo step");
s.execute("file.new", &json!({"width": 100, "height": 100})).unwrap();
assert!(!s.doc().unwrap().print_tiling, "each document has its own");
}
#[test]
fn tiling_pages_are_print_preview_tiles() {
let mut s = session();
let set = json!({"scaling": "tileImageable", "scale": {"width": 600, "height": 600}, "margin": 18, "overlap": 9, "tileRange": "1-2, 5"});
let pv = s.execute("print.preview", &json!({ "settings": set })).unwrap();
let grid = &pv["tiles"][0];
let tiles = grid["tiles"].as_array().unwrap();
let pages = tiling(&mut s, set.clone())["pages"].as_array().unwrap().clone();
assert!(tiles.len() > 4);
assert_eq!(pages.len(), tiles.len(), "one page per tile");
for (i, (p, t)) in pages.iter().zip(tiles).enumerate() {
assert_eq!(p["number"], i + 1);
assert!(close(rect(&p["imageable"]), rect(t)), "tiles are imageable areas");
let printed = grid["printed"].as_array().unwrap().contains(&json!(i + 1));
assert_eq!(p["printed"], printed);
// The paper reaches the margin (18 pt on paper, 3 pt of the document at 600%) further.
let (pg, im) = (rect(&p["page"]), rect(&p["imageable"]));
assert!((im[0] - pg[0] - 3.0).abs() < 1e-6 && (pg[3] - im[3] - 3.0).abs() < 1e-6);
}
// Full pages: the tiles are the paper, the imageable area inside it.
let full = json!({"scaling": "tileFull", "scale": {"width": 400, "height": 400}, "margin": 18});
let pv = s.execute("print.preview", &json!({ "settings": full })).unwrap();
let pages = tiling(&mut s, full)["pages"].as_array().unwrap().clone();
assert_eq!(pages.len(), pv["tiles"][0]["tiles"].as_array().unwrap().len());
assert!(close(rect(&pages[0]["page"]), rect(&pv["tiles"][0]["tiles"][0])));
}
#[test]
fn untiled_pages_come_from_the_sheets_once_per_page() {
let mut s = session();
s.execute("artboard.new", &json!({"x": 400, "y": 0, "width": 300, "height": 200})).unwrap();
// Letter turned landscape for the wide artboards, centred on each.
let set = json!({"output": {"mode": "separations"}, "margin": 36});
let pv = s.execute("print.preview", &json!({ "settings": set })).unwrap();
assert!(pv["sheets"].as_array().unwrap().len() >= 8, "a page per ink");
let pages = tiling(&mut s, set)["pages"].as_array().unwrap().clone();
assert_eq!(pages.len(), 2, "each page once, not once per ink");
for (p, cx) in pages.iter().zip([150.0, 550.0]) {
let pg = rect(&p["page"]);
assert!(close(pg, [cx - 396.0, 100.0 - 306.0, cx + 396.0, 100.0 + 306.0]), "{pg:?}");
assert!(close(rect(&p["imageable"]), [pg[0] + 36.0, pg[1] + 36.0, pg[2] - 36.0, pg[3] - 36.0]));
}
}
#[test]
fn the_tool_puts_the_first_page_where_it_is_dragged_as_one_undo_step() {
let mut s = session();
let v = ViewInfo::default();
s.select_tool("printTiling", v).unwrap();
let undo = s.doc().unwrap().history.undo.len();
s.pointer(&PointerEvent::new(PointerKind::Down, 50.0, 50.0), v).unwrap();
s.pointer(&PointerEvent::new(PointerKind::Drag, 45.0, 40.0), v).unwrap();
s.pointer(&PointerEvent::new(PointerKind::Drag, 40.0, 30.0), v).unwrap();
s.pointer(&PointerEvent::new(PointerKind::Up, 40.0, 30.0), v).unwrap();
let st = s.doc().unwrap();
assert_eq!(st.history.undo.len(), undo + 1);
assert_eq!(st.history.undo.last().unwrap().label, "Print Tiling");
let set = s.execute("print.setup", &json!({})).unwrap()["settings"].clone();
assert_eq!(set["tileOrigin"], json!({"placed": true, "x": 40.0, "y": 30.0}));
// The page's imageable corner is the point dragged to, on the paper and on the canvas.
let pv = s.execute("print.preview", &json!({"settings": {"margin": 12}})).unwrap();
let (x, y) = apply(&pv["sheets"][0]["transform"], (40.0, 30.0));
assert!((x - 12.0).abs() < 1e-6 && (y - 12.0).abs() < 1e-6, "({x}, {y})");
let page = &tiling(&mut s, json!({"margin": 12}))["pages"][0];
assert!((rect(&page["imageable"])[0] - 40.0).abs() < 1e-6 && (rect(&page["imageable"])[1] - 30.0).abs() < 1e-6);
// Saved in the native file.
let doc = &s.doc().unwrap().doc;
assert_eq!(vectorcraft_format::load(&vectorcraft_format::save(doc, false)).unwrap().print_setup, doc.print_setup);
// A double click puts the pages back where the placement puts them.
s.pointer(&PointerEvent::new(PointerKind::DoubleClick, 10.0, 10.0), v).unwrap();
assert_eq!(s.execute("print.setup", &json!({})).unwrap()["settings"]["tileOrigin"]["placed"], false);
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(s.execute("print.setup", &json!({})).unwrap()["settings"]["tileOrigin"]["placed"], true);
s.execute("edit.undo", &json!({})).unwrap();
assert!(s.doc().unwrap().doc.print_setup.is_none());
}
#[test]
fn tiles_start_at_the_tile_origin_and_cover_the_art() {
let mut s = session();
let tiles = json!({"scaling": "tileImageable", "scale": {"width": 400, "height": 400}});
s.execute("print.setup", &json!({ "settings": tiles })).unwrap();
let before = tiling(&mut s, json!({}))["pages"].as_array().unwrap().len();
s.execute("print.tiling.set", &json!({"origin": [60, 35]})).unwrap();
let pages = tiling(&mut s, json!({}))["pages"].as_array().unwrap().clone();
let pv = s.execute("print.preview", &json!({})).unwrap();
assert_eq!(pages.len(), pv["tiles"][0]["tiles"].as_array().unwrap().len(), "tile count equals print.preview");
assert_eq!(pages.len(), pv["sheets"].as_array().unwrap().len());
assert!(pages.len() > before, "the grid moved off the corner takes more tiles");
let rects: Vec<[f64; 4]> = pages.iter().map(|p| rect(&p["imageable"])).collect();
assert!(rects.iter().any(|r| (r[0] - 60.0).abs() < 1e-6 && (r[1] - 35.0).abs() < 1e-6), "a tile starts at the origin");
let all = rects.iter().fold([f64::MAX, f64::MAX, f64::MIN, f64::MIN], |a, r| [a[0].min(r[0]), a[1].min(r[1]), a[2].max(r[2]), a[3].max(r[3])]);
assert!(all[0] <= 0.0 && all[1] <= 0.0 && all[2] >= 300.0 && all[3] >= 200.0, "the tiles cover the artboard: {all:?}");
// Bad input is refused.
assert!(s.execute("print.tiling.set", &json!({})).is_err());
assert!(s.execute("print.tiling.set", &json!({"origin": [1, 2], "artboard": 7})).is_err());
assert!(s.execute("print.tiling.set", &json!({"origin": [1e9, 2]})).is_err());
}
#[test]
fn settings_saved_before_the_tile_origin_still_load() {
let mut s = session();
let mut old = serde_json::to_value(vectorcraft_pdf::PrintSettings::default()).unwrap();
old.as_object_mut().unwrap().remove("tileOrigin");
old["copies"] = json!(2);
let mut doc = (*s.doc().unwrap().doc).clone();
doc.print_setup = Some(old);
s.doc_mut().unwrap().doc = std::sync::Arc::new(doc);
let set = s.execute("print.setup", &json!({})).unwrap()["settings"].clone();
assert_eq!((set["copies"].clone(), set["tileOrigin"]["placed"].clone()), (json!(2), json!(false)));
assert_eq!(tiling(&mut s, json!({}))["pages"].as_array().unwrap().len(), 1);
}