diff --git a/_release-content/migration-guides/pointer_button_to_mouse_button.md b/_release-content/migration-guides/pointer_button_to_mouse_button.md new file mode 100644 index 0000000000000..3809cffd31bc9 --- /dev/null +++ b/_release-content/migration-guides/pointer_button_to_mouse_button.md @@ -0,0 +1,29 @@ +--- +title: PointerButton is now MouseButton. +pull_requests: [25392] +--- + +Bevy picking used `PointerButton` for reasons...? +This was limiting as it only exposed 3 buttons. +It is also seemingly redundant, and now has been replaced with `MouseButton`. + +```rust +PointerButton::Primary -> MouseButton::Left +PointerButton::Middle -> MouseButton::Middle +PointerButton::Secondary -> MouseButton::Right +``` + +Before: +```rust +MousePanSettings { + enabled: true, + button: MouseButton::Left, +} +``` +After: +```rust +MousePanSettings { + enabled: true, + button: PointerButton::Primary, +} +``` \ No newline at end of file diff --git a/crates/bevy_app/src/panic_handler.rs b/crates/bevy_app/src/panic_handler.rs index 9a0bc813dd762..3d3a628540027 100644 --- a/crates/bevy_app/src/panic_handler.rs +++ b/crates/bevy_app/src/panic_handler.rs @@ -46,7 +46,9 @@ impl Plugin for PanicHandlerPlugin { cfg_select! { all(target_arch = "wasm32", feature = "web") => { // This provides better panic handling in JS engines (displays the panic message and improves the backtrace). - std::panic::set_hook(alloc::boxed::Box::new(console_error_panic_hook::hook)); + std::panic::set_hook(alloc::boxed::Box::new( + console_error_panic_hook::hook, + )); } feature = "error_panic_hook" => { let current_hook = std::panic::take_hook(); @@ -55,7 +57,7 @@ impl Plugin for PanicHandlerPlugin { )); } // Otherwise use the default target panic hook - Do nothing. - _ => () + _ => (), } }); } diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index 8cd0d28fffaf4..038b0e2ce733c 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -157,17 +157,15 @@ impl Plugin for ScheduleRunnerPlugin { exit.take() } - _ =>{ - loop { - match tick(&mut app, wait) { - Ok(Some(delay)) => { - bevy_platform::thread::sleep(delay); - } - Ok(None) => continue, - Err(exit) => return exit, + _ => loop { + match tick(&mut app, wait) { + Ok(Some(delay)) => { + bevy_platform::thread::sleep(delay); } + Ok(None) => continue, + Err(exit) => return exit, } - } + }, } } } diff --git a/crates/bevy_app/src/task_pool_plugin.rs b/crates/bevy_app/src/task_pool_plugin.rs index fe25a43b7a013..b5102bcb294af 100644 --- a/crates/bevy_app/src/task_pool_plugin.rs +++ b/crates/bevy_app/src/task_pool_plugin.rs @@ -8,8 +8,8 @@ use log::trace; cfg_select! { not(all(target_arch = "wasm32", feature = "web")) => { - use {crate::Last, bevy_tasks::tick_global_task_pools_on_main_thread}; use bevy_ecs::system::NonSendMarker; + use {crate::Last, bevy_tasks::tick_global_task_pools_on_main_thread}; /// A system used to check and advanced our task pools. /// diff --git a/crates/bevy_camera_controller/src/pan_camera.rs b/crates/bevy_camera_controller/src/pan_camera.rs index 9f6cbd88c7395..a3ec40ab62ed8 100644 --- a/crates/bevy_camera_controller/src/pan_camera.rs +++ b/crates/bevy_camera_controller/src/pan_camera.rs @@ -10,12 +10,10 @@ use bevy_camera::{Camera, RenderTarget}; use bevy_ecs::prelude::*; use bevy_input::keyboard::KeyCode; use bevy_input::mouse::{AccumulatedMouseScroll, MouseScrollPixelsPerLine}; +use bevy_input::prelude::MouseButton; use bevy_input::ButtonInput; use bevy_math::{Vec2, Vec3}; -use bevy_picking::{ - events::{Drag, DragEnd, DragStart, Pointer}, - pointer::PointerButton, -}; +use bevy_picking::events::{Drag, DragEnd, DragStart, Pointer}; use bevy_time::{Real, Time}; use bevy_transform::components::GlobalTransform; use bevy_transform::prelude::Transform; @@ -90,7 +88,7 @@ pub struct MousePanSettings { /// Whether the mouse panning is enabled. pub enabled: bool, /// The mouse button to use for panning. - pub button: PointerButton, + pub button: MouseButton, } #[derive(Eq, PartialEq)] @@ -145,7 +143,7 @@ impl Default for PanCamera { key_rotate_cw: Some(KeyCode::KeyE), mouse_pan_settings: MousePanSettings { enabled: true, - button: PointerButton::Primary, + button: MouseButton::Left, }, } } diff --git a/crates/bevy_feathers/src/controls/number_input.rs b/crates/bevy_feathers/src/controls/number_input.rs index ca9b1baa2bd6a..295983d46bcd2 100644 --- a/crates/bevy_feathers/src/controls/number_input.rs +++ b/crates/bevy_feathers/src/controls/number_input.rs @@ -18,6 +18,7 @@ use bevy_ecs::{ }; use bevy_input::{ keyboard::{Key, KeyCode, KeyboardInput}, + mouse::MouseButton, ButtonInput, }; use bevy_input_focus::{FocusGained, FocusLost, FocusedInput, InputFocus, InputFocusSystems}; @@ -27,7 +28,6 @@ use bevy_picking::{ cursor::EntityCursor, events::{Cancel, Drag, DragEnd, DragStart, Pointer, Press, Release}, hover::Hovered, - pointer::PointerButton, PickingSystems, }; use bevy_platform::collections::HashMap; @@ -1015,7 +1015,7 @@ fn scrubber_on_release( // Copy of logic from EditableText / text_input, but done on pointer up instead of down. if drag_state.max_distance <= DRAG_THRESHOLD_DISTANCE { - if release.button != PointerButton::Primary { + if release.button != MouseButton::Left { return; } diff --git a/crates/bevy_picking/src/events.rs b/crates/bevy_picking/src/events.rs index b36400d9d74a4..448f74aec652e 100644 --- a/crates/bevy_picking/src/events.rs +++ b/crates/bevy_picking/src/events.rs @@ -50,7 +50,7 @@ use bevy_ecs::{ traversal::Traversal, }; use bevy_input::{ - mouse::{MouseScrollPixelsPerLine, MouseScrollUnit}, + mouse::{MouseButton, MouseScrollPixelsPerLine, MouseScrollUnit}, touch::TouchPhase, }; use bevy_math::Vec2; @@ -63,7 +63,7 @@ use tracing::debug; use crate::{ backend::{prelude::PointerLocation, HitData}, hover::{get_hovered_entities, is_directly_hovered, HoverMap, PreviousHoverMap}, - pointer::{Location, PointerAction, PointerButton, PointerId, PointerInput, PointerMap}, + pointer::{Location, PointerAction, PointerId, PointerInput, PointerMap}, PickingSettings, }; @@ -290,7 +290,7 @@ pub struct Leave { #[reflect(Clone, PartialEq)] pub struct Press { /// Pointer button pressed to trigger this event. - pub button: PointerButton, + pub button: MouseButton, /// Information about the picking intersection. pub hit: HitData, /// Number of consecutive presses, starting at `1`. @@ -302,7 +302,7 @@ pub struct Press { #[reflect(Clone, PartialEq)] pub struct Release { /// Pointer button lifted to trigger this event. - pub button: PointerButton, + pub button: MouseButton, /// Information about the picking intersection. pub hit: HitData, } @@ -313,7 +313,7 @@ pub struct Release { #[reflect(Clone, PartialEq)] pub struct Click { /// Pointer button pressed and lifted to trigger this event. - pub button: PointerButton, + pub button: MouseButton, /// Information about the picking intersection. pub hit: HitData, /// Duration between the pointer pressed and lifted for this click @@ -342,7 +342,7 @@ pub struct Move { #[reflect(Clone, PartialEq)] pub struct DragStart { /// Pointer button pressed and moved to trigger this event. - pub button: PointerButton, + pub button: MouseButton, /// Information about the picking intersection. pub hit: HitData, } @@ -352,7 +352,7 @@ pub struct DragStart { #[reflect(Clone, PartialEq)] pub struct Drag { /// Pointer button pressed and moved to trigger this event. - pub button: PointerButton, + pub button: MouseButton, /// The total distance vector of a drag, measured from drag start to the current position. /// /// This is stored in screen pixels, not world coordinates. Screen pixels go from top-left to @@ -374,7 +374,7 @@ pub struct Drag { #[reflect(Clone, PartialEq)] pub struct DragEnd { /// Pointer button pressed, moved, and released to trigger this event. - pub button: PointerButton, + pub button: MouseButton, /// The vector of drag movement measured from start to final pointer position. /// /// This is stored in screen pixels, not world coordinates. Screen pixels go from top-left to @@ -389,7 +389,7 @@ pub struct DragEnd { #[reflect(Clone, PartialEq)] pub struct DragEnter { /// Pointer button pressed to enter drag. - pub button: PointerButton, + pub button: MouseButton, /// The entity that was being dragged when the pointer entered the [target entity](EntityEvent::event_target). pub dragged: Entity, /// Information about the picking intersection. @@ -401,7 +401,7 @@ pub struct DragEnter { #[reflect(Clone, PartialEq)] pub struct DragOver { /// Pointer button pressed while dragging over. - pub button: PointerButton, + pub button: MouseButton, /// The entity that was being dragged when the pointer was over the [target entity](EntityEvent::event_target). pub dragged: Entity, /// Information about the picking intersection. @@ -413,7 +413,7 @@ pub struct DragOver { #[reflect(Clone, PartialEq)] pub struct DragLeave { /// Pointer button pressed while leaving drag. - pub button: PointerButton, + pub button: MouseButton, /// The entity that was being dragged when the pointer left the [target entity](EntityEvent::event_target). pub dragged: Entity, /// Information about the latest prior picking intersection. @@ -425,7 +425,7 @@ pub struct DragLeave { #[reflect(Clone, PartialEq)] pub struct DragDrop { /// Pointer button released to drop. - pub button: PointerButton, + pub button: MouseButton, /// The entity that was dropped onto the [target entity](EntityEvent::event_target). pub dropped: Entity, /// Information about the picking intersection. @@ -586,25 +586,27 @@ impl HoveredEntityAncestors { #[reflect(Debug, Clone, Default, Resource)] pub struct PointerState { /// Pressing and dragging state, organized by pointer and button. - pub pointer_buttons: HashMap<(PointerId, PointerButton), PointerButtonState>, + pub pointer_buttons: HashMap>, /// A cache map providing the set of an entity's ancestors for a given hovered entity. pub hovered_entity_ancestors: HoveredEntityAncestors, } 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)) + pub fn get(&self, pointer_id: PointerId, button: MouseButton) -> Option<&PointerButtonState> { + self.pointer_buttons.get(&pointer_id)?.get(&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, + button: MouseButton, ) -> &mut PointerButtonState { self.pointer_buttons - .entry((pointer_id, button)) + .entry(pointer_id) + .or_default() + .entry(button) .or_default() } @@ -621,10 +623,8 @@ impl PointerState { /// Clears all the data associated 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.clear(); - } + if let Some(state) = self.pointer_buttons.get_mut(&(pointer_id)) { + state.clear(); } } } @@ -810,22 +810,23 @@ pub fn pointer_events( } // Possibly send DragLeave events - for button in PointerButton::iter() { - let state = pointer_state.get_mut(pointer_id, button); - state.dragging_over.remove(&hovered_entity); - for drag_target in state.dragging.keys() { - let drag_leave_event = Pointer::new( - pointer_id, - location.clone(), - DragLeave { - button, - dragged: *drag_target, - hit: hit.clone(), - }, - hovered_entity, - ); - commands.trigger(drag_leave_event.clone()); - message_writers.drag_leave_events.write(drag_leave_event); + if let Some(pointer_data) = pointer_state.pointer_buttons.get_mut(&pointer_id) { + for (button, state) in pointer_data.iter_mut() { + state.dragging_over.remove(&hovered_entity); + for drag_target in state.dragging.keys() { + let drag_leave_event = Pointer::new( + pointer_id, + location.clone(), + DragLeave { + button: *button, + dragged: *drag_target, + hit: hit.clone(), + }, + hovered_entity, + ); + commands.trigger(drag_leave_event.clone()); + message_writers.drag_leave_events.write(drag_leave_event); + } } } } @@ -846,30 +847,30 @@ pub fn pointer_events( }; // For each button update its `dragging_over` state and possibly emit DragEnter events. - for button in PointerButton::iter() { - let state = pointer_state.get_mut(pointer_id, button); - - // Only update the `dragging_over` state if there is at least one entity being dragged. - // Only emit DragEnter events for this `hovered_entity`, if it had no previous `dragging_over` state. - if !state.dragging.is_empty() - && state - .dragging_over - .insert(hovered_entity, hit.clone()) - .is_none() - { - for drag_target in state.dragging.keys() { - let drag_enter_event = Pointer::new( - pointer_id, - location.clone(), - DragEnter { - button, - dragged: *drag_target, - hit: hit.clone(), - }, - hovered_entity, - ); - commands.trigger(drag_enter_event.clone()); - message_writers.drag_enter_events.write(drag_enter_event); + if let Some(pointer_data) = pointer_state.pointer_buttons.get_mut(&pointer_id) { + for (button, state) in pointer_data.iter_mut() { + // Only update the `dragging_over` state if there is at least one entity being dragged. + // Only emit DragEnter events for this `hovered_entity`, if it had no previous `dragging_over` state. + if !state.dragging.is_empty() + && state + .dragging_over + .insert(hovered_entity, hit.clone()) + .is_none() + { + for drag_target in state.dragging.keys() { + let drag_enter_event = Pointer::new( + pointer_id, + location.clone(), + DragEnter { + button: *button, + dragged: *drag_target, + hit: hit.clone(), + }, + hovered_entity, + ); + commands.trigger(drag_enter_event.clone()); + message_writers.drag_enter_events.write(drag_enter_event); + } } } } @@ -1092,99 +1093,104 @@ pub fn pointer_events( continue; // If delta is zero, the following events will not be triggered. } // Triggers during movement even if not over an entity - for button in PointerButton::iter() { - let state = pointer_state.get_mut(pointer_id, button); - - // Emit DragEntry and DragStart the first time we move while pressing an entity - for (press_target, (location, _, hit)) in state.pressing.iter() { - if state.dragging.contains_key(press_target) { - continue; // This entity is already logged as being dragged - } - state.dragging.insert( - *press_target, - DragEntry { - start_pos: location.position, - latest_pos: location.position, - }, - ); - let drag_start_event = Pointer::new( - pointer_id, - location.clone(), - DragStart { - button, - hit: hit.clone(), - }, - *press_target, - ); - - commands.trigger(drag_start_event.clone()); - message_writers.drag_start_events.write(drag_start_event); - - // Insert dragging over state and emit DragEnter for hovered entities. - for (hovered_entity, hit) in hover_map - .get(&pointer_id) - .iter() - .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned()))) - .filter(|(hovered_entity, _)| *hovered_entity != *press_target) - { - // Inserting the `dragging_over` state here ensures the `DragEnter` event won't be dispatched twice. - state.dragging_over.insert(hovered_entity, hit.clone()); - let drag_enter_event = Pointer::new( + if let Some(pointer_data) = pointer_state.pointer_buttons.get_mut(&pointer_id) { + for (button, state) in pointer_data.iter_mut() { + let button = *button; + // Emit DragEntry and DragStart the first time we move while pressing an entity + for (press_target, (location, _, hit)) in state.pressing.iter() { + if state.dragging.contains_key(press_target) { + continue; // This entity is already logged as being dragged + } + state.dragging.insert( + *press_target, + DragEntry { + start_pos: location.position, + latest_pos: location.position, + }, + ); + let drag_start_event = Pointer::new( pointer_id, location.clone(), - DragEnter { + DragStart { button, - dragged: *press_target, hit: hit.clone(), }, - hovered_entity, + *press_target, ); - commands.trigger(drag_enter_event.clone()); - message_writers.drag_enter_events.write(drag_enter_event); - } - } - // Emit Drag events to the entities we are dragging - for (drag_target, drag) in state.dragging.iter_mut() { - let delta = location.position - drag.latest_pos; - if delta == Vec2::ZERO { - continue; // No need to emit a Drag event if there is no movement + commands.trigger(drag_start_event.clone()); + message_writers.drag_start_events.write(drag_start_event); + + // Insert dragging over state and emit DragEnter for hovered entities. + for (hovered_entity, hit) in hover_map + .get(&pointer_id) + .iter() + .flat_map(|h| { + h.iter().map(|(entity, data)| (*entity, data.to_owned())) + }) + .filter(|(hovered_entity, _)| *hovered_entity != *press_target) + { + // Inserting the `dragging_over` state here ensures the `DragEnter` event won't be dispatched twice. + state.dragging_over.insert(hovered_entity, hit.clone()); + let drag_enter_event = Pointer::new( + pointer_id, + location.clone(), + DragEnter { + button, + dragged: *press_target, + hit: hit.clone(), + }, + hovered_entity, + ); + commands.trigger(drag_enter_event.clone()); + message_writers.drag_enter_events.write(drag_enter_event); + } } - let drag_event = Pointer::new( - pointer_id, - location.clone(), - Drag { - button, - distance: location.position - drag.start_pos, - delta, - }, - *drag_target, - ); - commands.trigger(drag_event.clone()); - message_writers.drag_events.write(drag_event); - - // Update drag position - drag.latest_pos = location.position; - - // Emit corresponding DragOver to the hovered entities - for (hovered_entity, hit) in hover_map - .get(&pointer_id) - .iter() - .flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned()))) - .filter(|(hovered_entity, _)| *hovered_entity != *drag_target) - { - let drag_over_event = Pointer::new( + + // Emit Drag events to the entities we are dragging + for (drag_target, drag) in state.dragging.iter_mut() { + let delta = location.position - drag.latest_pos; + if delta == Vec2::ZERO { + continue; // No need to emit a Drag event if there is no movement + } + let drag_event = Pointer::new( pointer_id, location.clone(), - DragOver { + Drag { button, - dragged: *drag_target, - hit: hit.clone(), + distance: location.position - drag.start_pos, + delta, }, - hovered_entity, + *drag_target, ); - commands.trigger(drag_over_event.clone()); - message_writers.drag_over_events.write(drag_over_event); + commands.trigger(drag_event.clone()); + message_writers.drag_events.write(drag_event); + + // Update drag position + drag.latest_pos = location.position; + + // Emit corresponding DragOver to the hovered entities + for (hovered_entity, hit) in hover_map + .get(&pointer_id) + .iter() + .flat_map(|h| { + h.iter().map(|(entity, data)| (*entity, data.to_owned())) + }) + .filter(|(hovered_entity, _)| *hovered_entity != *drag_target) + { + let drag_over_event = Pointer::new( + pointer_id, + location.clone(), + DragOver { + button, + dragged: *drag_target, + hit: hit.clone(), + }, + hovered_entity, + ); + commands.trigger(drag_over_event.clone()); + message_writers.drag_over_events.write(drag_over_event); + } } } } diff --git a/crates/bevy_picking/src/input.rs b/crates/bevy_picking/src/input.rs index ae6dd8f8df3d3..8138fb64cb7ff 100644 --- a/crates/bevy_picking/src/input.rs +++ b/crates/bevy_picking/src/input.rs @@ -26,9 +26,7 @@ use bevy_reflect::prelude::*; use bevy_window::{PrimaryWindow, WindowEvent, WindowRef}; use tracing::debug; -use crate::pointer::{ - Location, PointerAction, PointerButton, PointerId, PointerInput, PointerLocation, -}; +use crate::pointer::{Location, PointerAction, PointerId, PointerInput, PointerLocation}; use crate::PickingSystems; @@ -160,15 +158,9 @@ pub fn mouse_pick_events( }, position: *cursor_last, }; - let button = match input.button { - MouseButton::Left => PointerButton::Primary, - MouseButton::Right => PointerButton::Secondary, - MouseButton::Middle => PointerButton::Middle, - MouseButton::Other(_) | MouseButton::Back | MouseButton::Forward => continue, - }; let action = match input.state { - ButtonState::Pressed => PointerAction::Press(button), - ButtonState::Released => PointerAction::Release(button), + ButtonState::Pressed => PointerAction::Press(input.button), + ButtonState::Released => PointerAction::Release(input.button), }; pointer_inputs.write(PointerInput::new(PointerId::Mouse, location, action)); } @@ -231,7 +223,7 @@ pub fn touch_pick_events( pointer_inputs.write(PointerInput::new( pointer, location, - PointerAction::Press(PointerButton::Primary), + PointerAction::Press(MouseButton::Left), )); touch_cache.insert(touch.id, *touch); @@ -256,7 +248,7 @@ pub fn touch_pick_events( pointer_inputs.write(PointerInput::new( pointer, location, - PointerAction::Release(PointerButton::Primary), + PointerAction::Release(MouseButton::Left), )); touch_cache.remove(&touch.id); } diff --git a/crates/bevy_picking/src/lib.rs b/crates/bevy_picking/src/lib.rs index b508858f9629e..2395aa281587f 100644 --- a/crates/bevy_picking/src/lib.rs +++ b/crates/bevy_picking/src/lib.rs @@ -183,8 +183,8 @@ pub mod prelude { }; #[doc(hidden)] pub use crate::{ - events::*, input::PointerInputPlugin, pointer::PointerButton, DefaultPickingPlugins, - InteractionPlugin, Pickable, PickingPlugin, + events::*, input::PointerInputPlugin, DefaultPickingPlugins, InteractionPlugin, Pickable, + PickingPlugin, }; } diff --git a/crates/bevy_picking/src/pointer.rs b/crates/bevy_picking/src/pointer.rs index 5a2aff2386e71..220f1860ef7cc 100644 --- a/crates/bevy_picking/src/pointer.rs +++ b/crates/bevy_picking/src/pointer.rs @@ -11,7 +11,7 @@ use bevy_camera::NormalizedRenderTarget; use bevy_camera::{Camera, RenderTarget}; use bevy_ecs::prelude::*; -use bevy_input::mouse::MouseScrollUnit; +use bevy_input::mouse::{MouseButton, MouseScrollUnit}; use bevy_input::touch::TouchPhase; use bevy_math::Vec2; use bevy_platform::collections::HashMap; @@ -21,6 +21,7 @@ use bevy_window::PrimaryWindow; use uuid::Uuid; use core::{fmt::Debug, ops::Deref}; +use std::collections::HashSet; use crate::backend::HitData; @@ -114,64 +115,31 @@ pub fn update_pointer_map(pointers: Query<(Entity, &PointerId)>, mut map: ResMut /// Tracks the state of the pointer's buttons in response to [`PointerInput`] events. #[derive(Debug, Default, Clone, Component, Reflect, PartialEq, Eq)] #[reflect(Component, Default, Debug, PartialEq, Clone)] -pub struct PointerPress { - primary: bool, - secondary: bool, - middle: bool, -} +pub struct PointerPress(HashSet); impl PointerPress { /// Returns true if the primary pointer button is pressed. #[inline] pub fn is_primary_pressed(&self) -> bool { - self.primary + self.0.contains(&MouseButton::Left) } /// Returns true if the secondary pointer button is pressed. #[inline] pub fn is_secondary_pressed(&self) -> bool { - self.secondary + self.0.contains(&MouseButton::Right) } /// Returns true if the middle (tertiary) pointer button is pressed. #[inline] pub fn is_middle_pressed(&self) -> bool { - self.middle + self.0.contains(&MouseButton::Middle) } /// Returns true if any pointer button is pressed. #[inline] pub fn is_any_pressed(&self) -> bool { - self.primary || self.middle || self.secondary - } -} - -/// The stage of the pointer button press event -#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect)] -#[reflect(Clone, PartialEq)] -pub enum PressDirection { - /// The pointer button was just pressed - Pressed, - /// The pointer button was just released - Released, -} - -/// The button that was just pressed or released -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] -#[reflect(Clone, PartialEq)] -pub enum PointerButton { - /// The primary pointer button - Primary, - /// The secondary pointer button - Secondary, - /// The tertiary pointer button - Middle, -} - -impl PointerButton { - /// Iterator over all buttons that a pointer can have. - pub fn iter() -> impl Iterator { - [Self::Primary, Self::Secondary, Self::Middle].into_iter() + !self.0.is_empty() } } @@ -250,9 +218,9 @@ impl Location { #[reflect(Clone)] pub enum PointerAction { /// Causes the pointer to press a button. - Press(PointerButton), + Press(MouseButton), /// Causes the pointer to release a button. - Release(PointerButton), + Release(MouseButton), /// Move the pointer. Move { /// How much the pointer moved from the previous position. @@ -301,7 +269,7 @@ 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 { + pub fn button_just_pressed(&self, target_button: MouseButton) -> bool { if let PointerAction::Press(button) = self.action { button == target_button } else { @@ -311,7 +279,7 @@ 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 { + pub fn button_just_released(&self, target_button: MouseButton) -> bool { if let PointerAction::Release(button) = self.action { button == target_button } else { @@ -327,37 +295,25 @@ impl PointerInput { for event in events.read() { match event.action { PointerAction::Press(button) => { - pointers - .iter_mut() - .for_each(|(pointer_id, _, mut pointer)| { - if *pointer_id == event.pointer_id { - match button { - PointerButton::Primary => pointer.primary = true, - PointerButton::Secondary => pointer.secondary = true, - PointerButton::Middle => pointer.middle = true, - } - } - }); + for (pointer_id, _, mut pointer) in pointers.iter_mut() { + if *pointer_id == event.pointer_id { + pointer.0.insert(button); + } + } } 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, - } - } - }); + for (pointer_id, _, mut pointer) in pointers.iter_mut() { + if *pointer_id == event.pointer_id { + pointer.0.remove(&button); + } + } } PointerAction::Move { .. } => { - pointers.iter_mut().for_each(|(id, mut pointer, _)| { + for (id, mut pointer, _) in pointers.iter_mut() { if *id == event.pointer_id { pointer.location = Some(event.location.to_owned()); } - }); + } } _ => {} } diff --git a/crates/bevy_ui/src/widget/viewport.rs b/crates/bevy_ui/src/widget/viewport.rs index 5668f94ddda60..95f2d137693bb 100644 --- a/crates/bevy_ui/src/widget/viewport.rs +++ b/crates/bevy_ui/src/widget/viewport.rs @@ -94,13 +94,15 @@ pub fn viewport_picking( .collect(); // Handle dragged entities, which need to be considered for dragging in and out of viewports. - for ((pointer_id, _), pointer_state) in pointer_state.pointer_buttons.iter() { - for &target in pointer_state - .dragging - .keys() - .filter(|&entity| viewport_query.contains(*entity)) - { - viewport_picks.insert(target, *pointer_id); + for (pointer_id, buttons) in pointer_state.pointer_buttons.iter() { + for pointer_state in buttons.values() { + for &target in pointer_state + .dragging + .keys() + .filter(|&entity| viewport_query.contains(*entity)) + { + viewport_picks.insert(target, *pointer_id); + } } } diff --git a/crates/bevy_ui_widgets/src/checkbox.rs b/crates/bevy_ui_widgets/src/checkbox.rs index dcd04c8f24ba6..95c22e52affde 100644 --- a/crates/bevy_ui_widgets/src/checkbox.rs +++ b/crates/bevy_ui_widgets/src/checkbox.rs @@ -344,7 +344,7 @@ mod tests { /// descendant of the widget; the events bubble up via `ChildOf` just like real pointer events. fn click_entity(app: &mut App, target: Entity, window: Entity) { let location = window_location(window); - let button = bevy_picking::pointer::PointerButton::Primary; + let button = bevy_input::mouse::MouseButton::Left; app.world_mut().trigger(Pointer::new( PointerId::Mouse, location.clone(), diff --git a/crates/bevy_ui_widgets/src/dialog.rs b/crates/bevy_ui_widgets/src/dialog.rs index 6cf5298983593..3951a89c53b13 100644 --- a/crates/bevy_ui_widgets/src/dialog.rs +++ b/crates/bevy_ui_widgets/src/dialog.rs @@ -14,13 +14,11 @@ use bevy_ecs::{ schedule::{common_conditions::resource_changed, IntoScheduleConfigs}, system::{Commands, Query, Res, ResMut, Single}, }; +use bevy_input::mouse::MouseButton; use bevy_input_focus::tab_navigation::TabGroup; use bevy_log::warn; use bevy_math::Vec2; -use bevy_picking::{ - events::{Drag, DragStart, Pointer, Press}, - pointer::PointerButton, -}; +use bevy_picking::events::{Drag, DragStart, Pointer, Press}; use bevy_reflect::Reflect; use bevy_ui::{GlobalZIndex, UiScale, UiTransform, Val2}; use bevy_window::{PrimaryWindow, Window}; @@ -148,7 +146,7 @@ fn dialog_drag_start( mut q_state: Query<&mut DialogDragState>, ui_scale: Res, ) { - if drag_start.button != PointerButton::Primary { + if drag_start.button != MouseButton::Left { return; } // Only the handle entity itself drives the move. @@ -184,7 +182,7 @@ fn dialog_drag( // TODO: multiple windows? dragging between them, etc primary_window: Single<&Window, With>, ) { - if drag.button != PointerButton::Primary { + if drag.button != MouseButton::Left { return; } let handle = drag.event_target(); diff --git a/crates/bevy_ui_widgets/src/radio.rs b/crates/bevy_ui_widgets/src/radio.rs index 70c646a59a292..34e7f49d990f2 100644 --- a/crates/bevy_ui_widgets/src/radio.rs +++ b/crates/bevy_ui_widgets/src/radio.rs @@ -370,11 +370,12 @@ pub fn radio_self_update( mod tests { use super::*; use bevy_app::App; + use bevy_input::mouse::MouseButton; use bevy_input::InputPlugin; use bevy_input_focus::{tab_navigation::TabNavigationPlugin, InputFocusPlugin}; use bevy_math::Vec2; use bevy_picking::backend::HitData; - use bevy_picking::pointer::{Location, PointerButton, PointerId}; + use bevy_picking::pointer::{Location, PointerId}; use bevy_window::{PrimaryWindow, Window, WindowRef}; /// Builds a headless app with the radio-group observers plus [`radio_self_update`], so that a @@ -411,7 +412,7 @@ mod tests { PointerId::Mouse, window_location(window), Click { - button: PointerButton::Primary, + button: MouseButton::Left, hit: HitData::new(window, 0.0, None, None), duration: core::time::Duration::from_millis(10), count: 1, diff --git a/crates/bevy_ui_widgets/src/text_input.rs b/crates/bevy_ui_widgets/src/text_input.rs index ae59d3bec7c75..b6e191c95b69b 100644 --- a/crates/bevy_ui_widgets/src/text_input.rs +++ b/crates/bevy_ui_widgets/src/text_input.rs @@ -11,13 +11,13 @@ use bevy_a11y::{AccessibilityNode, AccessibilitySystems}; use bevy_app::{App, Plugin, PostUpdate, PreUpdate}; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_input::keyboard::{Key, KeyCode, KeyboardInput}; +use bevy_input::mouse::MouseButton; use bevy_input::{ButtonInput, InputSystems}; use bevy_input_focus::{ FocusCause, FocusGained, FocusLost, FocusedInput, InputFocus, InputFocusSystems, }; use bevy_math::Vec2; use bevy_picking::events::{Drag, Pointer, PointerState, Press, Release}; -use bevy_picking::pointer::PointerButton; use bevy_reflect::Reflect; use bevy_text::{ scrollable_text_layout_width, EditableText, EditableTextSystems, PreeditCursor, TextEdit, @@ -250,7 +250,7 @@ fn on_pointer_press( keys: Res>, ui_scale: Res, ) { - if press.button != PointerButton::Primary { + if press.button != MouseButton::Left { return; } @@ -318,7 +318,7 @@ fn on_pointer_drag( >, ui_scale: Res, ) { - if drag.button != PointerButton::Primary { + if drag.button != MouseButton::Left { return; } @@ -370,12 +370,13 @@ pub(crate) fn text_input_autoscroll_system( let Some(entity) = input_focus.get() else { return; }; - let Some(pointer_position) = pointer_state - .pointer_buttons - .iter() - .filter(|((_, button), ..)| *button == PointerButton::Primary) - .find_map(|(_, state)| state.dragging.get(&entity).map(|drag| drag.latest_pos)) - else { + + let Some(pointer_position) = pointer_state.pointer_buttons.values().find_map(|button| { + match button.get(&MouseButton::Left) { + Some(state) => Some(state.dragging.get(&entity).map(|drag| drag.latest_pos)?), + None => None, + } + }) else { return; }; @@ -694,7 +695,7 @@ fn apply_queued_select_all( return; }; for pointer_release in pointer_releases.read() { - if pointer_release.button == PointerButton::Primary + if pointer_release.button == MouseButton::Left && let Ok(mut editable_text) = q_text_input.get_mut(target) { editable_text.queue_edit(TextEdit::SelectAllIfCollapsed); @@ -894,7 +895,7 @@ mod tests { app.insert_resource(InputFocus::from_entity(entity)); app.world_mut() .resource_mut::() - .get_mut(PointerId::Mouse, PointerButton::Primary) + .get_mut(PointerId::Mouse, MouseButton::Left) .dragging .insert( entity, @@ -952,7 +953,7 @@ mod tests { .clear(); app.world_mut() .resource_mut::() - .get_mut(PointerId::Mouse, PointerButton::Primary) + .get_mut(PointerId::Mouse, MouseButton::Left) .dragging .get_mut(&entity) .unwrap() diff --git a/crates/bevy_winit/src/state.rs b/crates/bevy_winit/src/state.rs index d4933d7d3b81e..ee49a4b0a3584 100644 --- a/crates/bevy_winit/src/state.rs +++ b/crates/bevy_winit/src/state.rs @@ -678,12 +678,12 @@ impl WinitAppRunnerState { target_os = "android", target_os = "ios", all(target_os = "linux", any(feature = "x11", feature = "wayland")) - )) => - { + )) => { let visible = WINIT_WINDOWS.with_borrow(|winit_windows| { - winit_windows.windows.iter().any(|(_, w)| { - w.is_visible().unwrap_or(false) - }) + winit_windows + .windows + .iter() + .any(|(_, w)| w.is_visible().unwrap_or(false)) }); event_loop.set_control_flow(if visible { diff --git a/examples/asset/asset_saving_with_subassets.rs b/examples/asset/asset_saving_with_subassets.rs index 267327ed1020a..44b40029ed2ae 100644 --- a/examples/asset/asset_saving_with_subassets.rs +++ b/examples/asset/asset_saving_with_subassets.rs @@ -268,7 +268,7 @@ fn spawn_box( camera: Single<(&Camera, &GlobalTransform)>, mut commands: Commands, ) { - if event.button != PointerButton::Primary { + if event.button != MouseButton::Right { return; } if !window.contains(event.entity) { @@ -307,7 +307,7 @@ fn start_rotate_box_hue( boxes: Query<(), With>, mut commands: Commands, ) { - if event.button != PointerButton::Secondary { + if event.button != MouseButton::Right { return; } if !boxes.contains(event.entity) { @@ -322,7 +322,7 @@ fn end_rotate_box_hue_on_release( boxes: Query<(), (With, With)>, mut commands: Commands, ) { - if event.button != PointerButton::Secondary { + if event.button != MouseButton::Right { return; } if !boxes.contains(event.entity) { @@ -345,7 +345,7 @@ fn end_rotate_box_hue_on_out( /// Blocks propagation of pointer press events on left-clicked boxes. fn stop_propagate_on_clicked_box(mut event: On>, boxes: Query<(), With>) { - if event.button != PointerButton::Primary { + if event.button != MouseButton::Left { return; } if !boxes.contains(event.entity) { @@ -356,7 +356,7 @@ fn stop_propagate_on_clicked_box(mut event: On>, boxes: Query<(), /// Drags a box when you left-click on one. fn drag_box(event: On>, mut boxes: Query<&mut Transform, With>) { - if event.button != PointerButton::Primary { + if event.button != MouseButton::Left { return; } let Ok(mut transform) = boxes.get_mut(event.entity) else { diff --git a/examples/gizmos/transform_gizmo.rs b/examples/gizmos/transform_gizmo.rs index 5d63a950a6886..897930ed6f27b 100644 --- a/examples/gizmos/transform_gizmo.rs +++ b/examples/gizmos/transform_gizmo.rs @@ -11,7 +11,7 @@ use bevy::{ TransformGizmoCamera, TransformGizmoFocus, TransformGizmoMode, TransformGizmoPlugin, TransformGizmoSettings, TransformGizmoSpace, }, - picking::{pointer::PointerButton, Pickable}, + picking::Pickable, prelude::*, ui_widgets::{radio_self_update, SliderPrecision, SliderStep, SliderValue, ValueChange}, }; @@ -169,7 +169,7 @@ fn on_click_select( mut commands: Commands, existing: Query>, ) { - if click.button != PointerButton::Primary { + if click.button != MouseButton::Left { return; } // Remove focus from all entities diff --git a/examples/showcase/mines.rs b/examples/showcase/mines.rs index 9895f887e5e23..8ca1ed0e80898 100644 --- a/examples/showcase/mines.rs +++ b/examples/showcase/mines.rs @@ -421,7 +421,7 @@ fn on_button_click( mut game: ResMut, mut next_state: ResMut>, ) { - if click.button != PointerButton::Primary { + if click.button != MouseButton::Left { return; } @@ -490,14 +490,14 @@ fn on_tile_click( }; match click.button { - PointerButton::Primary => { + MouseButton::Left => { if game.field[position].mined { game.game_over = true; } else { game.field.reveal(position); } } - PointerButton::Secondary => { + MouseButton::Right => { if game.field[position].flagged { game.field[position].flagged = false; } else if game.field.flag_count() < game.field.mine_count() { diff --git a/examples/ui/navigation/directional_navigation.rs b/examples/ui/navigation/directional_navigation.rs index 15029faa01437..4c3c56fa76d07 100644 --- a/examples/ui/navigation/directional_navigation.rs +++ b/examples/ui/navigation/directional_navigation.rs @@ -473,7 +473,7 @@ fn interact_with_focused_button( position: Vec2::ZERO, }, Click { - button: PointerButton::Primary, + button: MouseButton::Left, hit: HitData { camera: Entity::PLACEHOLDER, depth: 0.0, diff --git a/examples/ui/navigation/directional_navigation_overrides.rs b/examples/ui/navigation/directional_navigation_overrides.rs index 84412f6ddf561..14ea408dcd992 100644 --- a/examples/ui/navigation/directional_navigation_overrides.rs +++ b/examples/ui/navigation/directional_navigation_overrides.rs @@ -812,7 +812,7 @@ fn interact_with_focused_button( position: Vec2::ZERO, }, Click { - button: PointerButton::Primary, + button: MouseButton::Left, hit: HitData { camera: Entity::PLACEHOLDER, depth: 0.0, diff --git a/examples/ui/render_ui_to_texture.rs b/examples/ui/render_ui_to_texture.rs index 304e299e781fa..4b5bcdf812f52 100644 --- a/examples/ui/render_ui_to_texture.rs +++ b/examples/ui/render_ui_to_texture.rs @@ -207,15 +207,9 @@ fn drive_diegetic_pointer( // Pipe pointer button presses to the virtual pointer on the UI texture. for window_event in window_events.read() { if let WindowEvent::MouseButtonInput(input) = window_event { - let button = match input.button { - MouseButton::Left => PointerButton::Primary, - MouseButton::Right => PointerButton::Secondary, - MouseButton::Middle => PointerButton::Middle, - _ => continue, - }; let action = match input.state { - ButtonState::Pressed => PointerAction::Press(button), - ButtonState::Released => PointerAction::Release(button), + ButtonState::Pressed => PointerAction::Press(input.button), + ButtonState::Released => PointerAction::Release(input.button), }; pointer_inputs.write(PointerInput::new( CUBE_POINTER_ID, diff --git a/examples/ui/scroll_and_overflow/scroll.rs b/examples/ui/scroll_and_overflow/scroll.rs index 83b89003d17e1..5c28728c6a535 100644 --- a/examples/ui/scroll_and_overflow/scroll.rs +++ b/examples/ui/scroll_and_overflow/scroll.rs @@ -174,7 +174,7 @@ fn setup(mut commands: Commands, asset_server: Res) { )) .observe( |press: On>, mut commands: Commands| { - if press.event().button == PointerButton::Primary { + if press.event().button == MouseButton::Left { commands.entity(press.entity).despawn(); } }, diff --git a/examples/ui/ui_target_camera.rs b/examples/ui/ui_target_camera.rs index 5e6260f16606e..d9d6988effe0f 100644 --- a/examples/ui/ui_target_camera.rs +++ b/examples/ui/ui_target_camera.rs @@ -83,7 +83,7 @@ fn setup(mut commands: Commands) { return; }; camera.order += match on_pressed.button { - PointerButton::Primary => 1, + MouseButton::Left => 1, _ => -1, }; label_text.0 = format!("{}", camera.order); diff --git a/examples/ui/widgets/viewport_node.rs b/examples/ui/widgets/viewport_node.rs index 7dbf2b2925d36..852e034f540a4 100644 --- a/examples/ui/widgets/viewport_node.rs +++ b/examples/ui/widgets/viewport_node.rs @@ -77,7 +77,7 @@ fn test( } fn on_drag_viewport(drag: On>, mut node_query: Query<&mut Node>) { - if matches!(drag.button, PointerButton::Secondary) { + if matches!(drag.button, MouseButton::Right) { let mut node = node_query.get_mut(drag.entity).unwrap(); if let (Val::Px(top), Val::Px(left)) = (node.top, node.left) { @@ -88,7 +88,7 @@ fn on_drag_viewport(drag: On>, mut node_query: Query<&mut Node>) { } fn on_drag_cuboid(drag: On>, mut transform_query: Query<&mut Transform>) { - if matches!(drag.button, PointerButton::Primary) { + if matches!(drag.button, MouseButton::Left) { let mut transform = transform_query.get_mut(drag.entity).unwrap(); transform.rotate_y(drag.delta.x * 0.02); transform.rotate_x(drag.delta.y * 0.02); diff --git a/tests/window/desktop_request_redraw.rs b/tests/window/desktop_request_redraw.rs index 35d5b494a6821..4fb60e2a3f456 100644 --- a/tests/window/desktop_request_redraw.rs +++ b/tests/window/desktop_request_redraw.rs @@ -83,10 +83,10 @@ fn setup( )) .observe( |click: On>, mut commands: Commands| match click.button { - PointerButton::Primary => { + MouseButton::Left => { commands.entity(click.entity).insert(AnimationActive); } - PointerButton::Secondary => { + MouseButton::Right => { commands.entity(click.entity).remove::(); } _ => {}