vectorcraft/crates/engine/tests/artboard_click.rs

131 lines
6.6 KiB
Rust

//! Artboard clicks fit the object without changing its art or selection, and are one undo step.
#![allow(clippy::unwrap_used)]
use serde_json::json;
use vectorcraft_doc::NodeId;
use vectorcraft_engine::{Session, ViewInfo};
use vectorcraft_geom::Rect;
use vectorcraft_tools::{Mods, PointerEvent, PointerKind, ToolKey};
fn fixture(x: f64, y: f64) -> (Session, NodeId) {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 500, "height": 500})).unwrap();
let id = s.execute("shape.rectangle", &json!({"x": x, "y": y, "width": 100, "height": 60})).unwrap()["id"].as_u64().unwrap();
s.execute("stroke.set", &json!({"weight": 10})).unwrap();
s.select_tool("artboard", ViewInfo::default()).unwrap();
(s, NodeId(id))
}
fn pointer(s: &mut Session, kind: PointerKind, x: f64, y: f64) {
s.pointer(&PointerEvent::new(kind, x, y), ViewInfo::default()).unwrap();
}
#[test]
fn clicks_inside_and_outside_an_artboard_fit_the_visible_object_in_one_undo_step() {
for (x, y) in [(100.0, 100.0), (650.0, 700.0)] {
let (mut s, id) = fixture(x, y);
let before = s.doc().unwrap().doc.clone();
let sel = s.doc().unwrap().selection.clone();
let history = s.doc().unwrap().history.undo.len();
let at = (x + 40.0, y + 25.0);
pointer(&mut s, PointerKind::Down, at.0, at.1);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 1, "a press alone does not edit the document");
pointer(&mut s, PointerKind::Drag, at.0 + 1.0, at.1);
pointer(&mut s, PointerKind::Up, at.0 + 1.0, at.1);
let st = s.doc().unwrap();
assert_eq!(st.doc.artboards.len(), 2);
let rect = Rect::new(x - 5.0, y - 5.0, x + 105.0, y + 65.0);
assert_eq!(st.doc.artboards[1].rect, rect, "includes the visible stroke, like Fit to Selected Art");
assert_eq!(st.doc.bounds_of(&[id], true), Some(rect));
assert_eq!(json!(st.doc.layers), json!(before.layers));
assert_eq!(json!(st.selection), json!(sel));
assert_eq!(st.history.undo.len(), history + 1);
assert_eq!(s.tool_options()["active"], 1);
pointer(&mut s, PointerKind::Up, at.0, at.1);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 2, "one release creates once");
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(json!(s.doc().unwrap().doc), json!(before));
assert_eq!(json!(s.doc().unwrap().selection), json!(sel));
s.execute("edit.redo", &json!({})).unwrap();
assert_eq!(s.doc().unwrap().doc.artboards[1].rect, rect);
}
}
#[test]
fn the_topmost_group_is_fitted_instead_of_the_selection_or_its_clicked_child() {
let (mut s, bottom) = fixture(100.0, 100.0);
let a = s.execute("shape.rectangle", &json!({"x": 120, "y": 110, "width": 30, "height": 30})).unwrap()["id"].as_u64().unwrap();
let b = s.execute("shape.rectangle", &json!({"x": 250, "y": 120, "width": 40, "height": 60})).unwrap()["id"].as_u64().unwrap();
s.execute("select.set", &json!({"ids": [a, b]})).unwrap();
s.execute("object.group", &json!({})).unwrap();
let group = s.doc().unwrap().selection.objects[0];
let expected = s.doc().unwrap().doc.bounds_of(&[group], true).unwrap();
s.execute("select.set", &json!({"ids": [bottom.0]})).unwrap();
let layers = json!(s.doc().unwrap().doc.layers);
pointer(&mut s, PointerKind::Down, 135.0, 125.0);
pointer(&mut s, PointerKind::Up, 135.0, 125.0);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 2);
assert_eq!(s.doc().unwrap().doc.artboards[1].rect, expected);
assert_eq!(s.doc().unwrap().selection.objects, vec![bottom]);
assert_eq!(json!(s.doc().unwrap().doc.layers), layers);
}
#[test]
fn cancelled_clicks_do_not_create_an_artboard_or_leak_into_the_next_gesture() {
for switch in [false, true] {
let (mut s, _) = fixture(100.0, 100.0);
let before = s.doc().unwrap().doc.clone();
let history = s.doc().unwrap().history.undo.len();
pointer(&mut s, PointerKind::Down, 140.0, 125.0);
if switch {
s.select_tool("selection", ViewInfo::default()).unwrap();
s.select_tool("artboard", ViewInfo::default()).unwrap();
} else {
s.tool_key(ToolKey::Escape, Mods::default(), ViewInfo::default()).unwrap();
s.select_tool("artboard", ViewInfo::default()).unwrap();
}
pointer(&mut s, PointerKind::Up, 140.0, 125.0);
assert_eq!(json!(s.doc().unwrap().doc), json!(before));
assert_eq!(s.doc().unwrap().history.undo.len(), history);
pointer(&mut s, PointerKind::Down, 300.0, 300.0);
pointer(&mut s, PointerKind::Up, 300.0, 300.0);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 1, "empty clicks do not use a stale object");
pointer(&mut s, PointerKind::Down, 140.0, 125.0);
pointer(&mut s, PointerKind::Up, 140.0, 125.0);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 2);
}
}
#[test]
fn locked_hidden_modifier_handle_and_drag_gestures_keep_their_existing_meaning() {
for command in ["object.lock", "object.hide"] {
let (mut s, _) = fixture(100.0, 100.0);
s.execute(command, &json!({})).unwrap();
let before = s.doc().unwrap().doc.clone();
let history = s.doc().unwrap().history.undo.len();
pointer(&mut s, PointerKind::Down, 140.0, 125.0);
pointer(&mut s, PointerKind::Up, 140.0, 125.0);
assert_eq!(json!(s.doc().unwrap().doc), json!(before));
assert_eq!(s.doc().unwrap().history.undo.len(), history);
}
for mods in [Mods { shift: true, ..Default::default() }, Mods { alt: true, ..Default::default() }, Mods { cmd: true, ..Default::default() }] {
let (mut s, _) = fixture(100.0, 100.0);
for kind in [PointerKind::Down, PointerKind::Up] {
s.pointer(&PointerEvent::new(kind, 140.0, 125.0).with_mods(mods), ViewInfo::default()).unwrap();
}
assert_eq!(s.doc().unwrap().doc.artboards.len(), 1);
}
let (mut s, _) = fixture(0.0, 0.0);
pointer(&mut s, PointerKind::Down, 0.0, 0.0);
pointer(&mut s, PointerKind::Up, 0.0, 0.0);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 1, "an artboard handle wins over art beneath it");
for (x, y) in [(100.0, 100.0), (650.0, 700.0)] {
let (mut s, _) = fixture(x, y);
pointer(&mut s, PointerKind::Down, x + 40.0, y + 25.0);
pointer(&mut s, PointerKind::Drag, x + 80.0, y + 50.0);
pointer(&mut s, PointerKind::Drag, x + 40.0, y + 25.0);
pointer(&mut s, PointerKind::Up, x + 40.0, y + 25.0);
assert_eq!(s.doc().unwrap().doc.artboards.len(), 1, "a drag returning to its start does not become an object click");
}
}