mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-01 05:37:23 -06:00
Artboards: Fit to Artwork Bounds fits each selected artboard to the art on it
Fit to Artwork Bounds resized the active artboard to the bounds of all the art in the document, wherever that art was. With art on two artboards, fitting one of them stretched it over both. artboard.fitToArt now takes `indices` and fits each artboard to the art on it, in one undo step. An object counts for every artboard its drawn bounds overlap, and the artboard is fitted to all of its bounds, also where it reaches past the artboard's edge. Art flush with an edge from outside does not count. An artboard with no art on it keeps its size and place, and the command fails with "no artwork" when none of its artboards has art. Object › Artboards and the Artboards panel menu pass the selected artboards (the Artboard tool's, else the active one), and a recorded action leaves them out. Fit to Selected Art still resizes the active artboard. Docs: docs/mcp.md, docs/target-app-parity.md.
This commit is contained in:
@@ -152,7 +152,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Fit to Artwork Bounds",
|
||||
["Object", "Artboards"],
|
||||
None,
|
||||
"{index?: n (0-based; the app passes the active artboard; default: the first)} the artboard fits the art that shows (with its strokes and effects; hidden objects and layers, guides and template layers don't count)",
|
||||
"{index?: n | indices?: [n…] (0-based; the app passes the selected artboards: the Artboard tool's, else the active one; default: the first)} each artboard fits the art on it that shows (with its strokes and effects; hidden objects and layers, guides and template layers don't count), in one undo step: an object counts for every artboard its bounds overlap, and a group or clipping layer counts as one object; an artboard with no art stays as it is, and the command fails when no artboard it names has art",
|
||||
has_doc,
|
||||
artboard_fit_art
|
||||
),
|
||||
@@ -161,7 +161,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Fit to Selected Art",
|
||||
["Object", "Artboards"],
|
||||
None,
|
||||
"{index?: n (0-based; the app passes the active artboard; default: the first)}",
|
||||
"{index?: n (0-based; the app passes the active artboard; default: the first)} the artboard fits the selected art (with its strokes)",
|
||||
has_selection,
|
||||
artboard_fit_sel
|
||||
),
|
||||
@@ -898,12 +898,38 @@ fn rect_map(from: Rect, to: Rect) -> Option<Affine> {
|
||||
xf.is_finite().then_some(xf)
|
||||
}
|
||||
|
||||
/// The artboard fits the art that exports draw: hidden objects and layers, guides and template
|
||||
/// layers don't count.
|
||||
/// Each artboard of `index` or `indices` (default: the first) fits the art on it that exports
|
||||
/// draw ([`vectorcraft_render::encode::art_bounds_on`]): hidden objects and layers, guides and
|
||||
/// template layers don't count. An artboard with no art on it stays as it is, and the command
|
||||
/// fails when none has art. The fits are one undo step named Artboard Options.
|
||||
fn artboard_fit_art(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let i = p.get("index").and_then(Value::as_u64).unwrap_or(0) as usize;
|
||||
let b = vectorcraft_render::encode::art_bounds(&s.doc()?.doc).ok_or_else(|| EngineError::Other("no artwork".into()))?;
|
||||
s.execute("artboard.setProps", &json!({"index": i, "x": b.x0, "y": b.y0, "width": b.width(), "height": b.height()}))
|
||||
let d = &s.doc()?.doc;
|
||||
let indices =
|
||||
if p.get("index").is_none() && p.get("indices").is_none() { vec![0] } else { super::panelcmds::artboard_indices(d, p, "artboard.fitToArt")? };
|
||||
let mut fits = vec![];
|
||||
for i in indices {
|
||||
let was = d.artboards.get(i).map(|a| a.rect).ok_or_else(|| EngineError::Other("no such artboard".into()))?;
|
||||
if let Some(b) = vectorcraft_render::encode::art_bounds_on(d, was) {
|
||||
// At least 1 pt a side, as `rect_from` makes Artboard Options' sizes.
|
||||
fits.push((i, was, Rect::new(b.x0, b.y0, b.x0 + b.width().max(1.0), b.y0 + b.height().max(1.0))));
|
||||
}
|
||||
}
|
||||
if fits.is_empty() {
|
||||
return Err(EngineError::Other("no artwork".into()));
|
||||
}
|
||||
s.edit("Artboard Options", |d, _| {
|
||||
for &(i, was, now) in &fits {
|
||||
let a = d.artboards.get_mut(i).ok_or_else(|| EngineError::Other("no such artboard".into()))?;
|
||||
a.rect = now;
|
||||
let id = a.id;
|
||||
// Moved and not resized, it takes its guides along, as in Artboard Options.
|
||||
if (now.width() - was.width()).abs() <= 1e-6 && (now.height() - was.height()).abs() <= 1e-6 {
|
||||
d.move_artboard_guides(id, now.origin() - was.origin());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
ok()
|
||||
}
|
||||
|
||||
fn artboard_fit_sel(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
Reference in New Issue
Block a user