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
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Gesture controller and events.

use std::marker::PhantomData;

use crate::{bind, file::RwOps, EnumInt, Result, Sdl, SdlError};

use super::TouchDevice;

/// A gesture controller by $1 gesture recognition system.
#[derive(Debug, Clone)]
pub struct Gesture(bind::SDL_GestureID);

impl Gesture {
    /// Saves all gestures into `dst` and returns the numbers of succeed to write.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to save all the template data.
    pub fn save_dollar_template_all(dst: &RwOps) -> Result<usize> {
        let ret = unsafe { bind::SDL_SaveAllDollarTemplates(dst.ptr().as_ptr()) };
        if ret == 0 {
            Err(SdlError::Others { msg: Sdl::error() })
        } else {
            Ok(ret as usize)
        }
    }

    /// Saves gesture into `dst` and returns the numbers of succeed to write.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to save a template data.
    pub fn save_dollar_template(&self, dst: &RwOps) -> Result<usize> {
        let ret = unsafe { bind::SDL_SaveDollarTemplate(self.0, dst.ptr().as_ptr()) };
        if ret == 0 {
            Err(SdlError::Others { msg: Sdl::error() })
        } else {
            Ok(ret as usize)
        }
    }
}

/// An event on recognized a gesture
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum GestureEvent {
    /// The gesture was multi touches.
    Multi {
        /// When this event occurred.
        timestamp: u32,
        /// The rotating amount of fingers on the gesture.
        delta_theta: f32,
        /// The distance difference among fingers on the gesture.
        delta_dist: f32,
        /// The normalized x coord of the center on the gesture.
        x: f32,
        /// The normalized y coord of the center on the gesture.
        y: f32,
        /// The numbers of fingers on the gesture.
        num_fingers: u16,
    },
    /// The gesture was recognized by $1.
    Dollar {
        /// When this event occurred.
        timestamp: u32,
        /// The touch device the gesture detected.
        touch: TouchDevice,
        /// The id of the nearest gesture.
        gesture: Gesture,
        /// The numbers of fingers on the gesture.
        num_fingers: u32,
        /// The error from the template.
        error: f32,
        /// The normalized x coord of the center on the gesture.
        x: f32,
        /// The normalized y coord of the center on the gesture.
        y: f32,
    },
    /// The gesture was recorded for $1.
    DollarRecord {
        /// The touch device the gesture detected.
        touch: TouchDevice,
        /// The id of the nearest gesture.
        gesture: Gesture,
    },
}

impl From<bind::SDL_MultiGestureEvent> for GestureEvent {
    fn from(raw: bind::SDL_MultiGestureEvent) -> Self {
        Self::Multi {
            timestamp: raw.timestamp,
            delta_theta: raw.dTheta,
            delta_dist: raw.dDist,
            x: raw.x,
            y: raw.y,
            num_fingers: raw.numFingers,
        }
    }
}

impl From<bind::SDL_DollarGestureEvent> for GestureEvent {
    fn from(raw: bind::SDL_DollarGestureEvent) -> Self {
        match raw.type_ as EnumInt {
            bind::SDL_DOLLARGESTURE => Self::Dollar {
                timestamp: raw.timestamp,
                touch: TouchDevice(raw.touchId, PhantomData),
                gesture: Gesture(raw.gestureId),
                num_fingers: raw.numFingers,
                error: raw.error,
                x: raw.x,
                y: raw.y,
            },
            bind::SDL_DOLLARRECORD => Self::DollarRecord {
                touch: TouchDevice(raw.touchId, PhantomData),
                gesture: Gesture(raw.gestureId),
            },
            _ => unreachable!(),
        }
    }
}