111 lines
4.9 KiB
Rust
111 lines
4.9 KiB
Rust
//! Stroke panel reach: `stroke.set` on groups, what the panel shows for a selection (mixed values,
|
|
//! Align Stroke), Units > Stroke, and the stroke options `document.inspect` reports.
|
|
|
|
use serde_json::{Value, json};
|
|
use vectorcraft_doc::{NodeId, NodeKind, Unit};
|
|
|
|
use super::*;
|
|
|
|
fn session() -> Session {
|
|
let mut s = Session::new();
|
|
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
|
|
s
|
|
}
|
|
|
|
fn run(s: &mut Session, id: &str, p: Value) -> Value {
|
|
s.execute(id, &p).unwrap_or_else(|e| panic!("{id}: {e}"))
|
|
}
|
|
|
|
fn rect(s: &mut Session, x: f64) -> NodeId {
|
|
NodeId(run(s, "shape.rectangle", json!({"x": x, "y": 10, "width": 40, "height": 40}))["id"].as_u64().unwrap())
|
|
}
|
|
|
|
fn select(s: &mut Session, ids: &[NodeId]) {
|
|
run(s, "select.set", json!({ "ids": ids.iter().map(|i| i.0).collect::<Vec<_>>() }));
|
|
}
|
|
|
|
#[test]
|
|
fn stroke_set_on_a_group_skips_images_and_symbol_instances() {
|
|
let mut s = session();
|
|
let (a, b, c) = (rect(&mut s, 10.0), rect(&mut s, 60.0), rect(&mut s, 110.0));
|
|
select(&mut s, &[b]);
|
|
let image = NodeId(run(&mut s, "object.rasterize", json!({}))["id"].as_u64().unwrap());
|
|
select(&mut s, &[c]);
|
|
let instance = NodeId(run(&mut s, "symbol.new", json!({"name": "Box"}))["id"].as_u64().unwrap());
|
|
select(&mut s, &[a, image, instance]);
|
|
run(&mut s, "object.group", json!({}));
|
|
run(&mut s, "stroke.set", json!({"weight": 5}));
|
|
let d = &s.doc().unwrap().doc;
|
|
assert_eq!(d.node(a).unwrap().appearance.stroke_width(), 5.0);
|
|
for id in [image, instance] {
|
|
let n = d.node(id).unwrap();
|
|
assert!(matches!(n.kind, NodeKind::Image(_) | NodeKind::SymbolInstance { .. }));
|
|
assert!(n.appearance.stroke().is_none(), "{:?} gains no stroke", n.kind_label());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn mixed_values_and_align_stroke_follow_the_selection() {
|
|
let mut s = session();
|
|
let (a, b) = (rect(&mut s, 10.0), rect(&mut s, 60.0));
|
|
run(&mut s, "stroke.set", json!({"ids": [b.0], "weight": 3, "join": "round"}));
|
|
select(&mut s, &[a, b]);
|
|
let m = s.active().unwrap().stroke_mixed();
|
|
assert!(m.weight && m.join && !m.cap && !m.miter_limit && !m.align && !m.dash && m.can_align, "{m:?}");
|
|
// An open path or type in the selection can't take an inside or outside stroke.
|
|
let line = NodeId(run(&mut s, "shape.line", json!({"x1": 10, "y1": 100, "x2": 90, "y2": 100}))["id"].as_u64().unwrap());
|
|
select(&mut s, &[a, line]);
|
|
assert!(!s.active().unwrap().stroke_mixed().can_align);
|
|
let text = NodeId(run(&mut s, "text.create", json!({"x": 10, "y": 200, "text": "Hi"}))["id"].as_u64().unwrap());
|
|
select(&mut s, &[text]);
|
|
assert!(!s.active().unwrap().stroke_mixed().can_align);
|
|
// Grouped closed paths can.
|
|
select(&mut s, &[a, b]);
|
|
run(&mut s, "object.group", json!({}));
|
|
let m = s.active().unwrap().stroke_mixed();
|
|
assert!(m.can_align && m.weight);
|
|
assert_eq!(s.shown_stroke().map(|st| st.width), Some(1.0), "a group shows its first painted object's stroke");
|
|
}
|
|
|
|
#[test]
|
|
fn stroke_unit_follows_the_preference() {
|
|
let mut s = session();
|
|
assert_eq!(s.stroke_unit(), Unit::Points);
|
|
s.prefs.units_stroke = "millimeters".into();
|
|
assert_eq!(s.stroke_unit(), Unit::Millimeters);
|
|
assert_eq!(s.stroke_unit().format(1.0), "0.3528 mm");
|
|
}
|
|
|
|
#[test]
|
|
fn inspect_reports_stroke_options() {
|
|
let mut s = session();
|
|
let line = run(&mut s, "shape.line", json!({"x1": 10, "y1": 100, "x2": 90, "y2": 100}))["id"].as_u64().unwrap();
|
|
run(
|
|
&mut s,
|
|
"stroke.set",
|
|
json!({"ids": [line], "cap": "round", "join": "bevel", "miterLimit": 4, "dash": [6, 3], "alignDashes": true, "endArrow": "Triangle", "arrowAlign": "tip", "profile": "lens"}),
|
|
);
|
|
let doc = run(&mut s, "document.inspect", json!({}));
|
|
let o = &doc["layers"][0]["children"][0]["strokeOptions"];
|
|
assert_eq!(o["cap"], "round");
|
|
assert_eq!(o["join"], "bevel");
|
|
assert_eq!(o["miterLimit"], 4.0);
|
|
assert_eq!(o["align"], "center");
|
|
assert_eq!(o["dash"], json!([6.0, 3.0]));
|
|
assert_eq!(o["alignDashes"], true);
|
|
assert_eq!((o["startArrow"].clone(), o["endArrow"].clone(), o["arrowAlign"].clone()), (Value::Null, json!("Triangle"), json!("tip")));
|
|
assert_eq!(o["profile"], "lens");
|
|
// The options read back into stroke.set unchanged.
|
|
let mut q = o.as_object().unwrap().clone();
|
|
q.insert("ids".into(), json!([line]));
|
|
let before = s.doc().unwrap().doc.node(NodeId(line)).unwrap().appearance.clone();
|
|
run(&mut s, "stroke.set", Value::Object(q));
|
|
assert_eq!(s.doc().unwrap().doc.node(NodeId(line)).unwrap().appearance, before);
|
|
// Type reports its characters' stroke.
|
|
run(&mut s, "text.create", json!({"x": 10, "y": 200, "text": "Hi"}));
|
|
run(&mut s, "stroke.set", json!({"join": "round"}));
|
|
let doc = run(&mut s, "document.inspect", json!({}));
|
|
let text = doc["layers"][0]["children"].as_array().unwrap().iter().find(|c| c["kind"] == "Text" || c.get("text").is_some()).unwrap().clone();
|
|
assert_eq!(text["strokeOptions"]["join"], "round", "{text}");
|
|
}
|