touch_selection/
lib.rs

1use std::{
2    collections::{BTreeSet, HashSet},
3    hash::Hash,
4};
5
6pub trait Selector {
7    type Selectable: Selectable<Position = Self::Position>;
8    type Position: Copy;
9
10    fn moved(&self, moved: Self::Position, cursor: Self::Position) -> bool;
11    fn stop(
12        &self,
13        selectable: &mut Self::Selectable,
14        index: <Self::Selectable as Selectable>::Index,
15    );
16
17    fn add(
18        &self,
19        selectable: &mut Self::Selectable,
20        pos: Self::Position,
21        from: Option<<Self::Selectable as Selectable>::Index>,
22    ) -> <Self::Selectable as Selectable>::Index {
23        selectable.add(pos, from)
24    }
25    fn get(
26        &self,
27        selectable: &Self::Selectable,
28        pos: Self::Position,
29    ) -> Option<<Self::Selectable as Selectable>::Index> {
30        selectable.get(pos)
31    }
32
33    fn connect(
34        &self,
35        selectable: &mut Self::Selectable,
36        index: <Self::Selectable as Selectable>::Index,
37        selected: &[<Self::Selectable as Selectable>::Index],
38    ) {
39        selectable.connect(index, selected)
40    }
41    fn special(
42        &self,
43        selectable: &mut Self::Selectable,
44        index: <Self::Selectable as Selectable>::Index,
45        selected: &[<Self::Selectable as Selectable>::Index],
46    ) {
47        selectable.connect(index, selected)
48    }
49}
50
51pub trait Selectable {
52    type Position: Copy;
53    type Index;
54
55    fn add(&mut self, pos: Self::Position, from: Option<Self::Index>) -> Self::Index;
56    fn get(&self, pos: Self::Position) -> Option<Self::Index>;
57
58    fn connect(&mut self, _index: Self::Index, _selected: &[Self::Index]) {}
59    fn special(&mut self, _index: Self::Index, _selected: &[Self::Index]) {}
60}
61
62#[derive(Copy, Clone, PartialEq, Eq)]
63pub enum Action {
64    Connect,
65    Move,
66}
67
68pub struct ObjectGrabState<I> {
69    pub index: I,
70    pub action: Action,
71}
72
73pub enum GrabState<I> {
74    Object(ObjectGrabState<I>),
75    Empty,
76}
77
78pub struct GrabInfo<P, I> {
79    pub pos: P,
80    pub state: GrabState<I>,
81    pub time: f32,
82    pub moved: Option<P>,
83    created: bool,
84}
85
86impl<P: Copy, I: Copy> GrabInfo<P, I> {
87    fn new(pos: P, state: GrabState<I>, cursor: P) -> Self {
88        Self {
89            pos,
90            state,
91            time: 0.0,
92            moved: Some(cursor),
93            created: false,
94        }
95    }
96
97    pub fn hold<S: Selector<Position = P>>(&mut self, selector: &S, selectable: &mut S::Selectable)
98    where
99        S::Selectable: Selectable<Index = I>,
100    {
101        use GrabState::*;
102        match &mut self.state {
103            Empty => {
104                self.created = true;
105                let index = selector.add(selectable, self.pos, None);
106                self.state = Object(ObjectGrabState {
107                    index,
108                    action: Action::Connect,
109                });
110                selector.stop(selectable, index);
111            }
112            Object(ObjectGrabState { action, .. }) => *action = Action::Connect,
113        }
114    }
115}
116
117pub trait SelectionSet {
118    type Index;
119
120    fn to_vec(&self) -> Vec<Self::Index>;
121    fn contains(&self, index: &Self::Index) -> bool;
122
123    fn insert(&mut self, index: Self::Index);
124    fn remove(&mut self, index: &Self::Index);
125    fn clear(&mut self);
126
127    fn single(&mut self, index: Self::Index) {
128        self.clear();
129        self.insert(index);
130    }
131}
132
133impl<I: Clone + Eq + Hash> SelectionSet for HashSet<I> {
134    type Index = I;
135
136    fn to_vec(&self) -> Vec<I> {
137        self.iter().cloned().collect()
138    }
139
140    fn contains(&self, index: &I) -> bool {
141        self.contains(index)
142    }
143
144    fn insert(&mut self, index: I) {
145        self.insert(index);
146    }
147
148    fn remove(&mut self, index: &I) {
149        self.remove(index);
150    }
151
152    fn clear(&mut self) {
153        self.clear()
154    }
155
156    fn single(&mut self, index: I) {
157        self.clear();
158        self.insert(index);
159    }
160}
161
162impl<I: Clone + Ord> SelectionSet for BTreeSet<I> {
163    type Index = I;
164
165    fn to_vec(&self) -> Vec<I> {
166        self.iter().cloned().collect()
167    }
168
169    fn contains(&self, index: &I) -> bool {
170        self.contains(index)
171    }
172
173    fn insert(&mut self, index: I) {
174        self.insert(index);
175    }
176
177    fn remove(&mut self, index: &I) {
178        self.remove(index);
179    }
180
181    fn clear(&mut self) {
182        self.clear()
183    }
184
185    fn single(&mut self, index: I) {
186        self.clear();
187        self.insert(index);
188    }
189}
190
191#[derive(Default)]
192pub struct Selection<P, C: SelectionSet> {
193    pub selected: C,
194    pub grab: Option<GrabInfo<P, C::Index>>,
195}
196
197impl<P: Copy, C: SelectionSet> Selection<P, C>
198where
199    C::Index: Copy,
200{
201    pub fn new(selected: C) -> Self {
202        Self {
203            selected,
204            grab: None,
205        }
206    }
207
208    pub fn press<S: Selector<Position = P>>(
209        &mut self,
210        pos: P,
211        cursor: P,
212        selector: &S,
213        selectable: &S::Selectable,
214    ) where
215        S::Selectable: Selectable<Index = C::Index>,
216    {
217        use GrabState::*;
218
219        self.grab = Some(GrabInfo::new(
220            pos,
221            if let Some(index) = selector.get(selectable, pos) {
222                Object(ObjectGrabState {
223                    index,
224                    action: Action::Move,
225                })
226            } else {
227                Empty
228            },
229            cursor,
230        ));
231    }
232
233    pub fn release<S: Selector<Position = P>>(
234        &mut self,
235        pos: P,
236        selector: &S,
237        selectable: &mut S::Selectable,
238    ) where
239        S::Selectable: Selectable<Index = C::Index>,
240    {
241        let Some(mut grab_info) = self.grab.take() else {
242            return;
243        };
244
245        let GrabState::Object(ObjectGrabState {
246            action,
247            index: event,
248        }) = grab_info.state
249        else {
250            if grab_info.moved.is_some() {
251                self.selected.clear();
252            }
253
254            return;
255        };
256
257        for index in self.selected.to_vec() {
258            selector.stop(selectable, index);
259        }
260
261        use Action::*;
262        match action {
263            Connect => {
264                if grab_info.moved.is_none() {
265                    let index = selector.get(selectable, pos).unwrap_or_else(|| {
266                        let index = selector.add(selectable, pos, Some(event));
267                        selector.stop(selectable, index);
268                        index
269                    });
270                    selector.connect(selectable, index, &self.selected.to_vec());
271                    self.selected.single(index);
272                } else if self.selected.contains(&event) {
273                    self.selected.single(event);
274                } else if grab_info.created {
275                    grab_info.created = false;
276                    self.selected.insert(event);
277                } else {
278                    selector.special(selectable, event, &self.selected.to_vec());
279                }
280            }
281            Move => {
282                if grab_info.moved.is_none() {
283                    return;
284                }
285
286                if self.selected.contains(&event) {
287                    self.selected.remove(&event);
288                } else {
289                    self.selected.insert(event);
290                }
291            }
292        }
293    }
294
295    pub fn on_moved<S: Selector<Position = P>>(&mut self, cursor: P, selector: &S) {
296        let Some(grab_info) = &mut self.grab else {
297            return;
298        };
299
300        let &Some(moved) = &grab_info.moved else {
301            return;
302        };
303
304        if !selector.moved(moved, cursor) {
305            return;
306        }
307
308        grab_info.created = false;
309        grab_info.moved = None;
310
311        let &GrabState::Object(ObjectGrabState { index, .. }) = &grab_info.state else {
312            return;
313        };
314
315        if !self.selected.contains(&index) {
316            self.selected.single(index);
317        }
318    }
319}
320
321impl<P, S: SelectionSet + IntoIterator> IntoIterator for Selection<P, S> {
322    type Item = <S as IntoIterator>::Item;
323    type IntoIter = <S as IntoIterator>::IntoIter;
324
325    fn into_iter(self) -> Self::IntoIter {
326        self.selected.into_iter()
327    }
328}
329
330impl<'a, P, S: SelectionSet> IntoIterator for &'a Selection<P, S>
331where
332    &'a S: IntoIterator,
333{
334    type Item = <&'a S as IntoIterator>::Item;
335    type IntoIter = <&'a S as IntoIterator>::IntoIter;
336
337    fn into_iter(self) -> Self::IntoIter {
338        self.selected.into_iter()
339    }
340}
341
342impl<P, S: SelectionSet> Selection<P, S> {
343    pub fn iter<'a>(&'a self) -> <&'a S as IntoIterator>::IntoIter
344    where
345        &'a S: IntoIterator,
346    {
347        self.into_iter()
348    }
349}