mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 17:09:46 +00:00
.ai import: hidden ruler guides open as ruler guides with their own state
A straight `(N) *` guide path that runs across the canvas or an artboard opens as a ruler guide, but a hidden one (`1 Xw`) stayed a guide path. It now opens as a ruler guide too, and every ruler guide made from such a path keeps the path's hide, lock and name, so its Layers row shows them. Before, a locked guide opened unlocked and a named one lost its name. Hidden or locked guide paths that are short, slanted, grouped or `(S) *` stay guide paths, and commented copies (`%_`) are still left out. Docs: docs/target-app-parity.md, docs/file-format-parity.md.
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
//! next layers: a clipping group in each layer, read by [`masks`].
|
||||
//! - Ruler guides: a straight `(N) *` guide path, directly on a layer, that runs across the whole
|
||||
//! canvas (16,383 points around the template box's centre) or from edge to edge of one artboard
|
||||
//! is a ruler guide on that layer ([`Document::guides`]); other guide paths stay paths.
|
||||
//! is a ruler guide on that layer ([`Document::guides`]), shown or hidden, with the path's name,
|
||||
//! lock and visibility; other guide paths stay paths.
|
||||
//! - Groups `u` … `U`, compound paths `*u` … `*U`, clipping groups `q` … `Q` (the path painted
|
||||
//! with `W` clips); a group's transparency and name follow its end. A wraparound group `*w` …
|
||||
//! `*W` (version 7 specification §15.4.2) is a group whose objects other than its type wrap
|
||||
|
||||
@@ -234,11 +234,10 @@ impl<'a> Reader<'a> {
|
||||
}
|
||||
let kind = NodeKind::Path { path, rule: gs.rule, live: None, clipping: clip, guide };
|
||||
let mut node = self.new_node(kind, &gs);
|
||||
// A ruler guide is written as a straight `(N) *` guide path on its layer.
|
||||
// A ruler guide is written as a straight `(N) *` guide path on its layer, shown or hidden.
|
||||
if guide
|
||||
&& op == "N"
|
||||
&& !hidden
|
||||
&& !gs.hidden
|
||||
&& !clip
|
||||
&& self.pattern.is_none()
|
||||
&& matches!(self.frames.last(), Some(Frame { kind: Kind::Layer(_), .. }))
|
||||
|
||||
@@ -1443,7 +1443,8 @@ fn ruler_guide(a: Point, b: Point, centre: Option<(f64, f64)>, boards: &[Rect])
|
||||
}
|
||||
|
||||
/// Makes the children of the layers and sublayers of `nodes` that `pick` makes a guide of into
|
||||
/// ruler guide nodes with the same ids, moved to the top of their layer in their order.
|
||||
/// ruler guide nodes with the same ids, names, locks and visibility, moved to the top of their layer
|
||||
/// in their order.
|
||||
fn take_ruler_guides(nodes: &mut [Arc<Node>], pick: &dyn Fn(NodeId) -> Option<Guide>, depth: usize) {
|
||||
if depth > MAX_DEPTH {
|
||||
return;
|
||||
@@ -1456,7 +1457,11 @@ fn take_ruler_guides(nodes: &mut [Arc<Node>], pick: &dyn Fn(NodeId) -> Option<Gu
|
||||
let mut guides = vec![];
|
||||
kids.retain(|k| match pick(k.id) {
|
||||
Some(g) => {
|
||||
guides.push(Arc::new(Node::new(k.id, NodeKind::RulerGuide { vertical: g.vertical, pos: g.pos, artboard: g.artboard })));
|
||||
let mut n = Node::new(k.id, NodeKind::RulerGuide { vertical: g.vertical, pos: g.pos, artboard: g.artboard });
|
||||
n.name = k.name.clone();
|
||||
n.locked = k.locked;
|
||||
n.visible = k.visible;
|
||||
guides.push(Arc::new(n));
|
||||
false
|
||||
}
|
||||
None => true,
|
||||
|
||||
@@ -8786,7 +8786,8 @@ fn other_guide_paths_stay_guide_paths() {
|
||||
guide_line(0.0, 30.0, 200.0, 30.0, "S"),
|
||||
guide_line(-7885.0, -7796.0, 8498.0, 8587.0, "N"),
|
||||
format!("u\n{}U\n", guide_line(-7885.0, 40.0, 8498.0, 40.0, "N")),
|
||||
format!("1 Xw\n{}0 Xw\n", guide_line(-7885.0, 40.0, 8498.0, 40.0, "N")),
|
||||
format!("1 Xw\n{}0 Xw\n", guide_line(20.0, 40.0, 80.0, 40.0, "N")),
|
||||
format!("1 A\n{}0 A\n", guide_line(-7885.0, 40.0, 8498.0, 40.0, "S")),
|
||||
"-7885 40 m\n306 40 L\n8498 40 L\n(N) *\n".to_string(),
|
||||
];
|
||||
for body in cases {
|
||||
@@ -8796,6 +8797,35 @@ fn other_guide_paths_stay_guide_paths() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A hidden (`1 Xw`), locked (`1 A`) or named ruler guide path is a ruler guide that keeps its own
|
||||
/// visibility, lock and name, across the canvas or an artboard, on a shown layer.
|
||||
#[test]
|
||||
fn hidden_locked_and_named_guide_paths_are_ruler_guides() {
|
||||
let body = format!(
|
||||
"1 Xw\n{}0 Xw\n1 A\n{}0 A\n{}%_/ArtDictionary :\n%_(Mark) /String (AIArtName) ,\n%_;\n%_\n1 Xw\n{}0 Xw\n",
|
||||
guide_line(-7885.0, 40.0, 8498.0, 40.0, "N"),
|
||||
guide_line(25.0, 8587.0, 25.0, -7796.0, "N"),
|
||||
guide_line(-7885.0, 90.0, 8498.0, 90.0, "N"),
|
||||
guide_line(0.0, 30.0, 200.0, 30.0, "N"),
|
||||
);
|
||||
let doc = read(canvas_stream(&layer(&body)).as_bytes()).unwrap().doc;
|
||||
let top = &doc.layers[0];
|
||||
assert!(top.visible);
|
||||
let kids = top.children().unwrap();
|
||||
assert_eq!(kids.len(), 4);
|
||||
assert!(kids.iter().all(|c| c.is_ruler_guide()), "no guide path is left");
|
||||
let got: Vec<_> = doc.ruler_guides().into_iter().map(|g| (g.vertical, g.pos, g.artboard, g.layer, g.hidden, g.locked, g.name)).collect();
|
||||
let want = [
|
||||
(false, 60.0, None, Some(top.id), true, false, None),
|
||||
(true, 25.0, None, Some(top.id), false, true, None),
|
||||
(false, 10.0, None, Some(top.id), false, false, Some("Mark".to_string())),
|
||||
(false, 70.0, Some(1), Some(top.id), true, false, None),
|
||||
];
|
||||
assert_eq!(got, want);
|
||||
// The nodes themselves carry the state, so the Layers rows show it.
|
||||
assert_eq!(kids.iter().map(|k| (k.visible, k.locked)).collect::<Vec<_>>(), [(false, false), (true, true), (true, false), (false, false)]);
|
||||
}
|
||||
|
||||
/// The layer whose `Lb` has `ops` as its options (the first one in the file).
|
||||
fn layer_with(ops: &str) -> Node {
|
||||
let doc = read_ok(&format!("%AI5_BeginLayer\n{ops} Lb\n(L) Ln\nLB\n%AI5_EndLayer--\n")).doc;
|
||||
|
||||
Reference in New Issue
Block a user