Skip to main content

freya_core/
events_combos.rs

1use std::time::{
2    Duration,
3    Instant,
4};
5
6use torin::prelude::CursorPoint;
7
8use crate::{
9    integration::ScopeId,
10    prelude::{
11        State,
12        *,
13    },
14};
15
16#[derive(Clone, Copy, PartialEq)]
17pub struct EventsCombos {
18    pub(crate) last_press: State<Option<(Instant, CursorPoint, u8)>>,
19}
20
21impl EventsCombos {
22    pub fn get() -> Self {
23        match try_consume_root_context() {
24            Some(rt) => rt,
25            None => {
26                let context_menu_state = EventsCombos {
27                    last_press: State::create_in_scope(None, ScopeId::ROOT),
28                };
29                provide_context_for_scope_id(context_menu_state, ScopeId::ROOT);
30                context_menu_state
31            }
32        }
33    }
34
35    /// Break the multi press chain when the pointer drags away from the last press.
36    pub fn moved(location: CursorPoint) {
37        let mut combos = Self::get();
38        let dragged_away = matches!(
39            &*combos.last_press.read(),
40            Some((_, last_location, _)) if last_location.distance_to(location) > LOCATION_THRESHOLD
41        );
42        if dragged_away {
43            combos.last_press.set(None);
44        }
45    }
46
47    pub fn pressed(location: CursorPoint) -> PressEventType {
48        let mut combos = Self::get();
49        let (event_type, click_count) = match &*combos.last_press.read() {
50            Some((inst, last_location, count)) if inst.elapsed() <= MULTI_PRESS_ELAPSED => {
51                if last_location.distance_to(location) <= LOCATION_THRESHOLD {
52                    match count {
53                        1 => (PressEventType::Double, 2),
54                        2 => (PressEventType::Triple, 3),
55                        3 => (PressEventType::Quadruple, 4),
56                        _ => (PressEventType::Single, 1),
57                    }
58                } else {
59                    (PressEventType::Single, 1)
60                }
61            }
62            _ => (PressEventType::Single, 1),
63        };
64        combos
65            .last_press
66            .set(Some((Instant::now(), location, click_count)));
67        event_type
68    }
69}
70
71const LOCATION_THRESHOLD: f64 = 5.0;
72const MULTI_PRESS_ELAPSED: Duration = Duration::from_millis(500);
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum PressEventType {
76    Single,
77    Double,
78    Triple,
79    Quadruple,
80}
81
82impl PressEventType {
83    pub fn is_single(&self) -> bool {
84        matches!(self, Self::Single)
85    }
86
87    pub fn is_double(&self) -> bool {
88        matches!(self, Self::Double)
89    }
90
91    pub fn is_triple(&self) -> bool {
92        matches!(self, Self::Triple)
93    }
94
95    pub fn is_quadruple(&self) -> bool {
96        matches!(self, Self::Quadruple)
97    }
98}