use std::collections::HashMap;
#[derive(Default, Debug, Clone, Copy)]
pub struct TouchPoint {
pub id: u64,
pub position: nalgebra_glm::Vec2,
pub start_position: nalgebra_glm::Vec2,
pub previous_position: nalgebra_glm::Vec2,
pub phase: TouchPhase,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum TouchPhase {
#[default]
Started,
Moved,
Ended,
Cancelled,
}
#[derive(Default, Debug, Clone)]
pub struct Touch {
pub touches: HashMap<u64, TouchPoint>,
pub primary_touch_id: Option<u64>,
pub secondary_touch_id: Option<u64>,
pub gesture: TouchGesture,
}
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub enum TouchGesture {
#[default]
None,
SingleDrag { delta: nalgebra_glm::Vec2 },
Pinch {
delta: f32,
center: nalgebra_glm::Vec2,
},
TwoFingerDrag { delta: nalgebra_glm::Vec2 },
}
impl Touch {
pub fn active_touch_count(&self) -> usize {
self.touches
.values()
.filter(|t| t.phase != TouchPhase::Ended && t.phase != TouchPhase::Cancelled)
.count()
}
pub fn primary_touch(&self) -> Option<&TouchPoint> {
self.primary_touch_id
.and_then(|id| self.touches.get(&id))
.filter(|t| t.phase != TouchPhase::Ended && t.phase != TouchPhase::Cancelled)
}
pub fn secondary_touch(&self) -> Option<&TouchPoint> {
self.secondary_touch_id
.and_then(|id| self.touches.get(&id))
.filter(|t| t.phase != TouchPhase::Ended && t.phase != TouchPhase::Cancelled)
}
pub fn update_gesture(&mut self) {
let active_count = self.active_touch_count();
self.gesture = match active_count {
1 => {
if let Some(touch) = self.primary_touch() {
if touch.phase == TouchPhase::Moved {
let delta = touch.position - touch.previous_position;
TouchGesture::SingleDrag { delta }
} else {
TouchGesture::None
}
} else {
TouchGesture::None
}
}
2 => {
if let (Some(primary), Some(secondary)) =
(self.primary_touch(), self.secondary_touch())
{
let current_distance = (primary.position - secondary.position).magnitude();
let previous_distance =
(primary.previous_position - secondary.previous_position).magnitude();
let pinch_delta = current_distance - previous_distance;
let primary_delta = primary.position - primary.previous_position;
let secondary_delta = secondary.position - secondary.previous_position;
let avg_delta = (primary_delta + secondary_delta) * 0.5;
let center = (primary.position + secondary.position) * 0.5;
if pinch_delta.abs() > avg_delta.magnitude() * 0.5 {
TouchGesture::Pinch {
delta: pinch_delta,
center,
}
} else {
TouchGesture::TwoFingerDrag { delta: avg_delta }
}
} else {
TouchGesture::None
}
}
_ => TouchGesture::None,
};
}
pub fn clear_ended_touches(&mut self) {
self.touches
.retain(|_, t| t.phase != TouchPhase::Ended && t.phase != TouchPhase::Cancelled);
if let Some(id) = self.primary_touch_id
&& !self.touches.contains_key(&id)
{
self.primary_touch_id = None;
}
if let Some(id) = self.secondary_touch_id
&& !self.touches.contains_key(&id)
{
self.secondary_touch_id = None;
}
}
}