mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-30 12:47:13 -06:00
Guides: Shift selects ruler guides and art together
A Shift-click on a guide adds it to the selected art (guide.select toggle keeps the art), and Shift-adding or -removing art keeps the selected guides; a new selection still clears them. With both selected, Delete deletes the art and the guides in one undo step (not when ids are given). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CC5DiGJEZ5ADaQMBEQk4W1
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
a9724275cc
commit
a22bced150
@@ -178,7 +178,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Select Guides",
|
||||
[],
|
||||
None,
|
||||
"{indexes: [index…], toggle?: bool} select ruler guides on their own (deselecting the art); toggle adds or removes them instead → {selected: [index…]}",
|
||||
"{indexes: [index…], toggle?: bool} select ruler guides on their own (deselecting the art); toggle adds or removes them instead, keeping the selected art (a Shift-click on a guide) → {selected: [index…]}",
|
||||
guides_unlocked,
|
||||
guide_select
|
||||
),
|
||||
@@ -539,15 +539,12 @@ fn guide_select(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let list = p.get("indexes").and_then(Value::as_array).ok_or_else(|| bad("guide.select", "missing indexes"))?;
|
||||
let picked = list.iter().map(|v| guide_index(s, Some(v), "guide.select")).collect::<Result<Vec<_>>>()?;
|
||||
if bool_or(p, "toggle", false) {
|
||||
let mut now = s.doc()?.selection.guides.clone();
|
||||
for i in picked {
|
||||
if let Some(k) = now.iter().position(|g| *g == i) {
|
||||
now.remove(k);
|
||||
} else {
|
||||
now.push(i);
|
||||
// Added to (or taken from) what is selected, the art included.
|
||||
s.select(|_, sel| {
|
||||
for i in picked {
|
||||
sel.toggle_guide(i);
|
||||
}
|
||||
}
|
||||
s.select(|_, sel| sel.set_guides(now))?;
|
||||
})?;
|
||||
} else {
|
||||
s.select(|_, sel| sel.set_guides(picked))?;
|
||||
}
|
||||
|
||||
@@ -268,6 +268,8 @@ fn clear(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
return super::docmenu::guide_remove(s, &json!({}));
|
||||
}
|
||||
let st = s.doc()?;
|
||||
// Guides selected with the art go with it (not when ids are given).
|
||||
let with_guides = explicit.is_none();
|
||||
let targets = explicit.unwrap_or_else(|| st.selection.in_paint_order(&st.doc));
|
||||
// Keep the selected ids themselves, without promoting compound members. Delete a selected
|
||||
// ancestor just once; its selected descendants leave with it. Layers themselves are kept.
|
||||
@@ -284,6 +286,10 @@ fn clear(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
for id in &ids {
|
||||
d.remove(*id)?;
|
||||
}
|
||||
if with_guides {
|
||||
let gone = sel.guides.clone();
|
||||
d.retain_guides(sel, |i, _| !gone.contains(&i));
|
||||
}
|
||||
sel.clear();
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -823,6 +823,40 @@ fn ruler_guides_select_move_and_delete() {
|
||||
assert!(matches!(s.execute("edit.clear", &json!({})), Err(EngineError::Disabled(..))));
|
||||
}
|
||||
|
||||
/// Shift selects ruler guides and art together, in either order; Delete takes both in one step.
|
||||
#[test]
|
||||
fn guides_and_art_are_shift_selected_together() {
|
||||
let mut s = session();
|
||||
let a = rect(&mut s, 10.0, 10.0, 40.0, 20.0);
|
||||
let b = rect(&mut s, 70.0, 50.0, 60.0, 30.0);
|
||||
s.execute("guide.add", &json!({"vertical": true, "pos": 200})).unwrap();
|
||||
s.execute("guide.add", &json!({"vertical": false, "pos": 300})).unwrap();
|
||||
// Art first, then a Shift-click on a guide: the art stays selected.
|
||||
sel(&mut s, &[a]);
|
||||
s.execute("guide.select", &json!({"indexes": [0], "toggle": true})).unwrap();
|
||||
assert_eq!((selected(&s), selected_guides(&s)), (vec![a], vec![0]));
|
||||
// A guide first, then Shift-added art: the guide stays selected.
|
||||
s.execute("guide.select", &json!({"indexes": [1]})).unwrap();
|
||||
s.execute("select.add", &json!({"ids": [b.0]})).unwrap();
|
||||
assert_eq!((selected(&s), selected_guides(&s)), (vec![b], vec![1]));
|
||||
// A new selection drops them.
|
||||
sel(&mut s, &[a]);
|
||||
assert!(selected_guides(&s).is_empty());
|
||||
// Delete takes the art and the guides, in one step; undo brings both back.
|
||||
s.execute("guide.select", &json!({"indexes": [1], "toggle": true})).unwrap();
|
||||
let n = undo_len(&s);
|
||||
s.execute("edit.clear", &json!({})).unwrap();
|
||||
assert_eq!((guides(&s), undo_len(&s)), (vec![(true, 200.0)], n + 1));
|
||||
assert!(s.doc().unwrap().doc.node(a).is_none() && s.doc().unwrap().doc.node(b).is_some());
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(guides(&s).len(), 2);
|
||||
// Ids given: only those go, the guides stay.
|
||||
s.execute("guide.select", &json!({"indexes": [0]})).unwrap();
|
||||
s.execute("select.add", &json!({"ids": [b.0]})).unwrap();
|
||||
s.execute("edit.clear", &json!({"ids": [b.0]})).unwrap();
|
||||
assert_eq!(guides(&s).len(), 2);
|
||||
}
|
||||
|
||||
/// #451: an artboard guide (`guide.add {artboard}`) runs across its artboard only, and is moved,
|
||||
/// copied and deleted with it; canvas guides stay put.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user