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:
dotCooCoo
2026-10-16 14:58:09 +07:00
committed by bflatastic
parent 467c47b719
commit cc3299dc0f
9 changed files with 149 additions and 32 deletions
+18
View File
@@ -198,6 +198,24 @@ pub fn art_bounds(doc: &Document) -> Option<Rect> {
doc.layers.iter().fold(None, |acc, l| vectorcraft_geom::union_opt(acc, drawn_bounds(&symbols, l)))
}
/// Bounds of the art an export draws ([`art_bounds`]) that is on artboard rectangle `rect`: each
/// object of a layer or sublayer whose drawn bounds overlap `rect`, with all of its bounds; a group
/// or a clipping layer counts as one object. `None` when no object overlaps `rect`.
pub fn art_bounds_on(doc: &Document, rect: Rect) -> Option<Rect> {
// Art flush with an edge from outside can overlap it by a rounding error (#1295).
let rect = rect.inflate(-1e-6, -1e-6);
fn on(symbols: &SymbolBoxes, n: &Node, rect: Rect) -> Option<Rect> {
match &n.kind {
NodeKind::Layer { template: false, clip: false, children, .. } if n.visible => {
children.iter().fold(None, |acc, c| vectorcraft_geom::union_opt(acc, on(symbols, c, rect)))
}
_ => drawn_bounds(symbols, n).filter(|b| b.x0 < rect.x1 && b.x1 > rect.x0 && b.y0 < rect.y1 && b.y1 > rect.y0),
}
}
let symbols = doc.symbol_boxes();
doc.layers.iter().fold(None, |acc, l| vectorcraft_geom::union_opt(acc, on(&symbols, l, rect)))
}
fn drawn_bounds(symbols: &SymbolBoxes, n: &Node) -> Option<Rect> {
if !n.visible {
return None;