mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 18:27:02 -06:00
Path: Simplify and Add Anchor Points record no undo step when they change no path
Simplify and Add Anchor Points edited the document whenever the
selection held a path, so a call that changed no path still recorded
an undo step, emptied Redo, marked the document modified and turned
the selected live shapes into plain paths. OK in the Simplify dialog
did the same. Simplify at its default options leaves a rectangle, a
star, a line and a path with one anchor as they are, and Add Anchor
Points leaves a path with one anchor as it is.
Both commands go through edit_paths, which now computes the new paths
before it edits the document. When no path changes, the command
returns without editing the document, and the reply
({ids, before, after}) has the same form and counts as before. When
some paths change, the command replaces only those paths and records
one undo step, so a path that Simplify leaves as it is keeps its live
shape.
One line in the evidence list of docs/target-app-parity.md names the
commands.
This commit is contained in:
@@ -643,34 +643,44 @@ fn path_ids(d: &Document, roots: &[NodeId]) -> Vec<NodeId> {
|
||||
out
|
||||
}
|
||||
|
||||
/// Replace each path under the selection ([`path_ids`]) by what `f` makes of it: → (their ids, how
|
||||
/// many anchors they have before and after). A path that `f` would empty or returns unchanged is
|
||||
/// left as it is, with its live shape and its direct-selected anchors; a replaced path loses both.
|
||||
fn edit_paths(s: &mut Session, label: &str, f: impl Fn(&PathData) -> PathData) -> Result<(Vec<NodeId>, usize, usize)> {
|
||||
let roots = selected_roots(s)?;
|
||||
s.edit(label, |d, sel| {
|
||||
let ids = path_ids(d, &roots);
|
||||
if ids.is_empty() {
|
||||
return Err(EngineError::Other(format!("{label}: select paths")));
|
||||
let d = &s.doc()?.doc;
|
||||
let ids = path_ids(d, &roots);
|
||||
if ids.is_empty() {
|
||||
return Err(EngineError::Other(format!("{label}: select paths")));
|
||||
}
|
||||
let (mut before, mut after, mut changed) = (0, 0, vec![]);
|
||||
for id in &ids {
|
||||
let Some(NodeKind::Path { path, .. }) = d.node(*id).map(|n| &n.kind) else { continue };
|
||||
before += path.anchor_count();
|
||||
let np = f(path);
|
||||
if (np.is_empty() && !path.is_empty()) || np == *path {
|
||||
after += path.anchor_count();
|
||||
continue;
|
||||
}
|
||||
let (mut before, mut after) = (0, 0);
|
||||
for id in &ids {
|
||||
if let Some(NodeKind::Path { path, live, .. }) = d.node_mut(*id).map(|n| &mut n.kind) {
|
||||
before += path.anchor_count();
|
||||
let np = f(path);
|
||||
if np.is_empty() && !path.is_empty() {
|
||||
after += path.anchor_count();
|
||||
continue;
|
||||
}
|
||||
after += np.anchor_count();
|
||||
if *path != np {
|
||||
after += np.anchor_count();
|
||||
changed.push((*id, np));
|
||||
}
|
||||
// When no path changes, the document and its undo history stay as they are.
|
||||
if !changed.is_empty() {
|
||||
s.edit(label, |d, sel| {
|
||||
for (id, np) in changed {
|
||||
if let Some(NodeKind::Path { path, live, .. }) = d.node_mut(id).map(|n| &mut n.kind) {
|
||||
// Refit and subdivision change what the old component indexes refer to.
|
||||
// Keep the object selected whole so its new points remain editable.
|
||||
sel.anchors.remove(id);
|
||||
sel.anchors.remove(&id);
|
||||
*path = np;
|
||||
*live = None;
|
||||
}
|
||||
*path = np;
|
||||
*live = None;
|
||||
}
|
||||
}
|
||||
Ok((ids, before, after))
|
||||
})
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
Ok((ids, before, after))
|
||||
}
|
||||
|
||||
fn simplify(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
Reference in New Issue
Block a user