use crate::core::Point;
use crate::event::{Event, TouchId};
use super::{distance, GestureRecognizer, LONG_PRESS_MAX_MOVE, LONG_PRESS_MIN_MS};
#[derive(Debug, Clone)]
pub struct LongPressGesture {
start_pos: Option<Point>,
start_time: Option<u64>,
touch_id: Option<TouchId>,
fired: bool,
}
impl LongPressGesture {
pub fn new() -> Self {
Self { start_pos: None, start_time: None, touch_id: None, fired: false }
}
}
impl GestureRecognizer for LongPressGesture {
fn process(&mut self, event: &Event, now_ms: u64) -> Option<Event> {
if self.fired {
if matches!(event, Event::TouchEnd { .. }) {
self.reset();
}
return None;
}
match event {
Event::TouchBegin { pos, touch_id } => {
self.start_pos = Some(*pos);
self.start_time = Some(now_ms);
self.touch_id = Some(*touch_id);
None
}
Event::TouchEnd { .. } => {
self.reset();
None
}
Event::TouchMove { pos, touch_id } => {
if self.touch_id == Some(*touch_id) {
if let Some(start) = self.start_pos {
if distance(start, *pos) > LONG_PRESS_MAX_MOVE {
self.reset();
}
}
}
None
}
_ => {
if let Some(start_time) = self.start_time {
let elapsed = now_ms.saturating_sub(start_time);
if elapsed >= LONG_PRESS_MIN_MS && matches!(event, Event::Timer { .. }) {
if let Some(pos) = self.start_pos {
self.fired = true;
return Some(Event::LongPress { pos });
}
}
}
None
}
}
}
fn reset(&mut self) {
self.start_pos = None;
self.start_time = None;
self.touch_id = None;
self.fired = false;
}
}
impl Default for LongPressGesture {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct PanGesture {
active: bool,
touch_id: Option<TouchId>,
last_pos: Option<Point>,
}
impl PanGesture {
pub fn new() -> Self {
Self { active: false, touch_id: None, last_pos: None }
}
}
impl GestureRecognizer for PanGesture {
fn process(&mut self, event: &Event, _now_ms: u64) -> Option<Event> {
match event {
Event::TouchBegin { pos, touch_id } if !self.active => {
self.active = true;
self.touch_id = Some(*touch_id);
self.last_pos = Some(*pos);
None
}
Event::TouchMove { pos, touch_id }
if self.active && Some(*touch_id) == self.touch_id =>
{
let delta = if let Some(last) = self.last_pos {
Point::new(pos.x - last.x, pos.y - last.y)
} else {
Point::new(0, 0)
};
self.last_pos = Some(*pos);
Some(Event::Drag { pos: *pos, touch_id: *touch_id, delta })
}
Event::TouchEnd { pos: _, touch_id } if Some(*touch_id) == self.touch_id => {
self.reset();
None
}
_ => None,
}
}
fn reset(&mut self) {
self.active = false;
self.touch_id = None;
self.last_pos = None;
}
}
impl Default for PanGesture {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct LongPressDragGesture {
start_pos: Option<Point>,
start_time: Option<u64>,
touch_id: Option<TouchId>,
long_press_fired: bool,
dragging: bool,
last_pos: Option<Point>,
}
impl LongPressDragGesture {
pub fn new() -> Self {
Self {
start_pos: None,
start_time: None,
touch_id: None,
long_press_fired: false,
dragging: false,
last_pos: None,
}
}
}
impl GestureRecognizer for LongPressDragGesture {
fn process(&mut self, event: &Event, now_ms: u64) -> Option<Event> {
match event {
Event::TouchBegin { pos, touch_id } if self.start_pos.is_none() => {
self.start_pos = Some(*pos);
self.start_time = Some(now_ms);
self.touch_id = Some(*touch_id);
self.long_press_fired = false;
self.dragging = false;
self.last_pos = Some(*pos);
None
}
Event::TouchMove { pos, touch_id } if self.touch_id == Some(*touch_id) => {
if self.dragging {
let delta = if let Some(last) = self.last_pos {
Point::new(pos.x - last.x, pos.y - last.y)
} else {
Point::new(0, 0)
};
self.last_pos = Some(*pos);
return Some(Event::Drag { pos: *pos, touch_id: *touch_id, delta });
}
if self.long_press_fired {
self.dragging = true;
self.last_pos = Some(*pos);
let delta = if let Some(start) = self.start_pos {
Point::new(pos.x - start.x, pos.y - start.y)
} else {
Point::new(0, 0)
};
return Some(Event::Drag { pos: *pos, touch_id: *touch_id, delta });
}
if let Some(start) = self.start_pos {
let dx = (pos.x - start.x).abs();
let dy = (pos.y - start.y).abs();
if (dx as f32) > LONG_PRESS_MAX_MOVE || (dy as f32) > LONG_PRESS_MAX_MOVE {
self.reset();
}
}
None
}
Event::TouchEnd { pos: _, touch_id } if self.touch_id == Some(*touch_id) => {
self.reset();
None
}
_ => {
if !self.long_press_fired && !self.dragging {
if let (Some(start_pos), Some(start)) = (self.start_pos, self.start_time) {
if now_ms >= start && now_ms - start >= LONG_PRESS_MIN_MS {
self.long_press_fired = true;
return Some(Event::LongPress { pos: start_pos });
}
}
}
None
}
}
}
fn reset(&mut self) {
self.start_pos = None;
self.start_time = None;
self.touch_id = None;
self.long_press_fired = false;
self.dragging = false;
self.last_pos = None;
}
}
impl Default for LongPressDragGesture {
fn default() -> Self {
Self::new()
}
}