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.
This commit is contained in:
parent
7740c0f879
commit
50dde9b0a7
@ -254,7 +254,7 @@ pub struct DragEntry {
|
|||||||
/// An entry in the cache that drives the `pointer_events` system, storing additional data
|
/// An entry in the cache that drives the `pointer_events` system, storing additional data
|
||||||
/// about pointer button presses.
|
/// about pointer button presses.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct PointerState {
|
pub struct PointerButtonState {
|
||||||
/// Stores the press location and start time for each button currently being pressed by the pointer.
|
/// Stores the press location and start time for each button currently being pressed by the pointer.
|
||||||
pub pressing: HashMap<Entity, (Location, Instant, HitData)>,
|
pub pressing: HashMap<Entity, (Location, Instant, HitData)>,
|
||||||
/// Stores the starting and current locations for each entity currently being dragged by the pointer.
|
/// Stores the starting and current locations for each entity currently being dragged by the pointer.
|
||||||
@ -263,6 +263,42 @@ pub struct PointerState {
|
|||||||
pub dragging_over: HashMap<Entity, HitData>,
|
pub dragging_over: HashMap<Entity, HitData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State for all pointers.
|
||||||
|
#[derive(Debug, Clone, Default, Resource)]
|
||||||
|
pub struct PointerState {
|
||||||
|
/// Pressing and dragging state, organized by pointer and button.
|
||||||
|
pub pointer_buttons: HashMap<(PointerId, PointerButton), PointerButtonState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerState {
|
||||||
|
/// Retrieves the current state for a specific pointer and button, if it has been created.
|
||||||
|
pub fn get(&self, pointer_id: PointerId, button: PointerButton) -> Option<&PointerButtonState> {
|
||||||
|
self.pointer_buttons.get(&(pointer_id, button))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides write access to the state of a pointer and button, creating it if it does not yet exist.
|
||||||
|
pub fn get_mut(
|
||||||
|
&mut self,
|
||||||
|
pointer_id: PointerId,
|
||||||
|
button: PointerButton,
|
||||||
|
) -> &mut PointerButtonState {
|
||||||
|
self.pointer_buttons
|
||||||
|
.entry((pointer_id, button))
|
||||||
|
.or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears all the data assoceated with all of the buttons on a pointer. Does not free the underlying memory.
|
||||||
|
pub fn clear(&mut self, pointer_id: PointerId) {
|
||||||
|
for button in PointerButton::iter() {
|
||||||
|
if let Some(state) = self.pointer_buttons.get_mut(&(pointer_id, button)) {
|
||||||
|
state.pressing.clear();
|
||||||
|
state.dragging.clear();
|
||||||
|
state.dragging_over.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A helper system param for accessing the picking event writers.
|
/// A helper system param for accessing the picking event writers.
|
||||||
#[derive(SystemParam)]
|
#[derive(SystemParam)]
|
||||||
pub struct PickingEventWriters<'w> {
|
pub struct PickingEventWriters<'w> {
|
||||||
@ -316,8 +352,7 @@ pub fn pointer_events(
|
|||||||
pointer_map: Res<PointerMap>,
|
pointer_map: Res<PointerMap>,
|
||||||
hover_map: Res<HoverMap>,
|
hover_map: Res<HoverMap>,
|
||||||
previous_hover_map: Res<PreviousHoverMap>,
|
previous_hover_map: Res<PreviousHoverMap>,
|
||||||
// Local state
|
mut pointer_state: ResMut<PointerState>,
|
||||||
mut pointer_state: Local<HashMap<(PointerId, PointerButton), PointerState>>,
|
|
||||||
// Output
|
// Output
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut event_writers: PickingEventWriters,
|
mut event_writers: PickingEventWriters,
|
||||||
@ -352,7 +387,7 @@ pub fn pointer_events(
|
|||||||
|
|
||||||
// Possibly send DragEnter events
|
// Possibly send DragEnter events
|
||||||
for button in PointerButton::iter() {
|
for button in PointerButton::iter() {
|
||||||
let state = pointer_state.entry((pointer_id, button)).or_default();
|
let state = pointer_state.get_mut(pointer_id, button);
|
||||||
|
|
||||||
for drag_target in state
|
for drag_target in state
|
||||||
.dragging
|
.dragging
|
||||||
@ -397,7 +432,7 @@ pub fn pointer_events(
|
|||||||
match action {
|
match action {
|
||||||
// Pressed Button
|
// Pressed Button
|
||||||
PointerAction::Pressed { direction, button } => {
|
PointerAction::Pressed { direction, button } => {
|
||||||
let state = pointer_state.entry((pointer_id, button)).or_default();
|
let state = pointer_state.get_mut(pointer_id, button);
|
||||||
|
|
||||||
// The sequence of events emitted depends on if this is a press or a release
|
// The sequence of events emitted depends on if this is a press or a release
|
||||||
match direction {
|
match direction {
|
||||||
@ -519,7 +554,7 @@ pub fn pointer_events(
|
|||||||
PointerAction::Moved { delta } => {
|
PointerAction::Moved { delta } => {
|
||||||
// Triggers during movement even if not over an entity
|
// Triggers during movement even if not over an entity
|
||||||
for button in PointerButton::iter() {
|
for button in PointerButton::iter() {
|
||||||
let state = pointer_state.entry((pointer_id, button)).or_default();
|
let state = pointer_state.get_mut(pointer_id, button);
|
||||||
|
|
||||||
// Emit DragEntry and DragStart the first time we move while pressing an entity
|
// Emit DragEntry and DragStart the first time we move while pressing an entity
|
||||||
for (press_target, (location, _, hit)) in state.pressing.iter() {
|
for (press_target, (location, _, hit)) in state.pressing.iter() {
|
||||||
@ -619,14 +654,8 @@ pub fn pointer_events(
|
|||||||
commands.trigger_targets(cancel_event.clone(), hovered_entity);
|
commands.trigger_targets(cancel_event.clone(), hovered_entity);
|
||||||
event_writers.cancel_events.send(cancel_event);
|
event_writers.cancel_events.send(cancel_event);
|
||||||
}
|
}
|
||||||
// Clear the local state for the canceled pointer
|
// Clear the state for the canceled pointer
|
||||||
for button in PointerButton::iter() {
|
pointer_state.clear(pointer_id);
|
||||||
if let Some(state) = pointer_state.get_mut(&(pointer_id, button)) {
|
|
||||||
state.pressing.clear();
|
|
||||||
state.dragging.clear();
|
|
||||||
state.dragging_over.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,7 +691,7 @@ pub fn pointer_events(
|
|||||||
|
|
||||||
// Possibly send DragLeave events
|
// Possibly send DragLeave events
|
||||||
for button in PointerButton::iter() {
|
for button in PointerButton::iter() {
|
||||||
let state = pointer_state.entry((pointer_id, button)).or_default();
|
let state = pointer_state.get_mut(pointer_id, button);
|
||||||
state.dragging_over.remove(&hovered_entity);
|
state.dragging_over.remove(&hovered_entity);
|
||||||
for drag_target in state.dragging.keys() {
|
for drag_target in state.dragging.keys() {
|
||||||
let drag_leave_event = Pointer::new(
|
let drag_leave_event = Pointer::new(
|
||||||
|
@ -381,6 +381,7 @@ impl Plugin for InteractionPlugin {
|
|||||||
|
|
||||||
app.init_resource::<focus::HoverMap>()
|
app.init_resource::<focus::HoverMap>()
|
||||||
.init_resource::<focus::PreviousHoverMap>()
|
.init_resource::<focus::PreviousHoverMap>()
|
||||||
|
.init_resource::<PointerState>()
|
||||||
.add_event::<Pointer<Cancel>>()
|
.add_event::<Pointer<Cancel>>()
|
||||||
.add_event::<Pointer<Click>>()
|
.add_event::<Pointer<Click>>()
|
||||||
.add_event::<Pointer<Down>>()
|
.add_event::<Pointer<Down>>()
|
||||||
|
Loading…
Reference in New Issue
Block a user