Merge pull request #4325 from Hassan1305/fix-4237-add-anchor-select

Fix #4237: Add Anchor Point selects the path it adds to
This commit is contained in:
BFlat
2026-10-29 10:47:20 +07:00
committed by GitHub
2 changed files with 34 additions and 2 deletions
+10 -2
View File
@@ -1251,13 +1251,21 @@ fn insert_anchor(s: &mut Session, p: &Value) -> Result<Value> {
let si = usize_opt(p, "subpath", "path.insertAnchor")?.unwrap_or(0);
let seg = p.get("segment").and_then(Value::as_u64).map(index).ok_or_else(|| bad("path.insertAnchor", "missing segment"))?;
let t = number_or(p, "t", 0.5, "path.insertAnchor")?.clamp(0.0, 1.0);
let idx = s.edit("Add Anchor Point", |d, _| {
let idx = s.edit("Add Anchor Point", |d, sel| {
let path = path_mut(d, id)?;
let sp = path.subpaths.get_mut(si).ok_or_else(|| EngineError::Other("no such subpath".into()))?;
if seg >= sp.segment_count() {
return Err(EngineError::Other("no such segment".into()));
}
Ok(sp.insert_anchor(seg, t))
let idx = sp.insert_anchor(seg, t);
// A path that wasn't selected becomes the selection, its new anchor direct-selected, so
// the point added shows and can be edited at once (#4237).
if !sel.contains(id) {
sel.clear();
sel.add(id);
sel.anchors.entry(id).or_default().insert((si, idx));
}
Ok(idx)
})?;
Ok(json!({ "anchor": idx }))
}
+24
View File
@@ -1799,6 +1799,30 @@ fn remove_anchor_points_keeps_the_paths_closed() {
assert_eq!(spec.menu, &["Object", "Path"][..]);
}
#[test]
fn add_anchor_point_selects_the_path_it_was_added_to() {
// #4237: an anchor added to a path that wasn't selected selects that path, the new anchor
// direct-selected, so it shows at once; undo puts the old selection back. A path already
// selected (the Pen's Auto Add) keeps its selection.
let mut s = session();
let other = rect(&mut s, 300.0, 0.0, 50.0, 50.0);
let line = |s: &mut Session| {
NodeId(s.execute("path.create", &json!({"anchors": [{"x": 0, "y": 0}, {"x": 100, "y": 0}]})).unwrap()["id"].as_u64().unwrap())
};
let id = line(&mut s);
s.execute("select.set", &json!({"ids": [other.0]})).unwrap();
s.execute("path.insertAnchor", &json!({"id": id.0, "segment": 0, "t": 0.5})).unwrap();
assert_eq!(s.doc().unwrap().selection.objects, [id]);
assert_eq!(selected_anchors(&s, id), [(0, 1)]);
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(s.doc().unwrap().selection.objects, [other]);
let kept = line(&mut s);
s.execute("select.set", &json!({"ids": [kept.0]})).unwrap();
s.execute("path.insertAnchor", &json!({"id": kept.0, "segment": 0, "t": 0.5})).unwrap();
assert_eq!(s.doc().unwrap().selection.objects, [kept]);
assert!(selected_anchors(&s, kept).is_empty(), "a path selected as a whole stays so");
}
fn selected_anchors(s: &Session, id: NodeId) -> Vec<(usize, usize)> {
s.doc().unwrap().selection.anchors.get(&id).map(|set| set.iter().copied().collect()).unwrap_or_default()
}