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