mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 04:07:12 -06:00
Merge pull request #1354 from dotCooCoo/feat/direct-selection-pattern-tiles
Part of #394: art moved whole with direct-selected anchors follows Transform Pattern Tiles
This commit is contained in:
@@ -86,7 +86,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Nudge",
|
||||
[],
|
||||
None,
|
||||
"{dx: -1|0|1, dy: -1|0|1, big?: bool (×10), copy?: bool} arrow-key nudge by the keyboard increment (the selected anchors, else objects, else ruler guides)",
|
||||
"{dx: -1|0|1, dy: -1|0|1, big?: bool (×10), copy?: bool, patterns?: bool (Transform Patterns: pattern fills and strokes transform with the objects that move whole; default: prefs transformPatternTiles)} arrow-key nudge by the keyboard increment (the selected anchors, else objects, else ruler guides)",
|
||||
has_selection_or_guides,
|
||||
nudge
|
||||
),
|
||||
@@ -337,7 +337,7 @@ fn nudge(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if dx == 0.0 && dy == 0.0 {
|
||||
return ok();
|
||||
}
|
||||
return super::path::move_anchors(s, &json!({ "dx": dx, "dy": dy }));
|
||||
return super::path::move_anchors(s, &json!({ "dx": dx, "dy": dy, "patterns": p.get("patterns") }));
|
||||
}
|
||||
if s.doc()?.selection.is_empty() {
|
||||
let copy = bool_or(p, "copy", false);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::{NodeId, NodeKind};
|
||||
use vectorcraft_doc::{NodeId, NodeKind, Scaling};
|
||||
use vectorcraft_geom::{AnchorKind, PathData, Point, SubPath, Vec2};
|
||||
|
||||
use super::create::anchor_from_json;
|
||||
@@ -27,7 +27,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Move Anchors",
|
||||
[],
|
||||
None,
|
||||
"{dx, dy} move direct-selected anchors (whole paths if fully selected)",
|
||||
"{dx, dy, patterns?: bool (Transform Patterns: pattern fills and strokes transform with the objects that move whole; default: prefs transformPatternTiles)} move direct-selected anchors (whole paths if fully selected)",
|
||||
has_selection,
|
||||
move_anchors
|
||||
),
|
||||
@@ -172,6 +172,10 @@ pub(crate) fn move_anchors(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let sel = st.selection.clone();
|
||||
let scale_strokes = s.prefs.scale_strokes;
|
||||
let _ = scale_strokes;
|
||||
// Objects selected whole (with no entry in `sel.anchors`) move as objects, and their pattern
|
||||
// tiles move with them when `patterns` (default: General › Transform Pattern Tiles) is on.
|
||||
let whole: Vec<NodeId> = sel.objects.iter().copied().filter(|id| !sel.anchors.contains_key(id)).collect();
|
||||
let sc = Scaling { patterns: super::object::transform_patterns(s, p, &whole)?, ..Scaling::default() };
|
||||
s.edit("Move", |doc, _| {
|
||||
for id in &sel.objects {
|
||||
match sel.anchors.get(id) {
|
||||
@@ -185,7 +189,7 @@ pub(crate) fn move_anchors(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
None => {
|
||||
if let Some(n) = doc.node_mut(*id) {
|
||||
n.transform(vectorcraft_geom::Affine::translate(d), false);
|
||||
n.transform(vectorcraft_geom::Affine::translate(d), sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,6 +699,59 @@ fn art_moved_with_its_artboard_follows_transform_pattern_tiles() {
|
||||
}
|
||||
}
|
||||
|
||||
/// General › Transform Pattern Tiles (#394) applies to the objects selected whole that move with
|
||||
/// direct-selected anchors (an arrow key, `path.moveAnchors` or a Direct Selection drag of an
|
||||
/// anchor): off, the tiles of a pattern-filled square stay in place; on, they move with it, and
|
||||
/// `patterns: false` keeps them in place for one call.
|
||||
#[test]
|
||||
fn whole_objects_moved_with_selected_anchors_follow_transform_pattern_tiles() {
|
||||
use vectorcraft_tools::PointerKind::{Down, Drag, Up};
|
||||
let mut s = new_doc();
|
||||
let filled = patterned_square(&mut s);
|
||||
let other = square(&mut s, 300.0, 100.0);
|
||||
let v = ViewInfo { smart_guides: false, snap_to_point: false, corner_widgets: false, ..ViewInfo::default() };
|
||||
s.select_tool("directSelection", v).unwrap();
|
||||
// The square is selected whole with the top-left anchor of `other`, as a click on the square's
|
||||
// fill and a Shift-click on that anchor select them. Each move takes both 10 pt right: Shift
|
||||
// with an arrow key, `path.moveAnchors`, and a drag of the anchor (no params).
|
||||
for (cmd, p) in [
|
||||
("object.nudge", Some(json!({"dx": 1, "dy": 0, "big": true}))),
|
||||
("path.moveAnchors", Some(json!({"dx": 10, "dy": 0}))),
|
||||
("path.moveAnchors", None),
|
||||
] {
|
||||
let run = |s: &mut Session, p: Option<&Value>| {
|
||||
s.execute("select.set", &json!({"ids": [filled.0]})).unwrap();
|
||||
s.execute("select.anchors", &json!({"id": other.0, "anchors": [[0, 0]], "mode": "add"})).unwrap();
|
||||
match p {
|
||||
Some(p) => {
|
||||
s.execute(cmd, p).unwrap();
|
||||
}
|
||||
None => gesture(s, v, &[(Down, 300.0, 100.0), (Drag, 305.0, 100.0), (Drag, 310.0, 100.0), (Up, 310.0, 100.0)]),
|
||||
}
|
||||
assert_eq!(top_left(s, filled), (110.0, 100.0), "{cmd}: the square moves whole");
|
||||
let anchors = &s.doc().unwrap().doc.node(other).unwrap().path_data().unwrap().subpaths[0].anchors;
|
||||
assert_eq!((anchors[0].p.x, anchors[1].p.x), (310.0, 350.0), "{cmd}: the selected anchor moves alone");
|
||||
assert_eq!(s.journal.last().unwrap().0, cmd);
|
||||
};
|
||||
run(&mut s, p.as_ref());
|
||||
assert_eq!(pattern_tiles(&s, filled), [1.0, 0.0, 0.0, 1.0, 0.0, 0.0], "{cmd}: off, the tiles stay");
|
||||
assert_eq!(s.journal.last().unwrap().1["patterns"], json!(false), "{cmd}: the journal keeps the choice");
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
set_pref(&mut s, "transformPatternTiles", json!(true));
|
||||
run(&mut s, p.as_ref());
|
||||
assert_eq!(pattern_tiles(&s, filled), [1.0, 0.0, 0.0, 1.0, 10.0, 0.0], "{cmd}: on, they move with the square");
|
||||
assert_eq!(s.journal.last().unwrap().1["patterns"], json!(true), "{cmd}: the journal keeps the choice");
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
if let Some(mut p) = p {
|
||||
p["patterns"] = json!(false);
|
||||
run(&mut s, Some(&p));
|
||||
assert_eq!(pattern_tiles(&s, filled), [1.0, 0.0, 0.0, 1.0, 0.0, 0.0], "{cmd}: the param wins");
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
}
|
||||
set_pref(&mut s, "transformPatternTiles", json!(false));
|
||||
}
|
||||
}
|
||||
|
||||
/// General › Select Same Tint % (#394): off, Select › Same › Fill Color takes every tint of the
|
||||
/// swatch; on, only the same tint.
|
||||
#[test]
|
||||
|
||||
+2
-1
@@ -1592,7 +1592,8 @@ The Selection & Anchor Display and General preferences apply to `pointer_gesture
|
||||
`object.align`, `object.distribute`, `object.distributeSpacing`, the Selection and transform tools, the dialogs'
|
||||
Transform Patterns) and of the same param on the commands that move or duplicate art with an artboard (`artboard.move`
|
||||
and the Artboard tool, `artboard.duplicate`, `artboard.rearrange`, `artboard.setProps`): pattern fills and strokes
|
||||
move with the art.
|
||||
move with the art. `object.nudge` (the arrow keys) and `path.moveAnchors` (a Direct Selection drag of selected
|
||||
anchors) take the same param, with the same default, for the objects they move whole.
|
||||
- `selectSameTintPercent` (off by default): `select.same.fillColor`, `strokeColor` and `fillAndStroke` take every tint
|
||||
of a global or spot swatch; on, only the same tint.
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user