Flattened PointerAction::Pressed into Press and Release. (#17424)

Fixes #17397.
Also renamed all variants into present-tense.
## Migration Guide
- `PointerAction::Pressed` has been seperated into two variants,
`PointerAction::Press` and `PointerAction::Release`.
- `PointerAction::Moved` has been renamed to `PointerAction::Move`. 
- `PointerAction::Canceled` has been renamed to `PointerAction::Cancel`.
This commit is contained in:
AlephCubed 2025-01-19 14:51:57 -08:00 committed by GitHub
parent e66aef2d7a
commit 5d0e9cfb36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 156 additions and 165 deletions

View File

@ -50,9 +50,7 @@ use tracing::debug;
use crate::{
backend::{prelude::PointerLocation, HitData},
hover::{HoverMap, PreviousHoverMap},
pointer::{
Location, PointerAction, PointerButton, PointerId, PointerInput, PointerMap, PressDirection,
},
pointer::{Location, PointerAction, PointerButton, PointerId, PointerInput, PointerMap},
};
/// Stores the common data needed for all pointer events.
@ -538,128 +536,123 @@ pub fn pointer_events(
} in input_events.read().cloned()
{
match action {
// Pressed Button
PointerAction::Pressed { direction, button } => {
PointerAction::Press(button) => {
let state = pointer_state.get_mut(pointer_id, button);
// The sequence of events emitted depends on if this is a press or a release
match direction {
PressDirection::Pressed => {
// If it's a press, emit a Pressed event and mark the hovered entities as pressed
for (hovered_entity, hit) in hover_map
.get(&pointer_id)
.iter()
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
{
let pressed_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Pressed {
button,
hit: hit.clone(),
},
);
commands.trigger_targets(pressed_event.clone(), hovered_entity);
event_writers.pressed_events.send(pressed_event);
// Also insert the press into the state
state
.pressing
.insert(hovered_entity, (location.clone(), now, hit));
}
}
PressDirection::Released => {
// Emit Click and Up events on all the previously hovered entities.
for (hovered_entity, hit) in previous_hover_map
.get(&pointer_id)
.iter()
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
{
// If this pointer previously pressed the hovered entity, emit a Click event
if let Some((_, press_instant, _)) = state.pressing.get(&hovered_entity)
{
let click_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Click {
button,
hit: hit.clone(),
duration: now - *press_instant,
},
);
commands.trigger_targets(click_event.clone(), hovered_entity);
event_writers.click_events.send(click_event);
}
// Always send the Released event
let released_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Released {
button,
hit: hit.clone(),
},
);
commands.trigger_targets(released_event.clone(), hovered_entity);
event_writers.released_events.send(released_event);
}
// Then emit the drop events.
for (drag_target, drag) in state.dragging.drain() {
// Emit DragDrop
for (dragged_over, hit) in state.dragging_over.iter() {
let drag_drop_event = Pointer::new(
pointer_id,
location.clone(),
*dragged_over,
DragDrop {
button,
dropped: drag_target,
hit: hit.clone(),
},
);
commands.trigger_targets(drag_drop_event.clone(), *dragged_over);
event_writers.drag_drop_events.send(drag_drop_event);
}
// Emit DragEnd
let drag_end_event = Pointer::new(
pointer_id,
location.clone(),
drag_target,
DragEnd {
button,
distance: drag.latest_pos - drag.start_pos,
},
);
commands.trigger_targets(drag_end_event.clone(), drag_target);
event_writers.drag_end_events.send(drag_end_event);
// Emit DragLeave
for (dragged_over, hit) in state.dragging_over.iter() {
let drag_leave_event = Pointer::new(
pointer_id,
location.clone(),
*dragged_over,
DragLeave {
button,
dragged: drag_target,
hit: hit.clone(),
},
);
commands.trigger_targets(drag_leave_event.clone(), *dragged_over);
event_writers.drag_leave_events.send(drag_leave_event);
}
}
// Finally, we can clear the state of everything relating to presses or drags.
state.pressing.clear();
state.dragging.clear();
state.dragging_over.clear();
}
// If it's a press, emit a Pressed event and mark the hovered entities as pressed
for (hovered_entity, hit) in hover_map
.get(&pointer_id)
.iter()
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
{
let pressed_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Pressed {
button,
hit: hit.clone(),
},
);
commands.trigger_targets(pressed_event.clone(), hovered_entity);
event_writers.pressed_events.send(pressed_event);
// Also insert the press into the state
state
.pressing
.insert(hovered_entity, (location.clone(), now, hit));
}
}
PointerAction::Release(button) => {
let state = pointer_state.get_mut(pointer_id, button);
// Emit Click and Up events on all the previously hovered entities.
for (hovered_entity, hit) in previous_hover_map
.get(&pointer_id)
.iter()
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
{
// If this pointer previously pressed the hovered entity, emit a Click event
if let Some((_, press_instant, _)) = state.pressing.get(&hovered_entity) {
let click_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Click {
button,
hit: hit.clone(),
duration: now - *press_instant,
},
);
commands.trigger_targets(click_event.clone(), hovered_entity);
event_writers.click_events.send(click_event);
}
// Always send the Released event
let released_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Released {
button,
hit: hit.clone(),
},
);
commands.trigger_targets(released_event.clone(), hovered_entity);
event_writers.released_events.send(released_event);
}
// Then emit the drop events.
for (drag_target, drag) in state.dragging.drain() {
// Emit DragDrop
for (dragged_over, hit) in state.dragging_over.iter() {
let drag_drop_event = Pointer::new(
pointer_id,
location.clone(),
*dragged_over,
DragDrop {
button,
dropped: drag_target,
hit: hit.clone(),
},
);
commands.trigger_targets(drag_drop_event.clone(), *dragged_over);
event_writers.drag_drop_events.send(drag_drop_event);
}
// Emit DragEnd
let drag_end_event = Pointer::new(
pointer_id,
location.clone(),
drag_target,
DragEnd {
button,
distance: drag.latest_pos - drag.start_pos,
},
);
commands.trigger_targets(drag_end_event.clone(), drag_target);
event_writers.drag_end_events.send(drag_end_event);
// Emit DragLeave
for (dragged_over, hit) in state.dragging_over.iter() {
let drag_leave_event = Pointer::new(
pointer_id,
location.clone(),
*dragged_over,
DragLeave {
button,
dragged: drag_target,
hit: hit.clone(),
},
);
commands.trigger_targets(drag_leave_event.clone(), *dragged_over);
event_writers.drag_leave_events.send(drag_leave_event);
}
}
// Finally, we can clear the state of everything relating to presses or drags.
state.pressing.clear();
state.dragging.clear();
state.dragging_over.clear();
}
// Moved
PointerAction::Moved { delta } => {
PointerAction::Move { delta } => {
if delta == Vec2::ZERO {
continue; // If delta is zero, the following events will not be triggered.
}
@ -757,7 +750,7 @@ pub fn pointer_events(
}
}
// Canceled
PointerAction::Canceled => {
PointerAction::Cancel => {
// Emit a Cancel to the hovered entity.
for (hovered_entity, hit) in hover_map
.get(&pointer_id)

View File

@ -118,7 +118,7 @@ fn build_over_map(
let cancelled_pointers: HashSet<PointerId> = pointer_input
.read()
.filter_map(|p| {
if let PointerAction::Canceled = p.action {
if let PointerAction::Cancel = p.action {
Some(p.pointer_id)
} else {
None

View File

@ -27,7 +27,6 @@ use tracing::debug;
use crate::pointer::{
Location, PointerAction, PointerButton, PointerId, PointerInput, PointerLocation,
PressDirection,
};
use crate::PickSet;
@ -128,7 +127,7 @@ pub fn mouse_pick_events(
pointer_events.send(PointerInput::new(
PointerId::Mouse,
location,
PointerAction::Moved {
PointerAction::Move {
delta: event.position - *cursor_last,
},
));
@ -151,15 +150,11 @@ pub fn mouse_pick_events(
MouseButton::Middle => PointerButton::Middle,
MouseButton::Other(_) | MouseButton::Back | MouseButton::Forward => continue,
};
let direction = match input.state {
ButtonState::Pressed => PressDirection::Pressed,
ButtonState::Released => PressDirection::Released,
let action = match input.state {
ButtonState::Pressed => PointerAction::Press(button),
ButtonState::Released => PointerAction::Release(button),
};
pointer_events.send(PointerInput::new(
PointerId::Mouse,
location,
PointerAction::Pressed { direction, button },
));
pointer_events.send(PointerInput::new(PointerId::Mouse, location, action));
}
_ => {}
}
@ -197,10 +192,7 @@ pub fn touch_pick_events(
pointer_events.send(PointerInput::new(
pointer,
location,
PointerAction::Pressed {
direction: PressDirection::Pressed,
button: PointerButton::Primary,
},
PointerAction::Press(PointerButton::Primary),
));
touch_cache.insert(touch.id, *touch);
@ -214,7 +206,7 @@ pub fn touch_pick_events(
pointer_events.send(PointerInput::new(
pointer,
location,
PointerAction::Moved {
PointerAction::Move {
delta: touch.position - last_touch.position,
},
));
@ -225,10 +217,7 @@ pub fn touch_pick_events(
pointer_events.send(PointerInput::new(
pointer,
location,
PointerAction::Pressed {
direction: PressDirection::Released,
button: PointerButton::Primary,
},
PointerAction::Release(PointerButton::Primary),
));
touch_cache.remove(&touch.id);
}
@ -236,7 +225,7 @@ pub fn touch_pick_events(
pointer_events.send(PointerInput::new(
pointer,
location,
PointerAction::Canceled,
PointerAction::Cancel,
));
touch_cache.remove(&touch.id);
}

View File

@ -239,23 +239,20 @@ impl Location {
}
}
/// Types of actions that can be taken by pointers.
/// Event sent to drive a pointer.
#[derive(Debug, Clone, Copy, Reflect)]
pub enum PointerAction {
/// A button has been pressed on the pointer.
Pressed {
/// The press state, either pressed or released.
direction: PressDirection,
/// The button that was pressed.
button: PointerButton,
},
/// The pointer has moved.
Moved {
/// Causes the pointer to press a button.
Press(PointerButton),
/// Causes the pointer to release a button.
Release(PointerButton),
/// Move the pointer.
Move {
/// How much the pointer moved from the previous position.
delta: Vec2,
},
/// The pointer has been canceled. The OS can cause this to happen to touch events.
Canceled,
/// Cancel the pointer. Often used for touch events.
Cancel,
}
/// An input event effecting a pointer.
@ -263,7 +260,7 @@ pub enum PointerAction {
pub struct PointerInput {
/// The id of the pointer.
pub pointer_id: PointerId,
/// The location of the pointer. For [[`PointerAction::Moved`]], this is the location after the movement.
/// The location of the pointer. For [`PointerAction::Move`], this is the location after the movement.
pub location: Location,
/// The action that the event describes.
pub action: PointerAction,
@ -284,8 +281,8 @@ impl PointerInput {
/// Returns true if the `target_button` of this pointer was just pressed.
#[inline]
pub fn button_just_pressed(&self, target_button: PointerButton) -> bool {
if let PointerAction::Pressed { direction, button } = self.action {
direction == PressDirection::Pressed && button == target_button
if let PointerAction::Press(button) = self.action {
button == target_button
} else {
false
}
@ -294,8 +291,8 @@ impl PointerInput {
/// Returns true if the `target_button` of this pointer was just released.
#[inline]
pub fn button_just_released(&self, target_button: PointerButton) -> bool {
if let PointerAction::Pressed { direction, button } = self.action {
direction == PressDirection::Released && button == target_button
if let PointerAction::Release(button) = self.action {
button == target_button
} else {
false
}
@ -308,21 +305,33 @@ impl PointerInput {
) {
for event in events.read() {
match event.action {
PointerAction::Pressed { direction, button } => {
PointerAction::Press(button) => {
pointers
.iter_mut()
.for_each(|(pointer_id, _, mut pointer)| {
if *pointer_id == event.pointer_id {
let is_pressed = direction == PressDirection::Pressed;
match button {
PointerButton::Primary => pointer.primary = is_pressed,
PointerButton::Secondary => pointer.secondary = is_pressed,
PointerButton::Middle => pointer.middle = is_pressed,
PointerButton::Primary => pointer.primary = true,
PointerButton::Secondary => pointer.secondary = true,
PointerButton::Middle => pointer.middle = true,
}
}
});
}
PointerAction::Moved { .. } => {
PointerAction::Release(button) => {
pointers
.iter_mut()
.for_each(|(pointer_id, _, mut pointer)| {
if *pointer_id == event.pointer_id {
match button {
PointerButton::Primary => pointer.primary = false,
PointerButton::Secondary => pointer.secondary = false,
PointerButton::Middle => pointer.middle = false,
}
}
});
}
PointerAction::Move { .. } => {
pointers.iter_mut().for_each(|(id, mut pointer, _)| {
if *id == event.pointer_id {
pointer.location = Some(event.location.to_owned());