//! View → Show Print Tiling (`view.printTiling`) and the Print Tiling tool (`print.tiling.set`): //! the pages of the document's print settings drawn on the canvas, from `print.preview`'s layout //! (`print.tiling`), and where the tool put them ([`vectorcraft_pdf::TileOrigin`], saved with //! the print settings). use serde_json::{Value, json}; use vectorcraft_doc::Document; use vectorcraft_geom::Point; use vectorcraft_pdf::{TileOrigin, TilingPage}; use super::fileio::pdf::pdf_error; use super::print::{settings, to_json}; use super::*; const SET: &str = "print.tiling.set"; pub fn specs() -> Vec { vec![ cmd!( query "view.printTiling", "Show Print Tiling", ["View"], None, "{on?: bool (default: toggle)} show the pages of the document's print settings on the canvas (each document has its own setting; the Print Tiling tool shows them too) → {on}", has_doc, show ), cmd!( "print.tiling.set", "Print Tiling", [], None, "{origin: [x, y] (document point: the top-left corner of the first page's imageable area), artboard? (0-based: the artboard it is measured from; default the printed artboard containing origin, else the first; ignored with artboards: ignore)} | {reset: true} place the printed pages as the Print Tiling tool does, saved with the print settings (tileOrigin: {placed, x, y}, from the artboard's top-left corner; it replaces the placement, and tiles start there), as one undo step; reset → the placement places them again → {tileOrigin}", has_doc, set_origin ), cmd!( query "print.tiling", "Print Tiling Pages", [], None, "{settings?: {…print.setup settings} (over the document's)} the pages as View → Show Print Tiling draws them, from print.preview's layout → {tileOrigin, pages: [{artboard (0-based; null with artboards ignored), number (1-based tile across then down, or page), printed (tiles outside tileRange don't), page: [x0, y0, x1, y1] (the paper's edge), imageable: [x0, y0, x1, y1] (inside the unprintable margin)}] (document space; every tile when tiling, else each page once)}", has_doc, tiling ), ] } fn show(s: &mut Session, p: &Value) -> Result { let st = s.doc_mut()?; st.print_tiling = p.get("on").and_then(Value::as_bool).unwrap_or(!st.print_tiling); Ok(json!({ "on": st.print_tiling })) } /// The pages of `doc`'s print settings in document space (what View → Show Print Tiling draws); /// an error when they can't print. pub fn pages(doc: &Document) -> Result> { pages_with(doc, &json!({})) } fn pages_with(doc: &Document, p: &Value) -> Result> { const C: &str = "print.tiling"; let set = settings(C, doc, p)?; let pv = vectorcraft_pdf::preview(doc, &set).map_err(|e| pdf_error(C, e))?; Ok(vectorcraft_pdf::tiling(&pv, &set)) } fn tiling(s: &mut Session, p: &Value) -> Result { let doc = &s.doc()?.doc; let origin = settings("print.tiling", doc, p)?.tile_origin; Ok(json!({ "tileOrigin": origin, "pages": pages_with(doc, p)? })) } /// `[x, y]` at `key` of `p`. fn point(p: &Value, key: &str) -> Option { let a = p.get(key)?.as_array()?; Some(Point::new(a.first()?.as_f64()?, a.get(1)?.as_f64()?)) } fn set_origin(s: &mut Session, p: &Value) -> Result { let doc = &s.doc()?.doc; let current = settings(SET, doc, &json!({}))?; let mut set = current.clone(); set.tile_origin = if bool_or(p, "reset", false) { TileOrigin::default() } else { let at = point(p, "origin").filter(|q| q.x.is_finite() && q.y.is_finite()); let at = at.ok_or_else(|| bad(SET, "give origin: [x, y], or reset: true"))?; let regions = vectorcraft_pdf::print_regions(doc, &set).map_err(|e| pdf_error(SET, e))?; let picked = match p.get("artboard").filter(|v| !v.is_null()) { Some(v) => { let i = v.as_u64().ok_or_else(|| bad(SET, "artboard must be a 0-based index"))? as usize; regions.iter().find(|(a, _)| a.is_none() || *a == Some(i)).ok_or_else(|| bad(SET, format!("artboard {i} doesn't print")))? } None => regions.iter().find(|(_, r)| r.contains(at)).or(regions.first()).ok_or_else(|| bad(SET, "nothing prints"))?, }; let corner = picked.1.origin(); TileOrigin { placed: true, x: at.x - corner.x, y: at.y - corner.y } }; set.check().map_err(|e| pdf_error(SET, e))?; if set != current { let stored = to_json(&set)?; s.edit("Print Tiling", |d, _| { d.print_setup = Some(stored); Ok(()) })?; } Ok(json!({ "tileOrigin": set.tile_origin })) }