1use std::fmt::Debug;
7
8use cranpose_render_common::Renderer;
9
10use crate::{AppShell, PointerSource};
11
12enum Route {
14 Primary,
15 Secondary(u64),
16 Untracked,
17}
18
19#[derive(Debug)]
25pub struct TouchRouter<F> {
26 primary: Option<F>,
27 secondaries: Vec<(F, u64)>,
30 next_secondary_id: u64,
31}
32
33impl<F> Default for TouchRouter<F> {
34 fn default() -> Self {
35 Self {
36 primary: None,
37 secondaries: Vec::new(),
38 next_secondary_id: 0,
39 }
40 }
41}
42
43impl<F: Copy + Eq> TouchRouter<F> {
44 pub fn press<R>(&mut self, shell: &mut AppShell<R>, finger: Option<F>, x: f32, y: f32) -> bool
46 where
47 R: Renderer,
48 R::Error: Debug,
49 {
50 match self.route_press(finger) {
51 Route::Primary => {
52 let event_time = shell.realtime_pointer_event_time(None);
53 shell.set_cursor_at_event_time(x, y, event_time);
54 shell.pointer_pressed_at_event_time(event_time)
55 }
56 Route::Secondary(id) => shell.secondary_pointer_pressed(id, x, y, None),
57 Route::Untracked => false,
58 }
59 }
60
61 pub fn moved<R>(&self, shell: &mut AppShell<R>, finger: Option<F>, x: f32, y: f32) -> bool
64 where
65 R: Renderer,
66 R::Error: Debug,
67 {
68 match self.route(finger) {
69 Route::Primary => shell.set_cursor(x, y),
70 Route::Secondary(id) => shell.secondary_pointer_moved(id, x, y, None),
71 Route::Untracked => false,
72 }
73 }
74
75 pub fn release<R>(&mut self, shell: &mut AppShell<R>, finger: Option<F>, x: f32, y: f32) -> bool
79 where
80 R: Renderer,
81 R::Error: Debug,
82 {
83 let Some(finger) = finger else {
84 return release_primary(shell, x, y);
85 };
86 if self.primary == Some(finger) {
87 let mut changed = false;
88 for (_, id) in self.secondaries.drain(..) {
89 changed |= shell.secondary_pointer_released(id, x, y, None);
90 }
91 self.end_gesture();
92 return release_primary(shell, x, y) | changed;
93 }
94 if let Some(id) = self.take_secondary(finger) {
95 return shell.secondary_pointer_released(id, x, y, None);
96 }
97 self.is_idle() && release_primary(shell, x, y)
100 }
101
102 pub fn cancel<R>(
107 &mut self,
108 shell: &mut AppShell<R>,
109 finger: Option<F>,
110 position: Option<(f32, f32)>,
111 ) -> bool
112 where
113 R: Renderer,
114 R::Error: Debug,
115 {
116 let secondary = finger
117 .filter(|finger| self.primary != Some(*finger))
118 .and_then(|finger| self.take_secondary(finger));
119 if let Some(id) = secondary {
120 shell.set_pointer_source(PointerSource::Touch);
121 let (x, y) = position.unwrap_or((0.0, 0.0));
122 return shell.secondary_pointer_released(id, x, y, None);
123 }
124 let ends_gesture = finger.is_none() || self.primary == finger || self.is_idle();
125 if ends_gesture {
126 self.end_gesture();
127 shell.cancel_gesture();
128 }
129 ends_gesture
130 }
131
132 fn route_press(&mut self, finger: Option<F>) -> Route {
133 let Some(finger) = finger else {
134 return Route::Primary;
135 };
136 match self.primary {
137 None => {
138 self.primary = Some(finger);
139 Route::Primary
140 }
141 Some(primary) if primary == finger => Route::Primary,
142 Some(_) => Route::Secondary(self.secondary_id(finger).unwrap_or_else(|| {
143 self.next_secondary_id += 1;
144 self.secondaries.push((finger, self.next_secondary_id));
145 self.next_secondary_id
146 })),
147 }
148 }
149
150 fn route(&self, finger: Option<F>) -> Route {
151 match finger {
152 None => Route::Primary,
153 Some(finger) if self.primary == Some(finger) => Route::Primary,
154 Some(finger) => self
155 .secondary_id(finger)
156 .map_or(Route::Untracked, Route::Secondary),
157 }
158 }
159
160 fn secondary_id(&self, finger: F) -> Option<u64> {
161 self.secondaries
162 .iter()
163 .find(|(tracked, _)| *tracked == finger)
164 .map(|(_, id)| *id)
165 }
166
167 fn take_secondary(&mut self, finger: F) -> Option<u64> {
168 let index = self
169 .secondaries
170 .iter()
171 .position(|(tracked, _)| *tracked == finger)?;
172 Some(self.secondaries.remove(index).1)
173 }
174
175 fn is_idle(&self) -> bool {
176 self.primary.is_none() && self.secondaries.is_empty()
177 }
178
179 fn end_gesture(&mut self) {
180 self.primary = None;
181 self.secondaries.clear();
182 self.next_secondary_id = 0;
183 }
184}
185
186fn release_primary<R>(shell: &mut AppShell<R>, x: f32, y: f32) -> bool
187where
188 R: Renderer,
189 R::Error: Debug,
190{
191 let event_time = shell.realtime_pointer_event_time(None);
192 shell.pointer_released_at_position_event_time(x, y, event_time)
193}