1use a7n_proto::v1::{ScrollEvent, ScrollUnit};
4
5use super::MotionScale;
6
7#[derive(Debug)]
9pub struct ScrollScale {
10 pixels: MotionScale,
11 lines: MotionScale,
12}
13
14impl ScrollScale {
15 #[must_use]
17 pub fn new(speed: f64, reverse: bool) -> Self {
18 let speed = if reverse { -speed } else { speed };
19 Self {
20 pixels: MotionScale::new(speed),
21 lines: MotionScale::new(speed),
22 }
23 }
24
25 #[allow(clippy::cast_precision_loss)] pub fn apply(&mut self, event: &mut ScrollEvent) {
27 let scale = match event.unit() {
28 ScrollUnit::Pixel => &mut self.pixels,
29 ScrollUnit::Line => &mut self.lines,
30 ScrollUnit::Unspecified => return,
31 };
32 event.dx =
33 MotionScale::axis(f64::from(event.dx), scale.speed, &mut scale.remainder.0) as f32;
34 event.dy =
35 MotionScale::axis(f64::from(event.dy), scale.speed, &mut scale.remainder.1) as f32;
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn apply_fractional_scroll_retains_remainder_per_unit_and_reverses_axes() {
45 let mut scale = ScrollScale::new(0.25, true);
47 let mut output = Vec::new();
48
49 for _ in 0..4 {
51 for unit in [ScrollUnit::Line, ScrollUnit::Pixel] {
52 let mut event = ScrollEvent {
53 dx: 1.0,
54 dy: -1.0,
55 unit: unit.into(),
56 };
57 scale.apply(&mut event);
58 output.push((event.dx, event.dy));
59 }
60 }
61
62 assert_eq!(
64 output,
65 [
66 (0.0, 0.0),
67 (0.0, 0.0),
68 (0.0, 0.0),
69 (0.0, 0.0),
70 (0.0, 0.0),
71 (0.0, 0.0),
72 (-1.0, 1.0),
73 (-1.0, 1.0)
74 ]
75 );
76 }
77
78 #[test]
79 fn apply_non_finite_scroll_preserves_pending_fraction() {
80 let mut scale = ScrollScale::new(0.5, false);
82 let mut event = ScrollEvent {
83 dx: 1.0,
84 dy: 1.0,
85 unit: ScrollUnit::Line.into(),
86 };
87 scale.apply(&mut event);
88
89 let mut invalid = ScrollEvent {
91 dx: f32::NAN,
92 dy: f32::INFINITY,
93 unit: ScrollUnit::Line.into(),
94 };
95 scale.apply(&mut invalid);
96 event.dx = 1.0;
97 event.dy = 1.0;
98 scale.apply(&mut event);
99
100 assert_eq!((invalid.dx, invalid.dy), (0.0, 0.0));
102 assert_eq!((event.dx, event.dy), (1.0, 1.0));
103 }
104}