1use bevy_camera::Camera;
12use bevy_camera::NormalizedRenderTarget;
13use bevy_ecs::prelude::*;
14use bevy_input::mouse::MouseScrollUnit;
15use bevy_math::Vec2;
16use bevy_platform::collections::HashMap;
17use bevy_reflect::prelude::*;
18use bevy_window::PrimaryWindow;
19
20use uuid::Uuid;
21
22use core::{fmt::Debug, ops::Deref};
23
24use crate::backend::HitData;
25
26#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, Component, Reflect)]
31#[require(PointerLocation, PointerPress, PointerInteraction)]
32#[reflect(Component, Default, Debug, Hash, PartialEq, Clone)]
33pub enum PointerId {
34 #[default]
36 Mouse,
37 Touch(u64),
39 #[reflect(ignore, clone)]
42 Custom(Uuid),
43}
44
45impl PointerId {
46 pub fn is_touch(&self) -> bool {
48 matches!(self, PointerId::Touch(_))
49 }
50 pub fn is_mouse(&self) -> bool {
52 matches!(self, PointerId::Mouse)
53 }
54 pub fn is_custom(&self) -> bool {
56 matches!(self, PointerId::Custom(_))
57 }
58 pub fn get_touch_id(&self) -> Option<u64> {
60 if let PointerId::Touch(id) = self {
61 Some(*id)
62 } else {
63 None
64 }
65 }
66}
67
68#[derive(Debug, Default, Clone, Component, Reflect)]
71#[reflect(Component, Default, Debug, Clone)]
72pub struct PointerInteraction {
73 pub(crate) sorted_entities: Vec<(Entity, HitData)>,
74}
75
76impl PointerInteraction {
77 pub fn get_nearest_hit(&self) -> Option<&(Entity, HitData)> {
79 self.sorted_entities.first()
80 }
81}
82
83impl Deref for PointerInteraction {
84 type Target = Vec<(Entity, HitData)>;
85
86 fn deref(&self) -> &Self::Target {
87 &self.sorted_entities
88 }
89}
90
91#[derive(Debug, Clone, Default, Resource)]
93pub struct PointerMap {
94 inner: HashMap<PointerId, Entity>,
95}
96
97impl PointerMap {
98 pub fn get_entity(&self, pointer_id: PointerId) -> Option<Entity> {
100 self.inner.get(&pointer_id).copied()
101 }
102}
103
104pub fn update_pointer_map(pointers: Query<(Entity, &PointerId)>, mut map: ResMut<PointerMap>) {
106 map.inner.clear();
107 for (entity, id) in &pointers {
108 map.inner.insert(*id, entity);
109 }
110}
111
112#[derive(Debug, Default, Clone, Component, Reflect, PartialEq, Eq)]
114#[reflect(Component, Default, Debug, PartialEq, Clone)]
115pub struct PointerPress {
116 primary: bool,
117 secondary: bool,
118 middle: bool,
119}
120
121impl PointerPress {
122 #[inline]
124 pub fn is_primary_pressed(&self) -> bool {
125 self.primary
126 }
127
128 #[inline]
130 pub fn is_secondary_pressed(&self) -> bool {
131 self.secondary
132 }
133
134 #[inline]
136 pub fn is_middle_pressed(&self) -> bool {
137 self.middle
138 }
139
140 #[inline]
142 pub fn is_any_pressed(&self) -> bool {
143 self.primary || self.middle || self.secondary
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect)]
149#[reflect(Clone, PartialEq)]
150pub enum PressDirection {
151 Pressed,
153 Released,
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
159#[reflect(Clone, PartialEq)]
160pub enum PointerButton {
161 Primary,
163 Secondary,
165 Middle,
167}
168
169impl PointerButton {
170 pub fn iter() -> impl Iterator<Item = PointerButton> {
172 [Self::Primary, Self::Secondary, Self::Middle].into_iter()
173 }
174}
175
176#[derive(Debug, Default, Clone, Component, Reflect, PartialEq)]
178#[reflect(Component, Default, Debug, PartialEq, Clone)]
179pub struct PointerLocation {
180 #[reflect(ignore, clone)]
183 pub location: Option<Location>,
184}
185
186impl PointerLocation {
187 pub fn new(location: Location) -> Self {
189 Self {
190 location: Some(location),
191 }
192 }
193
194 pub fn location(&self) -> Option<&Location> {
197 self.location.as_ref()
198 }
199}
200
201#[derive(Debug, Clone, Reflect, PartialEq)]
210#[reflect(Debug, PartialEq, Clone)]
211pub struct Location {
212 pub target: NormalizedRenderTarget,
214 pub position: Vec2,
216}
217
218impl Location {
219 #[inline]
223 pub fn is_in_viewport(
224 &self,
225 camera: &Camera,
226 primary_window: &Query<Entity, With<PrimaryWindow>>,
227 ) -> bool {
228 if camera
229 .target
230 .normalize(Some(match primary_window.single() {
231 Ok(w) => w,
232 Err(_) => return false,
233 }))
234 .as_ref()
235 != Some(&self.target)
236 {
237 return false;
238 }
239
240 camera
241 .logical_viewport_rect()
242 .is_some_and(|rect| rect.contains(self.position))
243 }
244}
245
246#[derive(Debug, Clone, Copy, Reflect)]
248#[reflect(Clone)]
249pub enum PointerAction {
250 Press(PointerButton),
252 Release(PointerButton),
254 Move {
256 delta: Vec2,
258 },
259 Scroll {
261 unit: MouseScrollUnit,
263 x: f32,
265 y: f32,
267 },
268 Cancel,
270}
271
272#[derive(Message, Debug, Clone, Reflect)]
274#[reflect(Clone)]
275pub struct PointerInput {
276 pub pointer_id: PointerId,
278 pub location: Location,
280 pub action: PointerAction,
282}
283
284impl PointerInput {
285 pub fn new(pointer_id: PointerId, location: Location, action: PointerAction) -> PointerInput {
289 PointerInput {
290 pointer_id,
291 location,
292 action,
293 }
294 }
295
296 #[inline]
298 pub fn button_just_pressed(&self, target_button: PointerButton) -> bool {
299 if let PointerAction::Press(button) = self.action {
300 button == target_button
301 } else {
302 false
303 }
304 }
305
306 #[inline]
308 pub fn button_just_released(&self, target_button: PointerButton) -> bool {
309 if let PointerAction::Release(button) = self.action {
310 button == target_button
311 } else {
312 false
313 }
314 }
315
316 pub fn receive(
318 mut events: MessageReader<PointerInput>,
319 mut pointers: Query<(&PointerId, &mut PointerLocation, &mut PointerPress)>,
320 ) {
321 for event in events.read() {
322 match event.action {
323 PointerAction::Press(button) => {
324 pointers
325 .iter_mut()
326 .for_each(|(pointer_id, _, mut pointer)| {
327 if *pointer_id == event.pointer_id {
328 match button {
329 PointerButton::Primary => pointer.primary = true,
330 PointerButton::Secondary => pointer.secondary = true,
331 PointerButton::Middle => pointer.middle = true,
332 }
333 }
334 });
335 }
336 PointerAction::Release(button) => {
337 pointers
338 .iter_mut()
339 .for_each(|(pointer_id, _, mut pointer)| {
340 if *pointer_id == event.pointer_id {
341 match button {
342 PointerButton::Primary => pointer.primary = false,
343 PointerButton::Secondary => pointer.secondary = false,
344 PointerButton::Middle => pointer.middle = false,
345 }
346 }
347 });
348 }
349 PointerAction::Move { .. } => {
350 pointers.iter_mut().for_each(|(id, mut pointer, _)| {
351 if *id == event.pointer_id {
352 pointer.location = Some(event.location.to_owned());
353 }
354 });
355 }
356 _ => {}
357 }
358 }
359 }
360}