bevy_picking/
events.rs

1//! This module defines a stateful set of interaction events driven by the `PointerInput` stream
2//! and the hover state of each Pointer.
3//!
4//! # Usage
5//!
6//! To receive events from this module, you must use an [`Observer`] or [`EventReader`] with [`Pointer<E>`] events.
7//! The simplest example, registering a callback when an entity is hovered over by a pointer, looks like this:
8//!
9//! ```rust
10//! # use bevy_ecs::prelude::*;
11//! # use bevy_picking::prelude::*;
12//! # let mut world = World::default();
13//! world.spawn_empty()
14//!     .observe(|trigger: Trigger<Pointer<Over>>| {
15//!         println!("I am being hovered over");
16//!     });
17//! ```
18//!
19//! Observers give us three important properties:
20//! 1. They allow for attaching event handlers to specific entities,
21//! 2. they allow events to bubble up the entity hierarchy,
22//! 3. and they allow events of different types to be called in a specific order.
23//!
24//! The order in which interaction events are received is extremely important, and you can read more
25//! about it on the docs for the dispatcher system: [`pointer_events`]. This system runs in
26//! [`PreUpdate`](bevy_app::PreUpdate) in [`PickSet::Hover`](crate::PickSet::Hover). All pointer-event
27//! observers resolve during the sync point between [`pointer_events`] and
28//! [`update_interactions`](crate::hover::update_interactions).
29//!
30//! # Events Types
31//!
32//! The events this module defines fall into a few broad categories:
33//! + Hovering and movement: [`Over`], [`Move`], and [`Out`].
34//! + Clicking and pressing: [`Pressed`], [`Released`], and [`Click`].
35//! + Dragging and dropping: [`DragStart`], [`Drag`], [`DragEnd`], [`DragEnter`], [`DragOver`], [`DragDrop`], [`DragLeave`].
36//!
37//! When received by an observer, these events will always be wrapped by the [`Pointer`] type, which contains
38//! general metadata about the pointer event.
39
40use core::{fmt::Debug, time::Duration};
41
42use bevy_ecs::{prelude::*, query::QueryData, system::SystemParam, traversal::Traversal};
43use bevy_input::mouse::MouseScrollUnit;
44use bevy_math::Vec2;
45use bevy_platform::collections::HashMap;
46use bevy_platform::time::Instant;
47use bevy_reflect::prelude::*;
48use bevy_render::camera::NormalizedRenderTarget;
49use bevy_window::Window;
50use tracing::debug;
51
52use crate::{
53    backend::{prelude::PointerLocation, HitData},
54    hover::{HoverMap, PreviousHoverMap},
55    pointer::{Location, PointerAction, PointerButton, PointerId, PointerInput, PointerMap},
56};
57
58/// Stores the common data needed for all pointer events.
59///
60/// The documentation for the [`pointer_events`] explains the events this module exposes and
61/// the order in which they fire.
62#[derive(Clone, PartialEq, Debug, Reflect, Component)]
63#[reflect(Component, Debug, Clone)]
64pub struct Pointer<E: Debug + Clone + Reflect> {
65    /// The original target of this picking event, before bubbling
66    pub target: Entity,
67    /// The pointer that triggered this event
68    pub pointer_id: PointerId,
69    /// The location of the pointer during this event
70    pub pointer_location: Location,
71    /// Additional event-specific data. [`DragDrop`] for example, has an additional field to describe
72    /// the `Entity` that is being dropped on the target.
73    pub event: E,
74}
75
76/// A traversal query (i.e. it implements [`Traversal`]) intended for use with [`Pointer`] events.
77///
78/// This will always traverse to the parent, if the entity being visited has one. Otherwise, it
79/// propagates to the pointer's window and stops there.
80#[derive(QueryData)]
81pub struct PointerTraversal {
82    child_of: Option<&'static ChildOf>,
83    window: Option<&'static Window>,
84}
85
86impl<E> Traversal<Pointer<E>> for PointerTraversal
87where
88    E: Debug + Clone + Reflect,
89{
90    fn traverse(item: Self::Item<'_>, pointer: &Pointer<E>) -> Option<Entity> {
91        let PointerTraversalItem { child_of, window } = item;
92
93        // Send event to parent, if it has one.
94        if let Some(child_of) = child_of {
95            return Some(child_of.parent());
96        };
97
98        // Otherwise, send it to the window entity (unless this is a window entity).
99        if window.is_none() {
100            if let NormalizedRenderTarget::Window(window_ref) = pointer.pointer_location.target {
101                return Some(window_ref.entity());
102            }
103        }
104
105        None
106    }
107}
108
109impl<E> Event for Pointer<E>
110where
111    E: Debug + Clone + Reflect,
112{
113    type Traversal = PointerTraversal;
114
115    const AUTO_PROPAGATE: bool = true;
116}
117
118impl<E: Debug + Clone + Reflect> core::fmt::Display for Pointer<E> {
119    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120        f.write_fmt(format_args!(
121            "{:?}, {:.1?}, {:.1?}",
122            self.pointer_id, self.pointer_location.position, self.event
123        ))
124    }
125}
126
127impl<E: Debug + Clone + Reflect> core::ops::Deref for Pointer<E> {
128    type Target = E;
129
130    fn deref(&self) -> &Self::Target {
131        &self.event
132    }
133}
134
135impl<E: Debug + Clone + Reflect> Pointer<E> {
136    /// Construct a new `Pointer<E>` event.
137    pub fn new(id: PointerId, location: Location, target: Entity, event: E) -> Self {
138        Self {
139            target,
140            pointer_id: id,
141            pointer_location: location,
142            event,
143        }
144    }
145}
146
147/// Fires when a pointer is canceled, and its current interaction state is dropped.
148#[derive(Clone, PartialEq, Debug, Reflect)]
149#[reflect(Clone, PartialEq)]
150pub struct Cancel {
151    /// Information about the picking intersection.
152    pub hit: HitData,
153}
154
155/// Fires when a the pointer crosses into the bounds of the `target` entity.
156#[derive(Clone, PartialEq, Debug, Reflect)]
157#[reflect(Clone, PartialEq)]
158pub struct Over {
159    /// Information about the picking intersection.
160    pub hit: HitData,
161}
162
163/// Fires when a the pointer crosses out of the bounds of the `target` entity.
164#[derive(Clone, PartialEq, Debug, Reflect)]
165#[reflect(Clone, PartialEq)]
166pub struct Out {
167    /// Information about the latest prior picking intersection.
168    pub hit: HitData,
169}
170
171/// Fires when a pointer button is pressed over the `target` entity.
172#[derive(Clone, PartialEq, Debug, Reflect)]
173#[reflect(Clone, PartialEq)]
174pub struct Pressed {
175    /// Pointer button pressed to trigger this event.
176    pub button: PointerButton,
177    /// Information about the picking intersection.
178    pub hit: HitData,
179}
180
181/// Fires when a pointer button is released over the `target` entity.
182#[derive(Clone, PartialEq, Debug, Reflect)]
183#[reflect(Clone, PartialEq)]
184pub struct Released {
185    /// Pointer button lifted to trigger this event.
186    pub button: PointerButton,
187    /// Information about the picking intersection.
188    pub hit: HitData,
189}
190
191/// Fires when a pointer sends a pointer pressed event followed by a pointer released event, with the same
192/// `target` entity for both events.
193#[derive(Clone, PartialEq, Debug, Reflect)]
194#[reflect(Clone, PartialEq)]
195pub struct Click {
196    /// Pointer button pressed and lifted to trigger this event.
197    pub button: PointerButton,
198    /// Information about the picking intersection.
199    pub hit: HitData,
200    /// Duration between the pointer pressed and lifted for this click
201    pub duration: Duration,
202}
203
204/// Fires while a pointer is moving over the `target` entity.
205#[derive(Clone, PartialEq, Debug, Reflect)]
206#[reflect(Clone, PartialEq)]
207pub struct Move {
208    /// Information about the picking intersection.
209    pub hit: HitData,
210    /// The change in position since the last move event.
211    pub delta: Vec2,
212}
213
214/// Fires when the `target` entity receives a pointer pressed event followed by a pointer move event.
215#[derive(Clone, PartialEq, Debug, Reflect)]
216#[reflect(Clone, PartialEq)]
217pub struct DragStart {
218    /// Pointer button pressed and moved to trigger this event.
219    pub button: PointerButton,
220    /// Information about the picking intersection.
221    pub hit: HitData,
222}
223
224/// Fires while the `target` entity is being dragged.
225#[derive(Clone, PartialEq, Debug, Reflect)]
226#[reflect(Clone, PartialEq)]
227pub struct Drag {
228    /// Pointer button pressed and moved to trigger this event.
229    pub button: PointerButton,
230    /// The total distance vector of a drag, measured from drag start to the current position.
231    pub distance: Vec2,
232    /// The change in position since the last drag event.
233    pub delta: Vec2,
234}
235
236/// Fires when a pointer is dragging the `target` entity and a pointer released event is received.
237#[derive(Clone, PartialEq, Debug, Reflect)]
238#[reflect(Clone, PartialEq)]
239pub struct DragEnd {
240    /// Pointer button pressed, moved, and released to trigger this event.
241    pub button: PointerButton,
242    /// The vector of drag movement measured from start to final pointer position.
243    pub distance: Vec2,
244}
245
246/// Fires when a pointer dragging the `dragged` entity enters the `target` entity.
247#[derive(Clone, PartialEq, Debug, Reflect)]
248#[reflect(Clone, PartialEq)]
249pub struct DragEnter {
250    /// Pointer button pressed to enter drag.
251    pub button: PointerButton,
252    /// The entity that was being dragged when the pointer entered the `target` entity.
253    pub dragged: Entity,
254    /// Information about the picking intersection.
255    pub hit: HitData,
256}
257
258/// Fires while the `dragged` entity is being dragged over the `target` entity.
259#[derive(Clone, PartialEq, Debug, Reflect)]
260#[reflect(Clone, PartialEq)]
261pub struct DragOver {
262    /// Pointer button pressed while dragging over.
263    pub button: PointerButton,
264    /// The entity that was being dragged when the pointer was over the `target` entity.
265    pub dragged: Entity,
266    /// Information about the picking intersection.
267    pub hit: HitData,
268}
269
270/// Fires when a pointer dragging the `dragged` entity leaves the `target` entity.
271#[derive(Clone, PartialEq, Debug, Reflect)]
272#[reflect(Clone, PartialEq)]
273pub struct DragLeave {
274    /// Pointer button pressed while leaving drag.
275    pub button: PointerButton,
276    /// The entity that was being dragged when the pointer left the `target` entity.
277    pub dragged: Entity,
278    /// Information about the latest prior picking intersection.
279    pub hit: HitData,
280}
281
282/// Fires when a pointer drops the `dropped` entity onto the `target` entity.
283#[derive(Clone, PartialEq, Debug, Reflect)]
284#[reflect(Clone, PartialEq)]
285pub struct DragDrop {
286    /// Pointer button released to drop.
287    pub button: PointerButton,
288    /// The entity that was dropped onto the `target` entity.
289    pub dropped: Entity,
290    /// Information about the picking intersection.
291    pub hit: HitData,
292}
293
294/// Dragging state.
295#[derive(Clone, PartialEq, Debug, Reflect)]
296#[reflect(Clone, PartialEq)]
297pub struct DragEntry {
298    /// The position of the pointer at drag start.
299    pub start_pos: Vec2,
300    /// The latest position of the pointer during this drag, used to compute deltas.
301    pub latest_pos: Vec2,
302}
303
304/// Fires while a pointer is scrolling over the `target` entity.
305#[derive(Clone, PartialEq, Debug, Reflect)]
306#[reflect(Clone, PartialEq)]
307pub struct Scroll {
308    /// The mouse scroll unit.
309    pub unit: MouseScrollUnit,
310    /// The horizontal scroll value.
311    pub x: f32,
312    /// The vertical scroll value.
313    pub y: f32,
314    /// Information about the picking intersection.
315    pub hit: HitData,
316}
317
318/// An entry in the cache that drives the `pointer_events` system, storing additional data
319/// about pointer button presses.
320#[derive(Debug, Clone, Default)]
321pub struct PointerButtonState {
322    /// Stores the press location and start time for each button currently being pressed by the pointer.
323    pub pressing: HashMap<Entity, (Location, Instant, HitData)>,
324    /// Stores the starting and current locations for each entity currently being dragged by the pointer.
325    pub dragging: HashMap<Entity, DragEntry>,
326    /// Stores  the hit data for each entity currently being dragged over by the pointer.
327    pub dragging_over: HashMap<Entity, HitData>,
328}
329
330/// State for all pointers.
331#[derive(Debug, Clone, Default, Resource)]
332pub struct PointerState {
333    /// Pressing and dragging state, organized by pointer and button.
334    pub pointer_buttons: HashMap<(PointerId, PointerButton), PointerButtonState>,
335}
336
337impl PointerState {
338    /// Retrieves the current state for a specific pointer and button, if it has been created.
339    pub fn get(&self, pointer_id: PointerId, button: PointerButton) -> Option<&PointerButtonState> {
340        self.pointer_buttons.get(&(pointer_id, button))
341    }
342
343    /// Provides write access to the state of a pointer and button, creating it if it does not yet exist.
344    pub fn get_mut(
345        &mut self,
346        pointer_id: PointerId,
347        button: PointerButton,
348    ) -> &mut PointerButtonState {
349        self.pointer_buttons
350            .entry((pointer_id, button))
351            .or_default()
352    }
353
354    /// Clears all the data associated with all of the buttons on a pointer. Does not free the underlying memory.
355    pub fn clear(&mut self, pointer_id: PointerId) {
356        for button in PointerButton::iter() {
357            if let Some(state) = self.pointer_buttons.get_mut(&(pointer_id, button)) {
358                state.pressing.clear();
359                state.dragging.clear();
360                state.dragging_over.clear();
361            }
362        }
363    }
364}
365
366/// A helper system param for accessing the picking event writers.
367#[derive(SystemParam)]
368pub struct PickingEventWriters<'w> {
369    cancel_events: EventWriter<'w, Pointer<Cancel>>,
370    click_events: EventWriter<'w, Pointer<Click>>,
371    pressed_events: EventWriter<'w, Pointer<Pressed>>,
372    drag_drop_events: EventWriter<'w, Pointer<DragDrop>>,
373    drag_end_events: EventWriter<'w, Pointer<DragEnd>>,
374    drag_enter_events: EventWriter<'w, Pointer<DragEnter>>,
375    drag_events: EventWriter<'w, Pointer<Drag>>,
376    drag_leave_events: EventWriter<'w, Pointer<DragLeave>>,
377    drag_over_events: EventWriter<'w, Pointer<DragOver>>,
378    drag_start_events: EventWriter<'w, Pointer<DragStart>>,
379    scroll_events: EventWriter<'w, Pointer<Scroll>>,
380    move_events: EventWriter<'w, Pointer<Move>>,
381    out_events: EventWriter<'w, Pointer<Out>>,
382    over_events: EventWriter<'w, Pointer<Over>>,
383    released_events: EventWriter<'w, Pointer<Released>>,
384}
385
386/// Dispatches interaction events to the target entities.
387///
388/// Within a single frame, events are dispatched in the following order:
389/// + [`Out`] → [`DragLeave`].
390/// + [`DragEnter`] → [`Over`].
391/// + Any number of any of the following:
392///   + For each movement: [`DragStart`] → [`Drag`] → [`DragOver`] → [`Move`].
393///   + For each button press: [`Pressed`] or [`Click`] → [`Released`] → [`DragDrop`] → [`DragEnd`] → [`DragLeave`].
394///   + For each pointer cancellation: [`Cancel`].
395///
396/// Additionally, across multiple frames, the following are also strictly
397/// ordered by the interaction state machine:
398/// + When a pointer moves over the target:
399///   [`Over`], [`Move`], [`Out`].
400/// + When a pointer presses buttons on the target:
401///   [`Pressed`], [`Click`], [`Released`].
402/// + When a pointer drags the target:
403///   [`DragStart`], [`Drag`], [`DragEnd`].
404/// + When a pointer drags something over the target:
405///   [`DragEnter`], [`DragOver`], [`DragDrop`], [`DragLeave`].
406/// + When a pointer is canceled:
407///   No other events will follow the [`Cancel`] event for that pointer.
408///
409/// Two events -- [`Over`] and [`Out`] -- are driven only by the [`HoverMap`].
410/// The rest rely on additional data from the [`PointerInput`] event stream. To
411/// receive these events for a custom pointer, you must add [`PointerInput`]
412/// events.
413///
414/// When the pointer goes from hovering entity A to entity B, entity A will
415/// receive [`Out`] and then entity B will receive [`Over`]. No entity will ever
416/// receive both an [`Over`] and and a [`Out`] event during the same frame.
417///
418/// When we account for event bubbling, this is no longer true. When the hovering focus shifts
419/// between children, parent entities may receive redundant [`Out`] → [`Over`] pairs.
420/// In the context of UI, this is especially problematic. Additional hierarchy-aware
421/// events will be added in a future release.
422///
423/// Both [`Click`] and [`Released`] target the entity hovered in the *previous frame*,
424/// rather than the current frame. This is because touch pointers hover nothing
425/// on the frame they are released. The end effect is that these two events can
426/// be received sequentially after an [`Out`] event (but always on the same frame
427/// as the [`Out`] event).
428///
429/// Note: Though it is common for the [`PointerInput`] stream may contain
430/// multiple pointer movements and presses each frame, the hover state is
431/// determined only by the pointer's *final position*. Since the hover state
432/// ultimately determines which entities receive events, this may mean that an
433/// entity can receive events from before or after it was actually hovered.
434pub fn pointer_events(
435    // Input
436    mut input_events: EventReader<PointerInput>,
437    // ECS State
438    pointers: Query<&PointerLocation>,
439    pointer_map: Res<PointerMap>,
440    hover_map: Res<HoverMap>,
441    previous_hover_map: Res<PreviousHoverMap>,
442    mut pointer_state: ResMut<PointerState>,
443    // Output
444    mut commands: Commands,
445    mut event_writers: PickingEventWriters,
446) {
447    // Setup utilities
448    let now = Instant::now();
449    let pointer_location = |pointer_id: PointerId| {
450        pointer_map
451            .get_entity(pointer_id)
452            .and_then(|entity| pointers.get(entity).ok())
453            .and_then(|pointer| pointer.location.clone())
454    };
455
456    // If the entity was hovered by a specific pointer last frame...
457    for (pointer_id, hovered_entity, hit) in previous_hover_map
458        .iter()
459        .flat_map(|(id, hashmap)| hashmap.iter().map(|data| (*id, *data.0, data.1.clone())))
460    {
461        // ...but is now not being hovered by that same pointer...
462        if !hover_map
463            .get(&pointer_id)
464            .iter()
465            .any(|e| e.contains_key(&hovered_entity))
466        {
467            let Some(location) = pointer_location(pointer_id) else {
468                debug!(
469                    "Unable to get location for pointer {:?} during pointer out",
470                    pointer_id
471                );
472                continue;
473            };
474
475            // Always send Out events
476            let out_event = Pointer::new(
477                pointer_id,
478                location.clone(),
479                hovered_entity,
480                Out { hit: hit.clone() },
481            );
482            commands.trigger_targets(out_event.clone(), hovered_entity);
483            event_writers.out_events.write(out_event);
484
485            // Possibly send DragLeave events
486            for button in PointerButton::iter() {
487                let state = pointer_state.get_mut(pointer_id, button);
488                state.dragging_over.remove(&hovered_entity);
489                for drag_target in state.dragging.keys() {
490                    let drag_leave_event = Pointer::new(
491                        pointer_id,
492                        location.clone(),
493                        hovered_entity,
494                        DragLeave {
495                            button,
496                            dragged: *drag_target,
497                            hit: hit.clone(),
498                        },
499                    );
500                    commands.trigger_targets(drag_leave_event.clone(), hovered_entity);
501                    event_writers.drag_leave_events.write(drag_leave_event);
502                }
503            }
504        }
505    }
506
507    // If the entity is hovered...
508    for (pointer_id, hovered_entity, hit) in hover_map
509        .iter()
510        .flat_map(|(id, hashmap)| hashmap.iter().map(|data| (*id, *data.0, data.1.clone())))
511    {
512        // ...but was not hovered last frame...
513        if !previous_hover_map
514            .get(&pointer_id)
515            .iter()
516            .any(|e| e.contains_key(&hovered_entity))
517        {
518            let Some(location) = pointer_location(pointer_id) else {
519                debug!(
520                    "Unable to get location for pointer {:?} during pointer over",
521                    pointer_id
522                );
523                continue;
524            };
525
526            // Possibly send DragEnter events
527            for button in PointerButton::iter() {
528                let state = pointer_state.get_mut(pointer_id, button);
529
530                for drag_target in state
531                    .dragging
532                    .keys()
533                    .filter(|&&drag_target| hovered_entity != drag_target)
534                {
535                    state.dragging_over.insert(hovered_entity, hit.clone());
536                    let drag_enter_event = Pointer::new(
537                        pointer_id,
538                        location.clone(),
539                        hovered_entity,
540                        DragEnter {
541                            button,
542                            dragged: *drag_target,
543                            hit: hit.clone(),
544                        },
545                    );
546                    commands.trigger_targets(drag_enter_event.clone(), hovered_entity);
547                    event_writers.drag_enter_events.write(drag_enter_event);
548                }
549            }
550
551            // Always send Over events
552            let over_event = Pointer::new(
553                pointer_id,
554                location.clone(),
555                hovered_entity,
556                Over { hit: hit.clone() },
557            );
558            commands.trigger_targets(over_event.clone(), hovered_entity);
559            event_writers.over_events.write(over_event);
560        }
561    }
562
563    // Dispatch input events...
564    for PointerInput {
565        pointer_id,
566        location,
567        action,
568    } in input_events.read().cloned()
569    {
570        match action {
571            PointerAction::Press(button) => {
572                let state = pointer_state.get_mut(pointer_id, button);
573
574                // If it's a press, emit a Pressed event and mark the hovered entities as pressed
575                for (hovered_entity, hit) in hover_map
576                    .get(&pointer_id)
577                    .iter()
578                    .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
579                {
580                    let pressed_event = Pointer::new(
581                        pointer_id,
582                        location.clone(),
583                        hovered_entity,
584                        Pressed {
585                            button,
586                            hit: hit.clone(),
587                        },
588                    );
589                    commands.trigger_targets(pressed_event.clone(), hovered_entity);
590                    event_writers.pressed_events.write(pressed_event);
591                    // Also insert the press into the state
592                    state
593                        .pressing
594                        .insert(hovered_entity, (location.clone(), now, hit));
595                }
596            }
597            PointerAction::Release(button) => {
598                let state = pointer_state.get_mut(pointer_id, button);
599
600                // Emit Click and Up events on all the previously hovered entities.
601                for (hovered_entity, hit) in previous_hover_map
602                    .get(&pointer_id)
603                    .iter()
604                    .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
605                {
606                    // If this pointer previously pressed the hovered entity, emit a Click event
607                    if let Some((_, press_instant, _)) = state.pressing.get(&hovered_entity) {
608                        let click_event = Pointer::new(
609                            pointer_id,
610                            location.clone(),
611                            hovered_entity,
612                            Click {
613                                button,
614                                hit: hit.clone(),
615                                duration: now - *press_instant,
616                            },
617                        );
618                        commands.trigger_targets(click_event.clone(), hovered_entity);
619                        event_writers.click_events.write(click_event);
620                    }
621                    // Always send the Released event
622                    let released_event = Pointer::new(
623                        pointer_id,
624                        location.clone(),
625                        hovered_entity,
626                        Released {
627                            button,
628                            hit: hit.clone(),
629                        },
630                    );
631                    commands.trigger_targets(released_event.clone(), hovered_entity);
632                    event_writers.released_events.write(released_event);
633                }
634
635                // Then emit the drop events.
636                for (drag_target, drag) in state.dragging.drain() {
637                    // Emit DragDrop
638                    for (dragged_over, hit) in state.dragging_over.iter() {
639                        let drag_drop_event = Pointer::new(
640                            pointer_id,
641                            location.clone(),
642                            *dragged_over,
643                            DragDrop {
644                                button,
645                                dropped: drag_target,
646                                hit: hit.clone(),
647                            },
648                        );
649                        commands.trigger_targets(drag_drop_event.clone(), *dragged_over);
650                        event_writers.drag_drop_events.write(drag_drop_event);
651                    }
652                    // Emit DragEnd
653                    let drag_end_event = Pointer::new(
654                        pointer_id,
655                        location.clone(),
656                        drag_target,
657                        DragEnd {
658                            button,
659                            distance: drag.latest_pos - drag.start_pos,
660                        },
661                    );
662                    commands.trigger_targets(drag_end_event.clone(), drag_target);
663                    event_writers.drag_end_events.write(drag_end_event);
664                    // Emit DragLeave
665                    for (dragged_over, hit) in state.dragging_over.iter() {
666                        let drag_leave_event = Pointer::new(
667                            pointer_id,
668                            location.clone(),
669                            *dragged_over,
670                            DragLeave {
671                                button,
672                                dragged: drag_target,
673                                hit: hit.clone(),
674                            },
675                        );
676                        commands.trigger_targets(drag_leave_event.clone(), *dragged_over);
677                        event_writers.drag_leave_events.write(drag_leave_event);
678                    }
679                }
680
681                // Finally, we can clear the state of everything relating to presses or drags.
682                state.pressing.clear();
683                state.dragging.clear();
684                state.dragging_over.clear();
685            }
686            // Moved
687            PointerAction::Move { delta } => {
688                if delta == Vec2::ZERO {
689                    continue; // If delta is zero, the following events will not be triggered.
690                }
691                // Triggers during movement even if not over an entity
692                for button in PointerButton::iter() {
693                    let state = pointer_state.get_mut(pointer_id, button);
694
695                    // Emit DragEntry and DragStart the first time we move while pressing an entity
696                    for (press_target, (location, _, hit)) in state.pressing.iter() {
697                        if state.dragging.contains_key(press_target) {
698                            continue; // This entity is already logged as being dragged
699                        }
700                        state.dragging.insert(
701                            *press_target,
702                            DragEntry {
703                                start_pos: location.position,
704                                latest_pos: location.position,
705                            },
706                        );
707                        let drag_start_event = Pointer::new(
708                            pointer_id,
709                            location.clone(),
710                            *press_target,
711                            DragStart {
712                                button,
713                                hit: hit.clone(),
714                            },
715                        );
716                        commands.trigger_targets(drag_start_event.clone(), *press_target);
717                        event_writers.drag_start_events.write(drag_start_event);
718                    }
719
720                    // Emit Drag events to the entities we are dragging
721                    for (drag_target, drag) in state.dragging.iter_mut() {
722                        let delta = location.position - drag.latest_pos;
723                        if delta == Vec2::ZERO {
724                            continue; // No need to emit a Drag event if there is no movement
725                        }
726                        let drag_event = Pointer::new(
727                            pointer_id,
728                            location.clone(),
729                            *drag_target,
730                            Drag {
731                                button,
732                                distance: location.position - drag.start_pos,
733                                delta,
734                            },
735                        );
736                        commands.trigger_targets(drag_event.clone(), *drag_target);
737                        event_writers.drag_events.write(drag_event);
738
739                        // Update drag position
740                        drag.latest_pos = location.position;
741
742                        // Emit corresponding DragOver to the hovered entities
743                        for (hovered_entity, hit) in hover_map
744                            .get(&pointer_id)
745                            .iter()
746                            .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
747                            .filter(|(hovered_entity, _)| *hovered_entity != *drag_target)
748                        {
749                            let drag_over_event = Pointer::new(
750                                pointer_id,
751                                location.clone(),
752                                hovered_entity,
753                                DragOver {
754                                    button,
755                                    dragged: *drag_target,
756                                    hit: hit.clone(),
757                                },
758                            );
759                            commands.trigger_targets(drag_over_event.clone(), hovered_entity);
760                            event_writers.drag_over_events.write(drag_over_event);
761                        }
762                    }
763                }
764
765                for (hovered_entity, hit) in hover_map
766                    .get(&pointer_id)
767                    .iter()
768                    .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
769                {
770                    // Emit Move events to the entities we are hovering
771                    let move_event = Pointer::new(
772                        pointer_id,
773                        location.clone(),
774                        hovered_entity,
775                        Move {
776                            hit: hit.clone(),
777                            delta,
778                        },
779                    );
780                    commands.trigger_targets(move_event.clone(), hovered_entity);
781                    event_writers.move_events.write(move_event);
782                }
783            }
784            PointerAction::Scroll { x, y, unit } => {
785                for (hovered_entity, hit) in hover_map
786                    .get(&pointer_id)
787                    .iter()
788                    .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
789                {
790                    // Emit Scroll events to the entities we are hovering
791                    let scroll_event = Pointer::new(
792                        pointer_id,
793                        location.clone(),
794                        hovered_entity,
795                        Scroll {
796                            unit,
797                            x,
798                            y,
799                            hit: hit.clone(),
800                        },
801                    );
802                    commands.trigger_targets(scroll_event.clone(), hovered_entity);
803                    event_writers.scroll_events.write(scroll_event);
804                }
805            }
806            // Canceled
807            PointerAction::Cancel => {
808                // Emit a Cancel to the hovered entity.
809                for (hovered_entity, hit) in hover_map
810                    .get(&pointer_id)
811                    .iter()
812                    .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
813                {
814                    let cancel_event =
815                        Pointer::new(pointer_id, location.clone(), hovered_entity, Cancel { hit });
816                    commands.trigger_targets(cancel_event.clone(), hovered_entity);
817                    event_writers.cancel_events.write(cancel_event);
818                }
819                // Clear the state for the canceled pointer
820                pointer_state.clear(pointer_id);
821            }
822        }
823    }
824}