Lasso: a recolour or move that changes nothing keeps the lasso selection (#4004)

This commit is contained in:
aiongg
2026-10-24 21:31:35 +00:00
parent 49d3551ca6
commit 885b1cbd13
2 changed files with 21 additions and 0 deletions
+19
View File
@@ -532,6 +532,16 @@ fn keep_lasso(s: &mut Session, sel: LassoSelection) {
s.view.draw.lasso = Some(LassoSelection { rev: s.rev().wrapping_add(1), ..sel });
}
/// After a command that changed nothing, which puts the revision back from `touched` to `rev`: a
/// lasso selection the command kept for the revision it would have reached stays selected.
pub(crate) fn rekey_lasso(s: &mut Session, touched: u64, rev: u64) {
if let Some(l) = s.view.draw.lasso.as_mut()
&& (l.rev == touched || l.rev == touched.wrapping_add(1))
{
l.rev = rev;
}
}
/// Whether (`x`, `y`) is inside the closed loop `poly` (even–odd rule).
fn inside(poly: &[[f32; 2]], x: f32, y: f32) -> bool {
let n = poly.len();
@@ -1081,6 +1091,15 @@ mod tests {
let objs = ink(&s);
let blue = objs.iter().filter(|o| matches!(o, InlineObject::Shape { stroke: Some(c), .. } if c.hex() == "0070C0")).count();
assert_eq!(blue, 1);
// Recolouring to the colour it has changes nothing, and the selection stays; an edit
// elsewhere ends it.
s.run("draw.lassoColor", &json!({"color": "0070C0"})).unwrap();
assert_eq!(s.undo_depth(), steps + 2);
assert_eq!(super::lasso_selection(&s).map(|l| l.items.clone()), Some(vec![sel.clone()]));
s.run("text.insert", &json!({"text": "x"})).unwrap();
assert!(super::lasso_selection(&s).is_none());
let r = s.run("draw.lasso", &json!({"page": 0, "points": [[80, 80], [260, 80], [260, 180], [80, 180]]})).unwrap();
assert_eq!(r["count"], 1);
// Deleted: only the selected stroke goes, and the selection with it.
s.run("draw.lassoDelete", &json!({})).unwrap();
assert_eq!(ink(&s).len(), 1);
+2
View File
@@ -1717,7 +1717,9 @@ impl Session {
self.dirty = dirty;
}
if let Some(rev) = rev_restore {
let touched = self.rev;
self.restore_rev(rev);
crate::cmd::draw::rekey_lasso(self, touched, rev);
}
if pushed {
self.join_anchor = false;