aboutsummaryrefslogtreecommitdiffstats
path: root/src/event_filter.rs
blob: 9eb462022bddb4acd993b6d3fce3a89b3559ab75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::cirque::TouchData;

use core::{
    cmp,
    ops::Sub,
};

#[derive(Copy, Clone, Debug)]
pub struct Point<T>(pub T, pub T);

impl<T> Point<T>
where
    T: Sub<Output = T>,
{
    pub fn delta(self, p: Point<T>) -> Point<T> {
        Point(p.0 - self.0, p.1 - self.1)
    }
}

impl Point<isize> {
    pub fn scale(self) -> Self {
        Point(self.0 >> 2, self.1 >> 2)
    }
}

impl From<&TouchData> for Point<isize> {
    fn from(td: &TouchData) -> Self {
        Self(td.x as _, td.y as _)
    }
}

impl From<Point<isize>> for Point<i8> {
    fn from(p: Point<isize>) -> Self {
        Point(
            cmp::min(i8::MAX as isize, cmp::max(p.0, i8::MIN as isize)) as i8,
            cmp::min(i8::MAX as isize, cmp::max(p.1, i8::MIN as isize)) as i8,
        )
    }
}

pub struct AbsToRel {
    last_touch: Point<isize>,
    is_collecting: bool,
}

impl AbsToRel {
    pub fn new() -> Self {
        Self {
            last_touch: Point(0, 0),
            is_collecting: false,
        }
    }

    pub fn update(&mut self, td: &TouchData) -> Option<Point<i8>> {
        let p: Point<isize> = td.into();
        let p = p.scale();

        let res = self.last_touch.delta(p);
        self.last_touch = p;
        if self.is_collecting && td.is_pressed {
            Some(res.into())
        } else {
            self.is_collecting = td.is_pressed;
            None
        }
    }
}

pub struct TrackBall(Point<i8>, i8, u32);

impl TrackBall
where
{
    pub fn new(friction: i8) -> Self {
        Self(Point(i8::default(), i8::default()), friction, 0)
    }

    pub fn update(&mut self, point: Option<Point<i8>>, elapsed: u32) -> Point<i8> {
        if let Some(p) = point {
            self.0 = p;
            self.2 = 0;
        } else {
            let elapsed = elapsed + self.2;
            // TODO: configure time divisor
            let decel: i8 = self.1.saturating_mul((elapsed >> 15).try_into().unwrap_or(i8::MAX));
            let rem = elapsed & (1 << 15) - 1;
            self.2 = rem;

            if decel > 0 {
                let x = Self::abs_add(self.0.0, decel);
                let y = Self::abs_add(self.0.1, decel);
                self.0 = Point(x, y);
            }
        }
        self.0
    }

    fn abs_add(speed: i8, decel: i8) -> i8 {
        if speed > decel {
            speed - decel
        } else if speed < -decel {
            speed + decel
        } else {
            0
        }
    }
}