address review: same distance test in width profile lower bound; preview the whole drag when a symbolism tool deactivates

This commit is contained in:
Dylan M. Taylor
2026-11-04 08:13:18 +07:00
committed by bflatastic
parent 13b0bbe639
commit fc83e5c5b9
2 changed files with 38 additions and 15 deletions
+5 -1
View File
@@ -90,7 +90,8 @@ impl WidthProfile {
/// discontinuous point (two points at `t`, within `1e-7`).
pub fn around(&self, t: f64) -> ((f64, f64), (f64, f64)) {
let p = &self.points;
let i = p.partition_point(|q| q.0 < t - 1e-7);
// The same distance test below, so a point exactly 1e-7 before `t` is never skipped by rounding.
let i = p.partition_point(|q| q.0 < t && (q.0 - t).abs() > 1e-7);
if let Some(first) = p.get(i).filter(|q| (q.0 - t).abs() <= 1e-7) {
let j = i + p[i..].partition_point(|q| q.0 - first.0 <= 1e-9) - 1;
if j > i {
@@ -353,5 +354,8 @@ mod tests {
// Many points at one position are one step, found without a pass over them all.
let many = WidthProfile { points: (0..1000).map(|i| (0.5, i as f64, i as f64)).collect() };
assert_eq!(many.around(0.5), ((0.0, 0.0), (999.0, 999.0)));
// 0.4999999 == 0.5 - 1e-7, yet its distance from 0.5 rounds above 1e-7: it is not part of the step.
let near = WidthProfile { points: vec![(0.4999999, 2.0, 2.0), (0.5, 1.0, 1.0), (0.5, 0.5, 0.25)] };
assert_eq!(near.around(0.5), ((1.0, 1.0), (0.5, 0.25)));
}
}
+33 -14
View File
@@ -117,6 +117,19 @@ impl SymbolismTool {
}
}
impl SymbolismTool {
/// Ends the drag: what is committed is the last preview, so the whole drag is shown first.
fn finish(&mut self, cx: &ToolContext) -> Vec<Action> {
self.active = false;
let stale = (self.previewed != self.points.len()).then(|| {
let (c, v) = self.command(cx);
Action::Preview(c, v)
});
self.points.clear();
stale.into_iter().chain([Action::Commit]).collect()
}
}
impl Tool for SymbolismTool {
fn id(&self) -> &'static str {
self.id
@@ -151,16 +164,7 @@ impl Tool for SymbolismTool {
let (c, v) = self.command(cx);
vec![Action::Preview(c, v)]
}
PointerKind::Up if self.active => {
self.active = false;
// What is committed is the last preview: show the whole drag first.
let stale = (self.previewed != self.points.len()).then(|| {
let (c, v) = self.command(cx);
Action::Preview(c, v)
});
self.points.clear();
stale.into_iter().chain([Action::Commit]).collect()
}
PointerKind::Up if self.active => self.finish(cx),
_ => vec![],
}
}
@@ -182,11 +186,9 @@ impl Tool for SymbolismTool {
}
vec![]
}
fn deactivate(&mut self, _cx: &ToolContext) -> Vec<Action> {
fn deactivate(&mut self, cx: &ToolContext) -> Vec<Action> {
if self.active {
self.active = false;
self.points.clear();
return vec![Action::Commit];
return self.finish(cx);
}
vec![]
}
@@ -335,6 +337,23 @@ mod tests {
assert_eq!(up.last(), Some(&Action::Commit));
}
#[test]
fn switching_tools_mid_drag_previews_the_whole_drag_before_committing() {
let (d, _) = doc_with_rect();
let (s, p) = (Selection::default(), paint());
let cx = cx(&d, &s, &p);
let mut t = SymbolismTool::new("symbolShifter");
t.pointer(&cx, &PointerEvent::new(PointerKind::Down, 0.0, 0.0));
let n = 7 * crate::PREVIEW_ALL_UNTIL + 1; // not a point that previews
for i in 1..n {
t.pointer(&cx, &PointerEvent::new(PointerKind::Drag, 50.0 * i as f64, 0.0));
}
let a = t.deactivate(&cx);
assert!(matches!(a.first(), Some(Action::Preview(_, v)) if v["points"].as_array().unwrap().len() == n), "{a:?}");
assert_eq!(a.last(), Some(&Action::Commit));
assert!(!t.busy());
}
#[test]
fn adjust_tools_map_to_symbol_adjust() {
let (d, _) = doc_with_rect();