mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
120 lines
5.3 KiB
Rust
120 lines
5.3 KiB
Rust
//! Painting a previously unpainted zero-width stroke restores the existing 1 pt default.
|
|
#![allow(clippy::unwrap_used)]
|
|
|
|
use serde_json::json;
|
|
use vectorcraft_doc::NodeId;
|
|
use vectorcraft_engine::{Session, ViewInfo};
|
|
use vectorcraft_tools::{PointerEvent, PointerKind};
|
|
|
|
fn fixture() -> (Session, NodeId) {
|
|
let mut s = Session::new();
|
|
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
|
|
let id = rectangle(&mut s, 10.0);
|
|
(s, id)
|
|
}
|
|
|
|
fn rectangle(s: &mut Session, x: f64) -> NodeId {
|
|
NodeId(s.execute("shape.rectangle", &json!({"x": x, "y": 10, "width": 50, "height": 40})).unwrap()["id"].as_u64().unwrap())
|
|
}
|
|
|
|
fn width(s: &Session, id: NodeId) -> f64 {
|
|
s.doc().unwrap().doc.node(id).unwrap().appearance.stroke().unwrap().width
|
|
}
|
|
|
|
#[test]
|
|
fn adding_a_stroke_after_sampling_strokeless_art_makes_it_visible_in_one_undo_step() {
|
|
let (mut s, _) = fixture();
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
s.execute("select.set", &json!({"ids": []})).unwrap();
|
|
s.select_tool("eyedropper", ViewInfo::default()).unwrap();
|
|
s.pointer(&PointerEvent::new(PointerKind::Down, 25.0, 25.0), ViewInfo::default()).unwrap();
|
|
let id = rectangle(&mut s, 100.0);
|
|
assert_eq!(width(&s, id), 0.0, "sampled None paint is a normal source of a zero-width stroke");
|
|
let st = s.doc().unwrap();
|
|
let before = st.doc.clone();
|
|
let sel = st.selection.clone();
|
|
let history = st.history.undo.len();
|
|
let geometry = st.doc.node(id).unwrap().geometric_bounds();
|
|
s.execute("paint.setStroke", &json!({"color": "#ee2222"})).unwrap();
|
|
assert_eq!(width(&s, id), 1.0);
|
|
let st = s.doc().unwrap();
|
|
assert_eq!(st.doc.node(id).unwrap().geometric_bounds(), geometry);
|
|
assert_eq!(json!(st.selection), json!(sel));
|
|
assert_eq!(st.history.undo.len(), history + 1);
|
|
let after = st.doc.clone();
|
|
s.execute("edit.undo", &json!({})).unwrap();
|
|
assert_eq!(json!(s.doc().unwrap().doc), json!(before));
|
|
s.execute("edit.redo", &json!({})).unwrap();
|
|
assert_eq!(json!(s.doc().unwrap().doc), json!(after));
|
|
}
|
|
|
|
#[test]
|
|
fn adding_stroke_paint_to_the_defaults_gives_the_next_shape_a_visible_stroke() {
|
|
let (mut s, _) = fixture();
|
|
s.execute("select.set", &json!({"ids": []})).unwrap();
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
s.execute("stroke.set", &json!({"weight": 0})).unwrap();
|
|
s.execute("paint.setStroke", &json!({"color": "#ee2222"})).unwrap();
|
|
assert_eq!(s.new_art_stroke().width, 1.0);
|
|
let id = rectangle(&mut s, 100.0);
|
|
assert_eq!(width(&s, id), 1.0);
|
|
}
|
|
|
|
#[test]
|
|
fn swapping_fill_into_an_unpainted_zero_width_stroke_makes_it_visible() {
|
|
let (mut s, id) = fixture();
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
s.execute("stroke.set", &json!({"weight": 0})).unwrap();
|
|
let fill = s.doc().unwrap().doc.node(id).unwrap().appearance.fill_paint();
|
|
s.execute("paint.swap", &json!({})).unwrap();
|
|
let n = s.doc().unwrap().doc.node(id).unwrap();
|
|
assert!(n.appearance.fill_paint().is_none());
|
|
assert_eq!(n.appearance.stroke_paint(), fill);
|
|
assert_eq!(width(&s, id), 1.0);
|
|
assert_eq!(s.new_art_stroke().width, 1.0);
|
|
}
|
|
|
|
#[test]
|
|
fn a_targeted_stroke_is_restored_without_changing_the_other_stroke() {
|
|
let (mut s, id) = fixture();
|
|
s.execute("stroke.set", &json!({"weight": 5})).unwrap();
|
|
s.execute("appearance.addStroke", &json!({})).unwrap();
|
|
s.execute("paint.setStroke", &json!({"item": 1, "none": true})).unwrap();
|
|
s.execute("stroke.set", &json!({"item": 1, "weight": 0})).unwrap();
|
|
s.execute("paint.setStroke", &json!({"item": 1, "color": "#ee2222"})).unwrap();
|
|
let ap = &s.doc().unwrap().doc.node(id).unwrap().appearance;
|
|
assert_eq!(ap.stroke_at(Some(1)).unwrap().width, 1.0);
|
|
assert_eq!(ap.stroke_at(Some(2)).unwrap().width, 5.0);
|
|
}
|
|
|
|
#[test]
|
|
fn existing_weights_and_explicitly_zero_painted_strokes_keep_their_widths() {
|
|
for (was_none, weight) in [(true, 5.0), (false, 5.0), (false, 0.0)] {
|
|
let (mut s, id) = fixture();
|
|
if was_none {
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
}
|
|
s.execute("stroke.set", &json!({"weight": weight})).unwrap();
|
|
s.execute("paint.setStroke", &json!({"color": "#ee2222"})).unwrap();
|
|
assert_eq!(width(&s, id), weight);
|
|
}
|
|
let (mut s, id) = fixture();
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
s.execute("stroke.set", &json!({"weight": 0})).unwrap();
|
|
s.execute("paint.setFill", &json!({"color": "#ffaa00"})).unwrap();
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
assert_eq!(width(&s, id), 0.0, "fill edits and removing paint do not enable a stroke");
|
|
}
|
|
|
|
#[test]
|
|
fn appearance_panel_stroke_colour_restores_an_unpainted_zero_width_stroke() {
|
|
let (mut s, id) = fixture();
|
|
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
|
s.execute("stroke.set", &json!({"weight": 0})).unwrap();
|
|
s.execute("appearance.setItem", &json!({"index": 1, "color": "#00ff00"})).unwrap();
|
|
assert_eq!(width(&s, id), 1.0);
|
|
s.execute("appearance.setItem", &json!({"index": 1, "weight": 0})).unwrap();
|
|
s.execute("appearance.setItem", &json!({"index": 1, "color": "#0000ff"})).unwrap();
|
|
assert_eq!(width(&s, id), 0.0, "a painted stroke keeps an explicit zero width");
|
|
}
|