Skip to content

Commit b182452

Browse files
NthTensormockersf
authored andcommitted
Expose picking pointer state as a resource (#16229)
In `bevy_mod_picking` events are driven by several interlocking state machines, which read and write events, and share state in a few common resources. When I merged theses state machines into one to make event ordering work properly, I combined this state and hid it in a `Local`. This PR exposes the state in a resource again. Also adds a simple little API for it. Useful for adding debug UI.
1 parent f32eed6 commit b182452

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

crates/bevy_picking/src/events.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ pub struct DragEntry {
254254
/// An entry in the cache that drives the `pointer_events` system, storing additional data
255255
/// about pointer button presses.
256256
#[derive(Debug, Clone, Default)]
257-
pub struct PointerState {
257+
pub struct PointerButtonState {
258258
/// Stores the press location and start time for each button currently being pressed by the pointer.
259259
pub pressing: HashMap<Entity, (Location, Instant, HitData)>,
260260
/// Stores the starting and current locations for each entity currently being dragged by the pointer.
@@ -263,6 +263,42 @@ pub struct PointerState {
263263
pub dragging_over: HashMap<Entity, HitData>,
264264
}
265265

266+
/// State for all pointers.
267+
#[derive(Debug, Clone, Default, Resource)]
268+
pub struct PointerState {
269+
/// Pressing and dragging state, organized by pointer and button.
270+
pub pointer_buttons: HashMap<(PointerId, PointerButton), PointerButtonState>,
271+
}
272+
273+
impl 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+
266302
/// A helper system param for accessing the picking event writers.
267303
#[derive(SystemParam)]
268304
pub struct PickingEventWriters<'w> {
@@ -316,8 +352,7 @@ pub fn pointer_events(
316352
pointer_map: Res<PointerMap>,
317353
hover_map: Res<HoverMap>,
318354
previous_hover_map: Res<PreviousHoverMap>,
319-
// Local state
320-
mut pointer_state: Local<HashMap<(PointerId, PointerButton), PointerState>>,
355+
mut pointer_state: ResMut<PointerState>,
321356
// Output
322357
mut commands: Commands,
323358
mut event_writers: PickingEventWriters,
@@ -352,7 +387,7 @@ pub fn pointer_events(
352387

353388
// Possibly send DragEnter events
354389
for button in PointerButton::iter() {
355-
let state = pointer_state.entry((pointer_id, button)).or_default();
390+
let state = pointer_state.get_mut(pointer_id, button);
356391

357392
for drag_target in state
358393
.dragging
@@ -397,7 +432,7 @@ pub fn pointer_events(
397432
match action {
398433
// Pressed Button
399434
PointerAction::Pressed { direction, button } => {
400-
let state = pointer_state.entry((pointer_id, button)).or_default();
435+
let state = pointer_state.get_mut(pointer_id, button);
401436

402437
// The sequence of events emitted depends on if this is a press or a release
403438
match direction {
@@ -519,7 +554,7 @@ pub fn pointer_events(
519554
PointerAction::Moved { delta } => {
520555
// Triggers during movement even if not over an entity
521556
for button in PointerButton::iter() {
522-
let state = pointer_state.entry((pointer_id, button)).or_default();
557+
let state = pointer_state.get_mut(pointer_id, button);
523558

524559
// Emit DragEntry and DragStart the first time we move while pressing an entity
525560
for (press_target, (location, _, hit)) in state.pressing.iter() {
@@ -619,14 +654,8 @@ pub fn pointer_events(
619654
commands.trigger_targets(cancel_event.clone(), hovered_entity);
620655
event_writers.cancel_events.send(cancel_event);
621656
}
622-
// Clear the local state for the canceled pointer
623-
for button in PointerButton::iter() {
624-
if let Some(state) = pointer_state.get_mut(&(pointer_id, button)) {
625-
state.pressing.clear();
626-
state.dragging.clear();
627-
state.dragging_over.clear();
628-
}
629-
}
657+
// Clear the state for the canceled pointer
658+
pointer_state.clear(pointer_id);
630659
}
631660
}
632661
}
@@ -662,7 +691,7 @@ pub fn pointer_events(
662691

663692
// Possibly send DragLeave events
664693
for button in PointerButton::iter() {
665-
let state = pointer_state.entry((pointer_id, button)).or_default();
694+
let state = pointer_state.get_mut(pointer_id, button);
666695
state.dragging_over.remove(&hovered_entity);
667696
for drag_target in state.dragging.keys() {
668697
let drag_leave_event = Pointer::new(

crates/bevy_picking/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ impl Plugin for InteractionPlugin {
381381

382382
app.init_resource::<focus::HoverMap>()
383383
.init_resource::<focus::PreviousHoverMap>()
384+
.init_resource::<PointerState>()
384385
.add_event::<Pointer<Cancel>>()
385386
.add_event::<Pointer<Click>>()
386387
.add_event::<Pointer<Down>>()

0 commit comments

Comments
 (0)