1use bevy_ecs::prelude::*;
12use bevy_input::mouse::MouseScrollUnit;
13use bevy_math::Vec2;
14use bevy_platform::collections::HashMap;
15use bevy_reflect::prelude::*;
16use bevy_render::camera::{Camera, NormalizedRenderTarget};
17use bevy_window::PrimaryWindow;
18
19use uuid::Uuid;
20
21use core::{fmt::Debug, ops::Deref};
22
23use crate::backend::HitData;
24
25#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, Component, Reflect)]
30#[require(PointerLocation, PointerPress, PointerInteraction)]
31#[reflect(Component, Default, Debug, Hash, PartialEq, Clone)]
32pub enum PointerId {
33 #[default]
35 Mouse,
36 Touch(u64),
38 #[reflect(ignore, clone)]
41 Custom(Uuid),
42}
43
44impl PointerId {
45 pub fn is_touch(&self) -> bool {
47 matches!(self, PointerId::Touch(_))
48 }
49 pub fn is_mouse(&self) -> bool {
51 matches!(self, PointerId::Mouse)
52 }
53 pub fn is_custom(&self) -> bool {
55 matches!(self, PointerId::Custom(_))
56 }
57 pub fn get_touch_id(&self) -> Option<u64> {
59 if let PointerId::Touch(id) = self {
60 Some(*id)
61 } else {
62 None
63 }
64 }
65}
66
67#[derive(Debug, Default, Clone, Component, Reflect)]
70#[reflect(Component, Default, Debug, Clone)]
71pub struct PointerInteraction {
72 pub(crate) sorted_entities: Vec<(Entity, HitData)>,
73}
74
75impl PointerInteraction {
76 pub fn get_nearest_hit(&self) -> Option<&(Entity, HitData)> {
78 self.sorted_entities.first()
79 }
80}
81
82impl Deref for PointerInteraction {
83 type Target = Vec<(Entity, HitData)>;
84
85 fn deref(&self) -> &Self::Target {
86 &self.sorted_entities
87 }
88}
89
90#[derive(Debug, Clone, Default, Resource)]
92pub struct PointerMap {
93 inner: HashMap<PointerId, Entity>,
94}
95
96impl PointerMap {
97 pub fn get_entity(&self, pointer_id: PointerId) -> Option<Entity> {
99 self.inner.get(&pointer_id).copied()
100 }
101}
102
103pub fn update_pointer_map(pointers: Query<(Entity, &PointerId)>, mut map: ResMut<PointerMap>) {
105 map.inner.clear();
106 for (entity, id) in &pointers {
107 map.inner.insert(*id, entity);
108 }
109}
110
111#[derive(Debug, Default, Clone, Component, Reflect, PartialEq, Eq)]
113#[reflect(Component, Default, Debug, PartialEq, Clone)]
114pub struct PointerPress {
115 primary: bool,
116 secondary: bool,
117 middle: bool,
118}
119
120impl PointerPress {
121 #[inline]
123 pub fn is_primary_pressed(&self) -> bool {
124 self.primary
125 }
126
127 #[inline]
129 pub fn is_secondary_pressed(&self) -> bool {
130 self.secondary
131 }
132
133 #[inline]
135 pub fn is_middle_pressed(&self) -> bool {
136 self.middle
137 }
138
139 #[inline]
141 pub fn is_any_pressed(&self) -> bool {
142 self.primary || self.middle || self.secondary
143 }
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect)]
148#[reflect(Clone, PartialEq)]
149pub enum PressDirection {
150 Pressed,
152 Released,
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
158#[reflect(Clone, PartialEq)]
159pub enum PointerButton {
160 Primary,
162 Secondary,
164 Middle,
166}
167
168impl PointerButton {
169 pub fn iter() -> impl Iterator<Item = PointerButton> {
171 [Self::Primary, Self::Secondary, Self::Middle].into_iter()
172 }
173}
174
175#[derive(Debug, Default, Clone, Component, Reflect, PartialEq)]
177#[reflect(Component, Default, Debug, PartialEq, Clone)]
178pub struct PointerLocation {
179 #[reflect(ignore, clone)]
182 pub location: Option<Location>,
183}
184
185impl PointerLocation {
186 pub fn new(location: Location) -> Self {
188 Self {
189 location: Some(location),
190 }
191 }
192
193 pub fn location(&self) -> Option<&Location> {
196 self.location.as_ref()
197 }
198}
199
200#[derive(Debug, Clone, Component, Reflect, PartialEq)]
209#[reflect(Component, Debug, PartialEq, Clone)]
210pub struct Location {
211 pub target: NormalizedRenderTarget,
213 pub position: Vec2,
215}
216
217impl Location {
218 #[inline]
222 pub fn is_in_viewport(
223 &self,
224 camera: &Camera,
225 primary_window: &Query<Entity, With<PrimaryWindow>>,
226 ) -> bool {
227 if camera
228 .target
229 .normalize(Some(match primary_window.single() {
230 Ok(w) => w,
231 Err(_) => return false,
232 }))
233 .as_ref()
234 != Some(&self.target)
235 {
236 return false;
237 }
238
239 camera
240 .logical_viewport_rect()
241 .is_some_and(|rect| rect.contains(self.position))
242 }
243}
244
245#[derive(Debug, Clone, Copy, Reflect)]
247#[reflect(Clone)]
248pub enum PointerAction {
249 Press(PointerButton),
251 Release(PointerButton),
253 Move {
255 delta: Vec2,
257 },
258 Scroll {
260 unit: MouseScrollUnit,
262 x: f32,
264 y: f32,
266 },
267 Cancel,
269}
270
271#[derive(Event, Debug, Clone, Reflect)]
273#[reflect(Clone)]
274pub struct PointerInput {
275 pub pointer_id: PointerId,
277 pub location: Location,
279 pub action: PointerAction,
281}
282
283impl PointerInput {
284 pub fn new(pointer_id: PointerId, location: Location, action: PointerAction) -> PointerInput {
288 PointerInput {
289 pointer_id,
290 location,
291 action,
292 }
293 }
294
295 #[inline]
297 pub fn button_just_pressed(&self, target_button: PointerButton) -> bool {
298 if let PointerAction::Press(button) = self.action {
299 button == target_button
300 } else {
301 false
302 }
303 }
304
305 #[inline]
307 pub fn button_just_released(&self, target_button: PointerButton) -> bool {
308 if let PointerAction::Release(button) = self.action {
309 button == target_button
310 } else {
311 false
312 }
313 }
314
315 pub fn receive(
317 mut events: EventReader<PointerInput>,
318 mut pointers: Query<(&PointerId, &mut PointerLocation, &mut PointerPress)>,
319 ) {
320 for event in events.read() {
321 match event.action {
322 PointerAction::Press(button) => {
323 pointers
324 .iter_mut()
325 .for_each(|(pointer_id, _, mut pointer)| {
326 if *pointer_id == event.pointer_id {
327 match button {
328 PointerButton::Primary => pointer.primary = true,
329 PointerButton::Secondary => pointer.secondary = true,
330 PointerButton::Middle => pointer.middle = true,
331 }
332 }
333 });
334 }
335 PointerAction::Release(button) => {
336 pointers
337 .iter_mut()
338 .for_each(|(pointer_id, _, mut pointer)| {
339 if *pointer_id == event.pointer_id {
340 match button {
341 PointerButton::Primary => pointer.primary = false,
342 PointerButton::Secondary => pointer.secondary = false,
343 PointerButton::Middle => pointer.middle = false,
344 }
345 }
346 });
347 }
348 PointerAction::Move { .. } => {
349 pointers.iter_mut().for_each(|(id, mut pointer, _)| {
350 if *id == event.pointer_id {
351 pointer.location = Some(event.location.to_owned());
352 }
353 });
354 }
355 _ => {}
356 }
357 }
358 }
359}