mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-25 19:06:47 -06:00
Merge fix/657
This commit is contained in:
@@ -996,8 +996,13 @@ impl Session {
|
||||
self.tool.overlay.guides.clear();
|
||||
let Gesture::Vector(g) = g else { return Ok(()) };
|
||||
match g {
|
||||
VGesture::Points { moved, split, click_clears, .. } => {
|
||||
VGesture::Points { verts, others, moved, split, click_clears, .. } => {
|
||||
if moved || split.is_some() {
|
||||
if let ([v], None) = (verts.as_slice(), split)
|
||||
&& others.iter().all(|(_, o)| o.is_empty())
|
||||
{
|
||||
self.merge_dropped_point(ve.id, *v, 6.0 / ev.zoom.max(1e-6))?;
|
||||
}
|
||||
self.commit_interaction()?;
|
||||
} else {
|
||||
self.cancel_interaction()?;
|
||||
@@ -1057,4 +1062,40 @@ impl Session {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Point `v` of vector `id`, dragged and dropped within `tol` (page units) of another of its
|
||||
/// points, merges into that point (in the same undo step as the move), which stays selected.
|
||||
fn merge_dropped_point(&mut self, id: NodeId, v: usize, tol: f64) -> Result<()> {
|
||||
let moved = self.ds()?.doc.get(id)?.clone();
|
||||
let w = self.ds()?.doc.world_transform(id);
|
||||
let NodeKind::Vector { network: net } = &moved.kind else { return Ok(()) };
|
||||
let Some(p) = net.vertices.get(v).map(|x| w * x.point()) else { return Ok(()) };
|
||||
let Some(keep) = net
|
||||
.vertices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| *i != v)
|
||||
.map(|(i, x)| (i, (w * x.point() - p).hypot()))
|
||||
.filter(|(_, d)| *d <= tol)
|
||||
.min_by(|a, b| a.1.total_cmp(&b.1))
|
||||
.map(|(i, _)| i)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let mut merged = net.clone();
|
||||
ops::merge_vertices(&mut merged, keep, v);
|
||||
// A merge that would leave no segment (a 2-point line's ends dropped together) only moves.
|
||||
if merged.segments.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
// The preview starts again from the document before the drag: bring the moved layer.
|
||||
self.preview(|doc, _| {
|
||||
*doc.get_mut(id)? = moved;
|
||||
edit(doc, id, |net| *net = merged)
|
||||
})?;
|
||||
set_state(self, |e| {
|
||||
e.vertices = vec![if keep > v { keep - 1 } else { keep }];
|
||||
e.segments.clear();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +280,36 @@ fn mirroring_position_and_join_commands() {
|
||||
assert!(s.execute("vector.join", &json!({"ids": [id]})).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_point_dropped_on_another_merges_into_it() {
|
||||
// #401: an open path's end dragged onto its start closes the path at that point.
|
||||
let mut s = Session::new();
|
||||
let r = ex(&mut s, "vector.create", json!({"points": [[0, 0], [100, 0], [100, 100], [0, 100]]}));
|
||||
let id = crate::params::id_of(&r["id"]).unwrap();
|
||||
ex(&mut s, "vector.edit.begin", json!({"id": id}));
|
||||
drag(&mut s, (0.0, 100.0), (2.0, 3.0));
|
||||
let n = net(&s, id);
|
||||
assert_eq!(n.vertices.len(), 3, "the dropped point merged");
|
||||
assert!((0..3).all(|v| n.incident(v).len() == 2), "a closed path: {n:?}");
|
||||
assert_eq!(ve(&s).vertices, vec![vertex_at(&n, 0.0, 0.0)], "the point it merged into stays selected");
|
||||
s.undo().unwrap();
|
||||
let n = net(&s, id);
|
||||
assert_eq!(n.vertices.len(), 4, "one undo step takes back the move and the merge");
|
||||
vertex_at(&n, 0.0, 100.0);
|
||||
// A drop away from every point only moves it.
|
||||
ex(&mut s, "vector.edit.select", json!({"vertices": []}));
|
||||
drag(&mut s, (0.0, 100.0), (0.0, 50.0));
|
||||
assert_eq!(net(&s, id).vertices.len(), 4);
|
||||
// A 2-point line's end dropped on its other end only moves: no segment would be left.
|
||||
let mut s = Session::new();
|
||||
let r = ex(&mut s, "vector.create", json!({"points": [[0, 0], [100, 0]]}));
|
||||
let id = crate::params::id_of(&r["id"]).unwrap();
|
||||
ex(&mut s, "vector.edit.begin", json!({"id": id}));
|
||||
drag(&mut s, (100.0, 0.0), (2.0, 0.0));
|
||||
let n = net(&s, id);
|
||||
assert_eq!((n.vertices.len(), n.segments.len()), (2, 1), "still a line: {n:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undo_back_past_the_conversion_leaves_edit_mode() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user