cranpose_app_shell/
wheel.rs1use cranpose_foundation::Modifiers;
2use cranpose_ui_graphics::Point;
3
4const NOTCH_LOGICAL_PX: f32 = 40.0;
5const ZOOM_PER_NOTCH: f32 = 1.2;
6
7#[derive(Clone, Copy, Debug, PartialEq)]
10pub struct WheelScroll {
11 pub delta: Point,
14 pub modifiers: Modifiers,
17 pub uptime_millis: u64,
20}
21
22impl WheelScroll {
23 pub fn new(delta: Point, uptime_millis: u64) -> Self {
25 Self {
26 delta,
27 modifiers: Modifiers::NONE,
28 uptime_millis,
29 }
30 }
31
32 pub fn with_modifiers(mut self, modifiers: Modifiers) -> Self {
34 self.modifiers = modifiers;
35 self
36 }
37
38 pub fn is_zoom(&self) -> bool {
41 self.modifiers.ctrl
42 }
43
44 pub fn zoom_factor(&self) -> f32 {
47 ZOOM_PER_NOTCH.powf(self.delta.y / NOTCH_LOGICAL_PX)
48 }
49
50 pub fn scroll_delta(&self) -> Point {
54 if !self.modifiers.alt {
55 return self.delta;
56 }
57 let x = if self.delta.x.abs() <= f32::EPSILON {
58 self.delta.y
59 } else {
60 self.delta.x
61 };
62 Point { x, y: 0.0 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 fn wheel(x: f32, y: f32) -> WheelScroll {
71 WheelScroll::new(Point { x, y }, 0)
72 }
73
74 #[test]
75 fn a_plain_sample_is_neither_a_zoom_nor_axis_swapped() {
76 let sample = wheel(3.0, -40.0);
77
78 assert!(!sample.is_zoom());
79 assert_eq!(sample.scroll_delta(), sample.delta);
80 }
81
82 #[test]
83 fn ctrl_makes_a_sample_a_zoom_that_grows_when_the_wheel_turns_up() {
84 let up = wheel(0.0, NOTCH_LOGICAL_PX).with_modifiers(Modifiers {
85 ctrl: true,
86 ..Modifiers::NONE
87 });
88 let down = wheel(0.0, -NOTCH_LOGICAL_PX).with_modifiers(Modifiers {
89 ctrl: true,
90 ..Modifiers::NONE
91 });
92
93 assert!(up.is_zoom());
94 assert!((up.zoom_factor() - ZOOM_PER_NOTCH).abs() < 1.0e-6);
95 assert!((up.zoom_factor() * down.zoom_factor() - 1.0).abs() < 1.0e-6);
96 }
97
98 #[test]
99 fn alt_moves_a_vertical_wheel_onto_the_horizontal_axis() {
100 let alt = Modifiers {
101 alt: true,
102 ..Modifiers::NONE
103 };
104
105 assert_eq!(
106 wheel(0.0, 48.0).with_modifiers(alt).scroll_delta(),
107 Point { x: 48.0, y: 0.0 }
108 );
109 assert_eq!(
110 wheel(12.0, 48.0).with_modifiers(alt).scroll_delta(),
111 Point { x: 12.0, y: 0.0 }
112 );
113 }
114}