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