1use fret_core::{Point, Px};
9
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct DragThreshold {
12 pub px: Px,
13}
14
15impl DragThreshold {
16 pub fn new(px: Px) -> Self {
17 Self { px }
18 }
19
20 pub fn distance_sq_exceeded(self, start: Point, current: Point) -> bool {
21 let dx = current.x.0 - start.x.0;
22 let dy = current.y.0 - start.y.0;
23 if !dx.is_finite() || !dy.is_finite() {
24 return false;
25 }
26
27 let dist2 = dx * dx + dy * dy;
28 let threshold = self.px.0;
29 if !threshold.is_finite() || threshold <= 0.0 {
30 return dist2 > 0.0;
31 }
32
33 dist2 >= threshold * threshold
34 }
35}
36
37impl Default for DragThreshold {
38 fn default() -> Self {
39 Self { px: Px(6.0) }
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn default_threshold_matches_imgui_default() {
49 assert_eq!(DragThreshold::default().px, Px(6.0));
50 }
51
52 #[test]
53 fn negative_threshold_is_treated_as_zero() {
54 let t = DragThreshold::new(Px(-10.0));
55 let start = Point::new(Px(0.0), Px(0.0));
56 let current = Point::new(Px(0.0), Px(0.0));
57 assert!(!t.distance_sq_exceeded(start, current));
58
59 let moved = Point::new(Px(1.0), Px(0.0));
60 assert!(t.distance_sq_exceeded(start, moved));
61 }
62
63 #[test]
64 fn threshold_exceeded_is_inclusive() {
65 let t = DragThreshold::new(Px(2.0));
66 let start = Point::new(Px(0.0), Px(0.0));
67 let current = Point::new(Px(2.0), Px(0.0));
68 assert!(t.distance_sq_exceeded(start, current));
69 }
70}