use crate::compat::HashMap;
use crate::event::types::{Event, TouchId};
#[derive(Debug, Default)]
pub struct TouchEventTranslator {
active_touches: HashMap<TouchId, (/* x */ i32, /* y */ i32)>,
enabled: bool,
}
impl TouchEventTranslator {
pub fn new() -> Self {
Self { active_touches: HashMap::new(), enabled: true }
}
pub fn disabled() -> Self {
Self { active_touches: HashMap::new(), enabled: false }
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn is_enabled(&self) -> bool {
self.enabled
}
pub fn translate(&mut self, event: &Event) -> Vec<Event> {
if !self.enabled {
return Vec::new();
}
match *event {
Event::TouchBegin { pos, touch_id } => {
self.active_touches.insert(touch_id, (pos.x, pos.y));
vec![Event::MousePress { pos, button: 0 }, Event::MouseEnter { pos }]
}
Event::TouchMove { pos, touch_id } => {
if let std::collections::hash_map::Entry::Occupied(mut e) =
self.active_touches.entry(touch_id)
{
e.insert((pos.x, pos.y));
vec![Event::MouseMove { pos }]
} else {
Vec::new()
}
}
Event::TouchEnd { pos, touch_id } => {
self.active_touches.remove(&touch_id);
vec![Event::MouseRelease { pos, button: 0 }, Event::MouseLeave { pos }]
}
_ => Vec::new(),
}
}
pub fn clear(&mut self) {
self.active_touches.clear();
}
pub fn active_touch_count(&self) -> usize {
self.active_touches.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::Point;
#[test]
fn touch_begin_generates_mouse_press_and_enter() {
let mut t = TouchEventTranslator::new();
let ev = Event::TouchBegin { pos: Point::new(10, 20), touch_id: 1 };
let result = t.translate(&ev);
assert_eq!(result.len(), 2);
assert!(matches!(result[0], Event::MousePress { .. }));
assert!(matches!(result[1], Event::MouseEnter { .. }));
assert_eq!(t.active_touch_count(), 1);
}
#[test]
fn touch_move_generates_mouse_move() {
let mut t = TouchEventTranslator::new();
t.translate(&Event::TouchBegin { pos: Point::new(0, 0), touch_id: 1 });
let ev = Event::TouchMove { pos: Point::new(10, 20), touch_id: 1 };
let result = t.translate(&ev);
assert_eq!(result.len(), 1);
assert!(matches!(result[0], Event::MouseMove { .. }));
}
#[test]
fn touch_end_generates_mouse_release_and_leave() {
let mut t = TouchEventTranslator::new();
t.translate(&Event::TouchBegin { pos: Point::new(0, 0), touch_id: 1 });
let ev = Event::TouchEnd { pos: Point::new(10, 20), touch_id: 1 };
let result = t.translate(&ev);
assert_eq!(result.len(), 2);
assert!(matches!(result[0], Event::MouseRelease { .. }));
assert!(matches!(result[1], Event::MouseLeave { .. }));
assert_eq!(t.active_touch_count(), 0);
}
#[test]
fn unknown_touch_id_ignored() {
let mut t = TouchEventTranslator::new();
let ev = Event::TouchMove { pos: Point::new(10, 20), touch_id: 999 };
let result = t.translate(&ev);
assert!(result.is_empty());
}
#[test]
fn disabled_translator_produces_no_events() {
let mut t = TouchEventTranslator::disabled();
let ev = Event::TouchBegin { pos: Point::new(10, 20), touch_id: 1 };
let result = t.translate(&ev);
assert!(result.is_empty());
}
#[test]
fn non_touch_events_produce_no_translation() {
let mut t = TouchEventTranslator::new();
let ev = Event::MousePress { pos: Point::new(10, 20), button: 0 };
let result = t.translate(&ev);
assert!(result.is_empty());
}
#[test]
fn clear_removes_all_tracked_touches() {
let mut t = TouchEventTranslator::new();
t.translate(&Event::TouchBegin { pos: Point::new(0, 0), touch_id: 1 });
t.translate(&Event::TouchBegin { pos: Point::new(0, 0), touch_id: 2 });
assert_eq!(t.active_touch_count(), 2);
t.clear();
assert_eq!(t.active_touch_count(), 0);
}
#[test]
fn multiple_touches_tracked_independently() {
let mut t = TouchEventTranslator::new();
t.translate(&Event::TouchBegin { pos: Point::new(10, 20), touch_id: 1 });
t.translate(&Event::TouchBegin { pos: Point::new(30, 40), touch_id: 2 });
assert_eq!(t.active_touch_count(), 2);
let r1 = t.translate(&Event::TouchMove { pos: Point::new(15, 25), touch_id: 1 });
assert_eq!(r1.len(), 1);
let r2 = t.translate(&Event::TouchEnd { pos: Point::new(35, 45), touch_id: 2 });
assert_eq!(r2.len(), 2);
assert_eq!(t.active_touch_count(), 1);
}
}