makepad_platform/event/
finger.rs

1#![allow(unused)]
2#![allow(dead_code)]
3use {
4    std::{cell::Cell, ops::Deref},
5    crate::{
6        makepad_micro_serde::*,
7        makepad_live_tokenizer::{LiveErrorOrigin, live_error_origin},
8        makepad_live_compiler::{
9            LivePropType,
10            LiveType,
11            LiveTypeField,
12            LiveFieldKind,
13            LiveNode,
14            LiveId,
15            LiveModuleId,
16            LiveTypeInfo,
17            LiveNodeSliceApi
18        },
19        live_traits::{LiveNew, LiveHook, LiveRegister, LiveHookDeref, LiveApplyValue, LiveApply,LiveApplyReset, Apply},
20        makepad_derive_live::*,
21        makepad_math::*,
22        makepad_live_id::{FromLiveId, live_id, live_id_num},
23        event::{
24            event::{Event, Hit}
25        },
26        window::WindowId,
27        cx::Cx,
28        event::xr::XrHand,
29        area::Area,
30    },
31};
32
33// Mouse events
34
35
36#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, Eq, PartialEq)]
37pub struct KeyModifiers {
38    pub shift: bool,
39    pub control: bool,
40    pub alt: bool,
41    pub logo: bool
42}
43
44impl KeyModifiers{
45    /// Returns true if the primary key modifier is active (pressed).
46    ///
47    /// The primary modifier is Logo key (Command ⌘) on macOS
48    /// and the Control key on all other platforms.
49    pub fn is_primary(&self) -> bool {
50        #[cfg(target_vendor = "apple")] {
51            self.logo
52        }
53        #[cfg(not(target_vendor = "apple"))] {
54            self.control
55        }
56    }
57
58    fn any(&self)->bool{
59        self.shift || self.control || self.alt || self.logo
60    }
61}
62
63
64bitflags::bitflags! {
65    /// A `u32` bit mask of all mouse buttons that were pressed
66    /// during a given mouse event.
67    ///
68    /// This is a bit mask because it is possible for multiple buttons
69    /// to be pressed simultaneously during a given input event.
70    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
71    #[doc(alias = "click")]
72    pub struct MouseButton: u32 {
73        /// The primary mouse button, typically the left-click button.
74        #[doc(alias("left", "left-click"))]
75        const PRIMARY =   1 << 0;
76        /// The secondary mouse button, typically the right-click button.
77        #[doc(alias("right", "right-click"))]
78        const SECONDARY = 1 << 1;
79        /// The middle mouse button, typically the scroll-wheel click button.
80        #[doc(alias("scroll", "wheel"))]
81        const MIDDLE =    1 << 2;
82        /// The fourth mouse button, typically used for back navigation.
83        const BACK =      1 << 3;
84        /// The fifth mouse button, typically used for forward navigation.
85        const FORWARD =   1 << 4;
86
87        // Ensure that all bits are valid, such that no bits get truncated.
88        const _ = !0;
89    }
90}
91impl MouseButton {
92    /// Returns true if the primary mouse button is pressed.
93    pub fn is_primary(&self) -> bool {
94        self.contains(MouseButton::PRIMARY)
95    }
96    /// Returns true if the secondary mouse button is pressed.
97    pub fn is_secondary(&self) -> bool {
98        self.contains(MouseButton::SECONDARY)
99    }
100    /// Returns true if the middle mouse button is pressed.
101    pub fn is_middle(&self) -> bool {
102        self.contains(MouseButton::MIDDLE)
103    }
104    /// Returns true if the back mouse button is pressed.
105    pub fn is_back(&self) -> bool {
106        self.contains(MouseButton::BACK)
107    }
108    /// Returns true if the forward mouse button is pressed.
109    pub fn is_forward(&self) -> bool {
110        self.contains(MouseButton::FORWARD)
111    }
112    /// Returns true if the `n`th button is pressed.
113    ///
114    /// The button values are:
115    /// * n = 0: PRIMARY
116    /// * n = 1: SECONDARY
117    /// * n = 2: MIDDLE
118    /// * n = 3: BACK
119    /// * n = 4: FORWARD
120    /// * n > 4: other/custom
121    pub fn is_other_button(&self, n: u8) -> bool {
122        self.bits() & (1 << n) != 0
123    }
124    /// Returns a `MouseButton` bit mask based on the raw button value: `1 << raw`.
125    ///
126    /// A raw button value is a number that represents a mouse button, like so:
127    /// * 0: MouseButton::PRIMARY
128    /// * 1: MouseButton::SECONDARY
129    /// * 2: MouseButton::MIDDLE
130    /// * 3: MouseButton::BACK
131    /// * 4: MouseButton::FORWARD
132    /// * etc.
133    pub fn from_raw_button(raw: usize) -> MouseButton {
134        MouseButton::from_bits_retain(1 << raw)
135    }
136}
137
138
139#[derive(Clone, Debug)]
140pub struct MouseDownEvent {
141    pub abs: DVec2,
142    pub button: MouseButton,
143    pub window_id: WindowId,
144    pub modifiers: KeyModifiers,
145    pub handled: Cell<Area>,
146    pub time: f64,
147}
148
149
150#[derive(Clone, Debug)]
151pub struct MouseMoveEvent {
152    pub abs: DVec2,
153    pub window_id: WindowId,
154    pub modifiers: KeyModifiers,
155    pub time: f64,
156    pub handled: Cell<Area>,
157}
158
159#[derive(Clone, Debug)]
160pub struct MouseUpEvent {
161    pub abs: DVec2,
162    pub button: MouseButton,
163    pub window_id: WindowId,
164    pub modifiers: KeyModifiers,
165    pub time: f64
166}
167
168#[derive(Clone, Debug)]
169pub struct MouseLeaveEvent {
170    pub abs: DVec2,
171    pub window_id: WindowId,
172    pub modifiers: KeyModifiers,
173    pub time: f64,
174    pub handled: Cell<Area>,
175}
176
177#[derive(Clone, Debug)]
178pub struct ScrollEvent {
179    pub window_id: WindowId,
180    pub scroll: DVec2,
181    pub abs: DVec2,
182    pub modifiers: KeyModifiers,
183    pub handled_x: Cell<bool>,
184    pub handled_y: Cell<bool>,
185    pub is_mouse: bool,
186    pub time: f64
187}
188
189#[derive(Clone, Debug)]
190pub struct LongPressEvent {
191    pub window_id: WindowId,
192    pub abs: DVec2,
193    pub uid: u64,
194    pub time: f64,
195}
196
197// Touch events
198
199#[derive(Clone, Copy, Debug)]
200pub enum TouchState {
201    Start,
202    Stop,
203    Move,
204    Stable
205}
206
207#[derive(Clone, Debug)]
208pub struct TouchPoint {
209    pub state: TouchState,
210    pub abs: DVec2,
211    pub time: f64,
212    pub uid: u64,
213    pub rotation_angle: f64,
214    pub force: f64,
215    pub radius: DVec2,
216    pub handled: Cell<Area>,
217    pub sweep_lock: Cell<Area>,
218}
219
220#[derive(Clone, Debug)]
221pub struct TouchUpdateEvent {
222    pub time: f64,
223    pub window_id: WindowId,
224    pub modifiers: KeyModifiers,
225    pub touches: Vec<TouchPoint>,
226}
227
228
229// Finger API
230
231
232#[derive(Clone, Copy, Default, Debug, Live)]
233#[live_ignore]
234pub struct Margin {
235    #[live] pub left: f64,
236    #[live] pub top: f64,
237    #[live] pub right: f64,
238    #[live] pub bottom: f64
239}
240impl LiveRegister for Margin{}
241
242impl LiveHook for Margin {
243    fn skip_apply(&mut self, _cx: &mut Cx, _apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> Option<usize> {
244        if let Some(v) = nodes[index].value.as_float() {
245            *self = Self {left: v, top: v, right: v, bottom: v};
246            Some(index + 1)
247        }
248        else {
249            None
250        }
251    }
252}
253
254impl Margin {
255    pub fn left_top(&self) -> DVec2 {
256        dvec2(self.left, self.top)
257    }
258    pub fn right_bottom(&self) -> DVec2 {
259        dvec2(self.right, self.bottom)
260    }
261    pub fn size(&self) -> DVec2 {
262        dvec2(self.left + self.right, self.top + self.bottom)
263    }
264    pub fn width(&self) -> f64 {
265        self.left + self.right
266    }
267    pub fn height(&self) -> f64 {
268        self.top + self.bottom
269    }
270    
271    pub fn rect_contains_with_margin(pos: DVec2, rect: &Rect, margin: &Option<Margin>) -> bool {
272        if let Some(margin) = margin {
273            return
274            pos.x >= rect.pos.x - margin.left
275                && pos.x <= rect.pos.x + rect.size.x + margin.right
276                && pos.y >= rect.pos.y - margin.top
277                && pos.y <= rect.pos.y + rect.size.y + margin.bottom;
278        }
279        else {
280            return rect.contains(pos);
281        }
282    }
283}
284
285// TODO: query the platform for its long-press timeout.
286//       See Android's ViewConfiguration.getLongPressTimeout().
287pub const TAP_COUNT_TIME: f64 = 0.5;
288pub const TAP_COUNT_DISTANCE: f64 = 5.0;
289
290#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
291pub struct DigitId(pub LiveId);
292
293#[derive(Default, Clone)]
294pub struct CxDigitCapture {
295    digit_id: DigitId,
296    has_long_press_occurred: bool,
297    pub area: Area,
298    pub sweep_area: Area,
299    pub switch_capture: Option<Area>,
300    pub time: f64,
301    pub abs_start: DVec2,
302}
303
304#[derive(Default, Clone)]
305pub struct CxDigitTap {
306    digit_id: DigitId,
307    last_pos: DVec2,
308    last_time: f64,
309    count: u32
310}
311
312#[derive(Default, Clone)]
313pub struct CxDigitHover {
314    digit_id: DigitId,
315    new_area: Area,
316    area: Area,
317}
318
319#[derive(Default, Clone)]
320pub struct CxFingers {
321    pub first_mouse_button: Option<(MouseButton, WindowId)>,
322    captures: Vec<CxDigitCapture>,
323    tap: CxDigitTap,
324    hovers: Vec<CxDigitHover>,
325    sweep_lock: Option<Area>,
326}
327
328impl CxFingers {
329    /*
330    pub (crate) fn get_captured_area(&self, digit_id: DigitId) -> Area {
331        if let Some(cxdigit) = self.captures.iter().find( | v | v.digit_id == digit_id) {
332            cxdigit.area
333        }
334        else {
335            Area::Empty
336        }
337    }*/
338    /*
339    pub (crate) fn get_capture_time(&self, digit_id: DigitId) -> f64 {
340        if let Some(cxdigit) = self.captures.iter().find( | v | v.digit_id == digit_id) {
341            cxdigit.time
342        }
343        else {
344            0.0
345        }
346    }*/
347    
348    pub (crate) fn find_digit_for_captured_area(&self, area: Area) -> Option<DigitId> {
349        if let Some(digit) = self.captures.iter().find( | d | d.area == area) {
350            return Some(digit.digit_id)
351        }
352        None
353    }
354    
355    pub (crate) fn update_area(&mut self, old_area: Area, new_area: Area) {
356        for hover in &mut self.hovers {
357            if hover.area == old_area {
358                hover.area = new_area;
359            }
360        }
361        for capture in &mut self.captures {
362            if capture.area == old_area {
363                capture.area = new_area;
364            }
365            if capture.sweep_area == old_area {
366                capture.sweep_area = new_area;
367            }
368        }
369        if self.sweep_lock == Some(old_area) {
370            self.sweep_lock = Some(new_area);
371        }
372    }
373    
374    pub (crate) fn new_hover_area(&mut self, digit_id: DigitId, new_area: Area) {
375        for hover in &mut self.hovers {
376            if hover.digit_id == digit_id {
377                hover.new_area = new_area;
378                return
379            }
380        }
381        self.hovers.push(CxDigitHover {
382            digit_id,
383            area: Area::Empty,
384            new_area: new_area,
385        })
386    }
387    
388    pub (crate) fn find_hover_area(&self, digit: DigitId) -> Area {
389        for hover in &self.hovers {
390            if hover.digit_id == digit {
391                return hover.area
392            }
393        }
394        Area::Empty
395    }
396    
397    pub (crate) fn cycle_hover_area(&mut self, digit_id: DigitId) {
398        if let Some(hover) = self.hovers.iter_mut().find( | v | v.digit_id == digit_id) {
399            hover.area = hover.new_area;
400            hover.new_area = Area::Empty;
401        }
402    }
403    
404    pub (crate) fn capture_digit(&mut self, digit_id: DigitId, area: Area, sweep_area: Area, time: f64, abs_start: DVec2) {
405        /*if let Some(capture) = self.captures.iter_mut().find( | v | v.digit_id == digit_id) {
406            capture.sweep_area = sweep_area;
407            capture.area = area;
408            capture.time = time;
409            capture.abs_start = abs_start;
410        }
411        else {*/
412        self.captures.push(CxDigitCapture {
413            sweep_area,
414            digit_id,
415            area,
416            time,
417            abs_start,
418            has_long_press_occurred: false,
419            switch_capture: None
420        })
421        /*}*/
422    }
423    
424    pub (crate) fn uncapture_area(&mut self, area: Area){
425        self.captures.retain(|v| v.area != area);
426    }
427    
428    pub (crate) fn find_digit_capture(&mut self, digit_id: DigitId) -> Option<&mut CxDigitCapture> {
429        self.captures.iter_mut().find( | v | v.digit_id == digit_id)
430    }
431    
432    
433    pub (crate) fn find_area_capture(&mut self, area: Area) -> Option<&mut CxDigitCapture> {
434        self.captures.iter_mut().find( | v | v.area == area)
435    }
436    
437    pub fn is_area_captured(&self, area: Area) -> bool {
438        self.captures.iter().find( | v | v.area == area).is_some()
439    }
440    
441    pub fn any_areas_captured(&self) -> bool {
442        self.captures.len() > 0
443    }
444    
445    pub (crate) fn release_digit(&mut self, digit_id: DigitId) {
446        while let Some(index) = self.captures.iter_mut().position( | v | v.digit_id == digit_id) {
447            self.captures.remove(index);
448        }
449    }
450    
451    pub (crate) fn remove_hover(&mut self, digit_id: DigitId) {
452        while let Some(index) = self.hovers.iter_mut().position( | v | v.digit_id == digit_id) {
453            self.hovers.remove(index);
454        }
455    }
456    
457    pub (crate) fn tap_count(&self) -> u32 {
458        self.tap.count
459    }
460    
461    pub (crate) fn process_tap_count(&mut self, pos: DVec2, time: f64) -> u32 {
462        // TODO: query the platform for its multi-press / double-click timeout.
463        //       e.g., see Android's ViewConfiguration.getMultiPressTimeout().
464        if (time - self.tap.last_time) < TAP_COUNT_TIME
465            && pos.distance(&self.tap.last_pos) < TAP_COUNT_DISTANCE
466        {
467            self.tap.count += 1;
468        }
469        else {
470            self.tap.count = 1;
471        }
472        self.tap.last_pos = pos;
473        self.tap.last_time = time;
474        return self.tap.count
475    }
476    
477    pub (crate) fn process_touch_update_start(&mut self, time: f64, touches: &[TouchPoint]) {
478        for touch in touches {
479            if let TouchState::Start = touch.state {
480                self.process_tap_count(touch.abs, time);
481            }
482        }
483    }
484    
485    pub (crate) fn process_touch_update_end(&mut self, touches: &[TouchPoint]) {
486        for touch in touches {
487            let digit_id = live_id_num!(touch, touch.uid).into();
488            match touch.state {
489                TouchState::Stop => {
490                    self.release_digit(digit_id);
491                    self.remove_hover(digit_id);
492                }
493                TouchState::Start | TouchState::Move | TouchState::Stable => {
494                    self.cycle_hover_area(digit_id);
495                }
496            }
497        }
498        self.switch_captures();
499    }
500    
501    pub (crate) fn mouse_down(&mut self, button: MouseButton, window_id: WindowId) {
502        if self.first_mouse_button.is_none() {
503            self.first_mouse_button = Some((button, window_id));
504        }
505    }
506    
507    pub (crate) fn switch_captures(&mut self) {
508        for capture in &mut self.captures {
509            if let Some(area) = capture.switch_capture {
510                capture.area = area;
511                capture.switch_capture = None;
512            }
513        }
514    }
515    
516    pub (crate) fn mouse_up(&mut self, button: MouseButton) {
517        match self.first_mouse_button {
518            Some((fmb, _)) if fmb == button => {
519                self.first_mouse_button = None;
520                let digit_id = live_id!(mouse).into();
521                self.release_digit(digit_id);
522            }
523            _ => { }
524        }
525    }
526    
527    pub (crate) fn test_sweep_lock(&mut self, sweep_area: Area) -> bool {
528        if let Some(lock) = self.sweep_lock {
529            if lock != sweep_area {
530                return true
531            }
532        }
533        false
534    }
535    
536    pub fn sweep_lock(&mut self, area: Area) {
537        if self.sweep_lock.is_none() {
538            self.sweep_lock = Some(area);
539        }
540    }
541    
542    pub fn sweep_unlock(&mut self, area: Area) {
543        if self.sweep_lock == Some(area) {
544            self.sweep_lock = None;
545        }
546    }
547    
548}
549
550#[derive(Clone, Debug)]
551pub enum DigitDevice {
552    Mouse {
553        button: MouseButton,
554    },
555    Touch {
556        uid: u64
557    },
558    XrHand{
559        is_left: bool,
560        index: usize
561    },
562    XrController{
563    }
564}
565
566impl DigitDevice {
567    /// Returns true if this device is a touch device.
568    pub fn is_touch(&self) -> bool { matches!(self, Self::Touch {..}) }
569    /// Returns true if this device is a mouse.
570    pub fn is_mouse(&self) -> bool { matches!(self, Self::Mouse {..}) }
571    /// Returns true if this device is an XR device.
572    pub fn is_xr_hand(&self) -> bool { matches!(self, Self::XrHand {..}) }
573    pub fn is_xr_controller(&self) -> bool { matches!(self, Self::XrController {..}) }
574    /// Returns true if this device can hover: either a mouse or an XR device.
575    pub fn has_hovers(&self) -> bool { matches!(self, Self::Mouse {..} | Self::XrController {..}| Self::XrHand {..}) }
576    /// Returns the `MouseButton` if this device is a mouse; otherwise `None`.
577    pub fn mouse_button(&self) -> Option<MouseButton> {
578        if let Self::Mouse {button} = self {
579            Some(*button)
580        } else {
581            None
582        }
583    }
584    /// Returns the `uid` of the touch device if this device is a touch device; otherwise `None`.
585    pub fn touch_uid(&self) -> Option<u64> {
586        if let Self::Touch {uid} = self {
587            Some(*uid)
588        } else {
589            None
590        }
591    }
592    /// Returns true if this is a *primary* mouse button hit *or* any touch hit.
593    pub fn is_primary_hit(&self) -> bool {
594        match self {
595            DigitDevice::Mouse { button } => button.is_primary(),
596            DigitDevice::Touch {..} => true,
597            DigitDevice::XrHand {..} => true,
598            DigitDevice::XrController {..} => true,
599        }
600    }
601    // pub fn xr_input(&self) -> Option<usize> {if let DigitDevice::XR(input) = self {Some(*input)}else {None}}
602}
603
604#[derive(Clone, Debug)]
605pub struct FingerDownEvent {
606    pub window_id: WindowId,
607    pub abs: DVec2,
608    
609    pub digit_id: DigitId,
610    pub device: DigitDevice,
611    
612    pub tap_count: u32,
613    pub modifiers: KeyModifiers,
614    pub time: f64,
615    pub rect: Rect,
616}
617impl Deref for FingerDownEvent {
618    type Target = DigitDevice;
619    fn deref(&self) -> &DigitDevice {
620        &self.device
621    }
622}
623impl FingerDownEvent {
624    pub fn mod_control(&self) -> bool {self.modifiers.control}
625    pub fn mod_alt(&self) -> bool {self.modifiers.alt}
626    pub fn mod_shift(&self) -> bool {self.modifiers.shift}
627    pub fn mod_logo(&self) -> bool {self.modifiers.logo}
628}
629
630#[derive(Clone, Debug)]
631pub struct FingerMoveEvent {
632    pub window_id: WindowId,
633    pub abs: DVec2,
634    pub digit_id: DigitId,
635    pub device: DigitDevice,
636    
637    pub tap_count: u32,
638    pub modifiers: KeyModifiers,
639    pub time: f64,
640    
641    pub abs_start: DVec2,
642    pub rect: Rect,
643    pub is_over: bool,
644}
645impl Deref for FingerMoveEvent {
646    type Target = DigitDevice;
647    fn deref(&self) -> &DigitDevice {
648        &self.device
649    }
650}
651impl FingerMoveEvent {
652    pub fn move_distance(&self) -> f64 {
653        ((self.abs_start.x - self.abs.x).powf(2.) + (self.abs_start.y - self.abs.y).powf(2.)).sqrt()
654    }
655}
656
657#[derive(Clone, Debug)]
658pub struct FingerUpEvent {
659    pub window_id: WindowId,
660    /// The absolute position of this finger-up event.
661    pub abs: DVec2,
662    /// The absolute position of the original finger-down event.
663    pub abs_start: DVec2,
664    /// The time at which the original finger-down event occurred.
665    pub capture_time: f64,
666    /// The time at which this finger-up event occurred.
667    pub time: f64,
668
669    pub digit_id: DigitId,
670    pub device: DigitDevice,
671    /// Whether a platform-native long press has occurred between
672    /// the original finger-down event and this finger-up event.
673    pub has_long_press_occurred: bool,
674
675    pub tap_count: u32,
676    pub modifiers: KeyModifiers,
677    pub rect: Rect,
678    /// Whether this finger-up event (`abs`) occurred within the hits area.
679    pub is_over: bool,
680    pub is_sweep: bool,
681}
682impl Deref for FingerUpEvent {
683    type Target = DigitDevice;
684    fn deref(&self) -> &DigitDevice {
685        &self.device
686    }
687}
688impl FingerUpEvent {
689    /// Returns `true` if this FingerUp event was a regular tap/click (not a long press).
690    pub fn was_tap(&self) -> bool {
691        if self.has_long_press_occurred {
692            return false;
693        }
694        self.time - self.capture_time < TAP_COUNT_TIME
695        && (self.abs_start - self.abs).length() < TAP_COUNT_DISTANCE
696    }
697}
698
699#[derive(Clone, Debug)]
700pub struct FingerLongPressEvent {
701    pub window_id: WindowId,
702    /// The absolute position of this long-press event.
703    pub abs: DVec2,
704    /// The time at which the original finger-down event occurred.
705    pub capture_time: f64,
706    /// The time at which this long-press event occurred.
707    pub time: f64,
708    
709    pub digit_id: DigitId,
710    pub device: DigitDevice,
711    pub rect: Rect,
712}
713
714#[derive(Clone, Debug, Default, PartialEq)]
715pub enum HoverState {
716    In,
717    #[default]
718    Over,
719    Out
720}
721
722#[derive(Clone, Debug)]
723pub struct FingerHoverEvent {
724    pub window_id: WindowId,
725    pub abs: DVec2,
726    pub digit_id: DigitId,
727    pub device: DigitDevice,
728    pub modifiers: KeyModifiers,
729    pub time: f64,
730    pub rect: Rect,
731}
732
733#[derive(Clone, Debug)]
734pub struct FingerScrollEvent {
735    pub window_id: WindowId,
736    pub digit_id: DigitId,
737    pub abs: DVec2,
738    pub scroll: DVec2,
739    pub device: DigitDevice,
740    pub modifiers: KeyModifiers,
741    pub time: f64,
742    pub rect: Rect,
743}
744
745/*
746pub enum HitTouch {
747    Single,
748    Multi
749}*/
750
751
752// Status
753
754
755#[derive(Clone, Debug, Default)]
756pub struct HitOptions {
757    pub margin: Option<Margin>,
758    pub sweep_area: Area,
759    pub capture_overload: bool,
760}
761
762impl HitOptions {
763    pub fn new() -> Self {
764        Self::default()
765    }
766    
767    pub fn with_sweep_area(self, area: Area) -> Self {
768        Self {
769            sweep_area: area,
770            ..self
771        }
772    }
773    pub fn with_margin(self, margin: Margin) -> Self {
774        Self {
775            margin: Some(margin),
776            ..self
777        }
778    }
779    pub fn with_capture_overload(self, capture_overload:bool) -> Self {
780        Self {
781            capture_overload,
782            ..self
783        }
784    }
785}
786
787impl Event{
788    pub fn unhandle(&self, cx:&mut Cx, area:&Area){
789        match self{
790            Event::TouchUpdate(e)=>{
791                for t in &e.touches {
792                    if let TouchState::Start = t.state{
793                        if t.handled.get() == *area{
794                            t.handled.set(Area::Empty);
795                        }
796                        cx.fingers.uncapture_area(*area);
797                    }
798                }
799            }
800            Event::MouseDown(fd)=>{
801                if fd.handled.get() == *area{
802                    fd.handled.set(Area::Empty);
803                }
804                cx.fingers.uncapture_area(*area);
805            }
806            _=>()
807        }
808    }
809}
810
811impl Event {
812    
813    pub fn hits(&self, cx: &mut Cx, area: Area) -> Hit {
814        self.hits_with_options(cx, area, HitOptions::default())
815    }
816
817    pub fn hits_with_test<F>(&self, cx: &mut Cx, area: Area, hit_test:F) -> Hit 
818    where F: Fn(DVec2, &Rect, &Option<Margin>)->bool{
819        self.hits_with_options_and_test(cx, area,  HitOptions::new(), hit_test)
820    }
821
822    pub fn hits_with_sweep_area(&self, cx: &mut Cx, area: Area, sweep_area: Area) -> Hit {
823        self.hits_with_options(cx, area, HitOptions::new().with_sweep_area(sweep_area))
824    }
825    
826    pub fn hits_with_capture_overload(&self, cx: &mut Cx, area: Area, capture_overload: bool) -> Hit {
827        self.hits_with_options(cx, area, HitOptions::new().with_capture_overload(capture_overload))
828    }
829    
830    pub fn hits_with_options(&self, cx: &mut Cx, area: Area, options: HitOptions) -> Hit {
831        self.hits_with_options_and_test(cx, area, options, |abs, rect, margin|{
832            Margin::rect_contains_with_margin(abs, rect, margin)
833        })
834    }
835    
836    pub fn hits_with_options_and_test<F>(&self, cx: &mut Cx, area: Area, options: HitOptions, hit_test:F) -> Hit 
837    where F: Fn(DVec2, &Rect, &Option<Margin>)->bool
838    {
839        if !area.is_valid(cx) {
840            return Hit::Nothing
841        }
842        match self {
843            Event::KeyFocus(kf) => {
844                if area == kf.prev {
845                    return Hit::KeyFocusLost(kf.clone())
846                }
847                else if area == kf.focus {
848                    return Hit::KeyFocus(kf.clone())
849                }
850            },
851            Event::KeyDown(kd) => {
852                if cx.keyboard.has_key_focus(area) {
853                    return Hit::KeyDown(kd.clone())
854                }
855            },
856            Event::KeyUp(ku) => {
857                if cx.keyboard.has_key_focus(area) {
858                    return Hit::KeyUp(ku.clone())
859                }
860            },
861            Event::TextInput(ti) => {
862                if cx.keyboard.has_key_focus(area) {
863                    return Hit::TextInput(ti.clone())
864                }
865            },
866            Event::TextCopy(tc) => {
867                if cx.keyboard.has_key_focus(area) {
868                    return Hit::TextCopy(tc.clone());
869                }
870            },
871            Event::TextCut(tc) => {
872                if cx.keyboard.has_key_focus(area) {
873                    return Hit::TextCut(tc.clone());
874                }
875            },
876            Event::Scroll(e) => {
877                if cx.fingers.test_sweep_lock(options.sweep_area) {
878                    // log!("Skipping Scroll sweep_area: {:?}", options.sweep_area);
879                    return Hit::Nothing
880                }
881                let digit_id = live_id!(mouse).into();
882                
883                let rect = area.clipped_rect(&cx);
884                if hit_test(e.abs, &rect, &options.margin) {
885                    let device = DigitDevice::Mouse {
886                        button: MouseButton::PRIMARY,
887                    };
888                    return Hit::FingerScroll(FingerScrollEvent {
889                        abs: e.abs,
890                        rect,
891                        window_id: e.window_id,
892                        digit_id,
893                        device,
894                        modifiers: e.modifiers,
895                        time: e.time,
896                        scroll: e.scroll
897                    })
898                }
899            },
900            Event::TouchUpdate(e) => {
901                if cx.fingers.test_sweep_lock(options.sweep_area) {
902                    // log!("Skipping TouchUpdate, sweep_area: {:?}", options.sweep_area);
903                    return Hit::Nothing
904                }
905                for t in &e.touches {
906                    let digit_id = live_id_num!(touch, t.uid).into();
907                    let device = DigitDevice::Touch { uid: t.uid };
908
909                    match t.state {
910                        TouchState::Start => {
911                            // someone did a second call on our area
912                            if cx.fingers.find_digit_for_captured_area(area).is_some() {
913                                let rect = area.clipped_rect(&cx);
914                                return Hit::FingerDown(FingerDownEvent {
915                                    window_id: e.window_id,
916                                    abs: t.abs,
917                                    digit_id,
918                                    device,
919                                    tap_count: cx.fingers.tap_count(),
920                                    modifiers: e.modifiers,
921                                    time: e.time,
922                                    rect,
923                                });
924                            }
925                            
926                            if !options.capture_overload && !t.handled.get().is_empty() {
927                                continue;
928                            }
929                            
930                            if cx.fingers.find_area_capture(area).is_some(){
931                                continue;
932                            }
933                            
934                            let rect = area.clipped_rect(&cx);
935                            if !hit_test(t.abs, &rect, &options.margin) {
936                                continue;
937                            }
938                            
939                            cx.fingers.capture_digit(digit_id, area, options.sweep_area, e.time, t.abs);
940                            
941                            t.handled.set(area);
942                            return Hit::FingerDown(FingerDownEvent {
943                                window_id: e.window_id,
944                                abs: t.abs,
945                                digit_id,
946                                device,
947                                tap_count: cx.fingers.tap_count(),
948                                modifiers: e.modifiers,
949                                time: e.time,
950                                rect,
951                            });
952                        }
953                        TouchState::Stop => {
954                            let tap_count = cx.fingers.tap_count();
955                            let rect = area.clipped_rect(&cx);
956                            if let Some(capture) = cx.fingers.find_area_capture(area) {
957                                return Hit::FingerUp(FingerUpEvent {
958                                    abs_start: capture.abs_start,
959                                    rect,
960                                    window_id: e.window_id,
961                                    abs: t.abs,
962                                    digit_id,
963                                    device,
964                                    has_long_press_occurred: capture.has_long_press_occurred,
965                                    tap_count,
966                                    capture_time: capture.time,
967                                    modifiers: e.modifiers,
968                                    time: e.time,
969                                    is_over: rect.contains(t.abs),
970                                    is_sweep: false,
971                                });
972                            }
973                        }
974                        TouchState::Move => {
975                            let tap_count = cx.fingers.tap_count();
976                            //let hover_last = cx.fingers.get_hover_area(digit_id);
977                            let rect = area.clipped_rect(&cx);
978                            
979                            //let handled_area = t.handled.get();
980                            if !options.sweep_area.is_empty() {
981                                if let Some(capture) = cx.fingers.find_digit_capture(digit_id) {
982                                    if capture.switch_capture.is_none()
983                                        && hit_test(t.abs, &rect, &options.margin)
984                                    {
985                                        if t.handled.get().is_empty() {
986                                            t.handled.set(area);
987                                            if capture.area == area {
988                                                return Hit::FingerMove(FingerMoveEvent {
989                                                    window_id: e.window_id,
990                                                    abs: t.abs,
991                                                    digit_id,
992                                                    device,
993                                                    tap_count,
994                                                    modifiers: e.modifiers,
995                                                    time: e.time,
996                                                    abs_start: capture.abs_start,
997                                                    rect,
998                                                    is_over: true,
999                                                });
1000                                            }
1001                                            else if capture.sweep_area == options.sweep_area { // take over the capture
1002                                                capture.switch_capture = Some(area);
1003                                                return Hit::FingerDown(FingerDownEvent {
1004                                                    window_id: e.window_id,
1005                                                    abs: t.abs,
1006                                                    digit_id,
1007                                                    device,
1008                                                    tap_count: cx.fingers.tap_count(),
1009                                                    modifiers: e.modifiers,
1010                                                    time: e.time,
1011                                                    rect,
1012                                                });
1013                                            }
1014                                        }
1015                                    }
1016                                    else if capture.area == area { // we are not over the area
1017                                        if capture.switch_capture.is_none() {
1018                                            capture.switch_capture = Some(Area::Empty);
1019                                        }
1020                                        return Hit::FingerUp(FingerUpEvent {
1021                                            abs_start: capture.abs_start,
1022                                            rect,
1023                                            window_id: e.window_id,
1024                                            abs: t.abs,
1025                                            digit_id,
1026                                            device,
1027                                            has_long_press_occurred: capture.has_long_press_occurred,
1028                                            tap_count,
1029                                            capture_time: capture.time,
1030                                            modifiers: e.modifiers,
1031                                            time: e.time,
1032                                            is_sweep: true,
1033                                            is_over: false,
1034                                        });
1035                                    }
1036                                }
1037                            }
1038                            else if let Some(capture) = cx.fingers.find_area_capture(area) {
1039                                return Hit::FingerMove(FingerMoveEvent {
1040                                    window_id: e.window_id,
1041                                    abs: t.abs,
1042                                    digit_id,
1043                                    device,
1044                                    tap_count,
1045                                    modifiers: e.modifiers,
1046                                    time: e.time,
1047                                    abs_start: capture.abs_start,
1048                                    rect,
1049                                    is_over: hit_test(t.abs, &rect, &options.margin),
1050                                })
1051                            }
1052                        }
1053                        TouchState::Stable => {}
1054                    }
1055                }
1056            }
1057            Event::MouseMove(e) => { // ok so we dont get hovers
1058                if cx.fingers.test_sweep_lock(options.sweep_area) {
1059                    // log!("Skipping MouseMove, sweep_area: {:?}", options.sweep_area);
1060                    return Hit::Nothing
1061                }
1062                
1063                let digit_id = live_id!(mouse).into();
1064                
1065                let tap_count = cx.fingers.tap_count();
1066                let hover_last = cx.fingers.find_hover_area(digit_id);
1067                let rect = area.clipped_rect(&cx);
1068                
1069                if let Some((button, _window_id)) = cx.fingers.first_mouse_button {
1070                    let device = DigitDevice::Mouse {
1071                        button,
1072                    };
1073                    //let handled_area = e.handled.get();
1074                    if !options.sweep_area.is_empty() {
1075                        if let Some(capture) = cx.fingers.find_digit_capture(digit_id) {
1076                            if capture.switch_capture.is_none()
1077                                && hit_test(e.abs, &rect, &options.margin) {
1078                                if e.handled.get().is_empty() {
1079                                    e.handled.set(area);
1080                                    if capture.area == area {
1081                                        return Hit::FingerMove(FingerMoveEvent {
1082                                            window_id: e.window_id,
1083                                            abs: e.abs,
1084                                            digit_id,
1085                                            device,
1086                                            tap_count,
1087                                            modifiers: e.modifiers,
1088                                            time: e.time,
1089                                            abs_start: capture.abs_start,
1090                                            rect,
1091                                            is_over: true,
1092                                        })
1093                                    }
1094                                    else if capture.sweep_area == options.sweep_area { // take over the capture
1095                                        capture.switch_capture = Some(area);
1096                                        cx.fingers.new_hover_area(digit_id, area);
1097                                        return Hit::FingerDown(FingerDownEvent {
1098                                            window_id: e.window_id,
1099                                            abs: e.abs,
1100                                            digit_id,
1101                                            device,
1102                                            tap_count: cx.fingers.tap_count(),
1103                                            modifiers: e.modifiers,
1104                                            time: e.time,
1105                                            rect,
1106                                        })
1107                                    }
1108                                }
1109                            }
1110                            else if capture.area == area { // we are not over the area
1111                                if capture.switch_capture.is_none() {
1112                                    capture.switch_capture = Some(Area::Empty);
1113                                }
1114                                return Hit::FingerUp(FingerUpEvent {
1115                                    abs_start: capture.abs_start,
1116                                    rect,
1117                                    window_id: e.window_id,
1118                                    abs: e.abs,
1119                                    digit_id,
1120                                    device,
1121                                    has_long_press_occurred: capture.has_long_press_occurred,
1122                                    tap_count,
1123                                    capture_time: capture.time,
1124                                    modifiers: e.modifiers,
1125                                    time: e.time,
1126                                    is_sweep: true,
1127                                    is_over: false,
1128                                });
1129                                
1130                            }
1131                        }
1132                    }
1133                    else if let Some(capture) = cx.fingers.find_area_capture(area) {
1134                        let event = Hit::FingerMove(FingerMoveEvent {
1135                            window_id: e.window_id,
1136                            abs: e.abs,
1137                            digit_id,
1138                            device,
1139                            tap_count,
1140                            modifiers: e.modifiers,
1141                            time: e.time,
1142                            abs_start: capture.abs_start,
1143                            rect,
1144                            is_over: hit_test(e.abs, &rect, &options.margin),
1145                        });
1146                        cx.fingers.new_hover_area(digit_id, area);
1147                        return event
1148                    }
1149                }
1150                else {
1151                    let device = DigitDevice::Mouse {
1152                        button: MouseButton::PRIMARY,
1153                    };
1154                    
1155                    let handled_area = e.handled.get();
1156                    
1157                    let fhe = FingerHoverEvent {
1158                        window_id: e.window_id,
1159                        abs: e.abs,
1160                        digit_id,
1161                        device,
1162                        modifiers: e.modifiers,
1163                        time: e.time,
1164                        rect,
1165                    };
1166                    
1167                    if hover_last == area {
1168                        
1169                        if (handled_area.is_empty() || handled_area == area) && hit_test(e.abs, &rect, &options.margin) {
1170                            e.handled.set(area);
1171                            cx.fingers.new_hover_area(digit_id, area);
1172                            return Hit::FingerHoverOver(fhe)
1173                        }
1174                        else {
1175                            return Hit::FingerHoverOut(fhe)
1176                        }
1177                    }
1178                    else {
1179                        if (handled_area.is_empty() || handled_area == area) && hit_test(e.abs, &rect, &options.margin) {
1180                            //let any_captured = cx.fingers.get_digit_for_captured_area(area);
1181                            cx.fingers.new_hover_area(digit_id, area);
1182                            e.handled.set(area);
1183                            return Hit::FingerHoverIn(fhe)
1184                        }
1185                    }
1186                }
1187            },
1188            Event::MouseDown(e) => {
1189                                
1190                let digit_id = live_id!(mouse).into();
1191                                                
1192                let device = DigitDevice::Mouse {
1193                    button: e.button,
1194                };
1195                 
1196                // if we already captured it just return it immediately
1197                if cx.fingers.find_digit_for_captured_area(area).is_some() {
1198                    let rect = area.clipped_rect(&cx);
1199                    return Hit::FingerDown(FingerDownEvent {
1200                        window_id: e.window_id,
1201                        abs: e.abs,
1202                        digit_id,
1203                        device,
1204                        tap_count: cx.fingers.tap_count(),
1205                        modifiers: e.modifiers,
1206                        time: e.time,
1207                        rect,
1208                    })
1209                }
1210                
1211                if cx.fingers.test_sweep_lock(options.sweep_area) {
1212                    // log!("Skipping MouseDown, sweep_area: {:?}", options.sweep_area);
1213                    return Hit::Nothing
1214                }
1215                
1216                
1217                if !options.capture_overload && !e.handled.get().is_empty() {
1218                    return Hit::Nothing
1219                }
1220                
1221                if cx.fingers.first_mouse_button.is_some() && cx.fingers.first_mouse_button.unwrap().0 != e.button{
1222                    return Hit::Nothing
1223                }
1224                
1225                let rect = area.clipped_rect(&cx);
1226                if !hit_test(e.abs, &rect, &options.margin) {
1227                    return Hit::Nothing
1228                }
1229                
1230                
1231                if cx.fingers.find_digit_for_captured_area(area).is_some() {
1232                    return Hit::Nothing;
1233                }
1234                
1235                cx.fingers.capture_digit(digit_id, area, options.sweep_area, e.time, e.abs);
1236                e.handled.set(area);
1237                cx.fingers.new_hover_area(digit_id, area);
1238                return Hit::FingerDown(FingerDownEvent {
1239                    window_id: e.window_id,
1240                    abs: e.abs,
1241                    digit_id,
1242                    device,
1243                    tap_count: cx.fingers.tap_count(),
1244                    modifiers: e.modifiers,
1245                    time: e.time,
1246                    rect,
1247                })
1248            },
1249            Event::MouseUp(e) => {
1250                if cx.fingers.test_sweep_lock(options.sweep_area) {
1251                    // log!("Skipping MouseUp, sweep_area: {:?}", options.sweep_area);
1252                    return Hit::Nothing
1253                }
1254                
1255                if cx.fingers.first_mouse_button.is_some() && cx.fingers.first_mouse_button.unwrap().0 != e.button {
1256                    return Hit::Nothing
1257                }
1258                
1259                let digit_id = live_id!(mouse).into();
1260                
1261                let device = DigitDevice::Mouse {
1262                    button: e.button,
1263                };
1264                let tap_count = cx.fingers.tap_count();
1265                let rect = area.clipped_rect(&cx);
1266                
1267                if let Some(capture) = cx.fingers.find_area_capture(area) {
1268                    let is_over = hit_test(e.abs, &rect, &options.margin);
1269                    let event = Hit::FingerUp(FingerUpEvent {
1270                        abs_start: capture.abs_start,
1271                        rect,
1272                        window_id: e.window_id,
1273                        abs: e.abs,
1274                        digit_id,
1275                        device,
1276                        has_long_press_occurred: capture.has_long_press_occurred,
1277                        tap_count,
1278                        capture_time: capture.time,
1279                        modifiers: e.modifiers,
1280                        time: e.time,
1281                        is_over,
1282                        is_sweep: false,
1283                    });
1284                    if is_over {
1285                        cx.fingers.new_hover_area(digit_id, area);
1286                    }
1287                    return event
1288                }
1289            },
1290            Event::MouseLeave(e) => {
1291                if cx.fingers.test_sweep_lock(options.sweep_area) {
1292                    // log!("Skipping MouseLeave, sweep_area: {:?}", options.sweep_area);
1293                    return Hit::Nothing;
1294                }
1295                let device = DigitDevice::Mouse { button: MouseButton::empty() };
1296                let digit_id = live_id!(mouse).into();
1297                let rect = area.clipped_rect(&cx);
1298                let hover_last = cx.fingers.find_hover_area(digit_id);
1299                let handled_area = e.handled.get();
1300                
1301                let fhe = FingerHoverEvent {
1302                    window_id: e.window_id,
1303                    abs: e.abs,
1304                    digit_id,
1305                    device,
1306                    modifiers: e.modifiers,
1307                    time: e.time,
1308                    rect,
1309                };
1310                if hover_last == area {
1311                    return Hit::FingerHoverOut(fhe);
1312                }
1313            },
1314            Event::LongPress(e) => {
1315                if cx.fingers.test_sweep_lock(options.sweep_area) {
1316                    log!("Skipping LongPress Hit, sweep_area: {:?}", options.sweep_area);
1317                    return Hit::Nothing
1318                }
1319
1320                let rect = area.clipped_rect(&cx);
1321                if let Some(capture) = cx.fingers.find_area_capture(area) {
1322                    capture.has_long_press_occurred = true;
1323                    // No hit test is needed because we already did that in the previous
1324                    // FingerDown `capture` event that started the long press.
1325                    // Also, there is no need to include the starting position (`abs_start`)
1326                    // since it will always be identical to the `abs` position of the original capture.
1327                    let digit_id = live_id_num!(touch, e.uid).into();
1328                    let device = DigitDevice::Touch {
1329                        uid: e.uid,
1330                    };
1331                    return Hit::FingerLongPress(FingerLongPressEvent {
1332                        window_id: e.window_id,
1333                        abs: e.abs,
1334                        capture_time: capture.time,
1335                        time: e.time,
1336                        digit_id,
1337                        device,
1338                        rect,
1339                    });
1340                }
1341            },
1342            Event::DesignerPick(e) => {
1343               
1344                let rect = area.clipped_rect(&cx);
1345                if !hit_test(e.abs, &rect, &options.margin) {
1346                    return Hit::Nothing
1347                }
1348                // lets add our area to a handled vec?
1349                // but how will we communicate the widget?
1350                return Hit::DesignerPick(e.clone())
1351            },
1352            Event::XrLocal(e)=>{
1353                return e.hits_with_options_and_test(cx, area, options, hit_test)
1354            },
1355            _ => ()
1356        };
1357        Hit::Nothing
1358    }
1359}