1use core::ops::{Div, Mul};
4
5use crate::{touch::TouchPhase, ButtonInput, ButtonState};
6#[cfg(feature = "bevy_reflect")]
7use bevy_ecs::prelude::ReflectMessage;
8use bevy_ecs::{
9 change_detection::DetectChangesMut,
10 entity::Entity,
11 message::{Message, MessageReader},
12 resource::Resource,
13 system::ResMut,
14};
15use bevy_math::Vec2;
16use derive_more::{Deref, DerefMut};
17
18#[cfg(feature = "bevy_reflect")]
19use {
20 bevy_ecs::reflect::ReflectResource,
21 bevy_reflect::{std_traits::ReflectDefault, Reflect},
22};
23
24#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
25use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
26
27#[derive(Message, Debug, Clone, Copy, PartialEq, Eq)]
36#[cfg_attr(
37 feature = "bevy_reflect",
38 derive(Reflect),
39 reflect(Debug, PartialEq, Clone, Message)
40)]
41#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
42#[cfg_attr(
43 all(feature = "serialize", feature = "bevy_reflect"),
44 reflect(Serialize, Deserialize)
45)]
46pub struct MouseButtonInput {
47 pub button: MouseButton,
49 pub state: ButtonState,
51 pub window: Entity,
53}
54
55#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
66#[cfg_attr(
67 feature = "bevy_reflect",
68 derive(Reflect),
69 reflect(Debug, Hash, PartialEq, Clone)
70)]
71#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
72#[cfg_attr(
73 all(feature = "serialize", feature = "bevy_reflect"),
74 reflect(Serialize, Deserialize)
75)]
76pub enum MouseButton {
77 Left,
79 Right,
81 Middle,
83 Back,
85 Forward,
87 Other(u16),
89}
90
91#[derive(Message, Debug, Clone, Copy, PartialEq)]
101#[cfg_attr(
102 feature = "bevy_reflect",
103 derive(Reflect),
104 reflect(Debug, PartialEq, Clone, Message)
105)]
106#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
107#[cfg_attr(
108 all(feature = "serialize", feature = "bevy_reflect"),
109 reflect(Serialize, Deserialize)
110)]
111pub struct MouseMotion {
112 pub delta: Vec2,
114}
115
116#[derive(Debug, Hash, Clone, Copy, Eq, PartialEq)]
125#[cfg_attr(
126 feature = "bevy_reflect",
127 derive(Reflect),
128 reflect(Debug, PartialEq, Clone)
129)]
130#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
131#[cfg_attr(
132 all(feature = "serialize", feature = "bevy_reflect"),
133 reflect(Serialize, Deserialize)
134)]
135pub enum MouseScrollUnit {
136 Line,
141 Pixel,
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Resource, Deref, DerefMut)]
155#[cfg_attr(
156 feature = "bevy_reflect",
157 derive(Reflect),
158 reflect(Debug, PartialEq, Clone)
159)]
160#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
161#[cfg_attr(
162 all(feature = "serialize", feature = "bevy_reflect"),
163 reflect(Serialize, Deserialize)
164)]
165pub struct MouseScrollPixelsPerLine(f32);
166
167impl Default for MouseScrollPixelsPerLine {
168 fn default() -> Self {
169 MouseScrollPixelsPerLine(100.0)
170 }
171}
172
173impl Mul<MouseScrollPixelsPerLine> for f32 {
174 type Output = f32;
175 fn mul(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
176 self * rhs.0
177 }
178}
179
180impl Div<MouseScrollPixelsPerLine> for f32 {
181 type Output = f32;
182 fn div(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
183 self / rhs.0
184 }
185}
186
187impl Mul<MouseScrollPixelsPerLine> for Vec2 {
188 type Output = Vec2;
189 fn mul(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
190 self * rhs.0
191 }
192}
193
194impl Div<MouseScrollPixelsPerLine> for Vec2 {
195 type Output = Vec2;
196 fn div(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
197 self / rhs.0
198 }
199}
200#[derive(Message, Debug, Clone, Copy, PartialEq)]
204#[cfg_attr(
205 feature = "bevy_reflect",
206 derive(Reflect),
207 reflect(Debug, PartialEq, Clone, Message)
208)]
209#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
210#[cfg_attr(
211 all(feature = "serialize", feature = "bevy_reflect"),
212 reflect(Serialize, Deserialize)
213)]
214pub struct MouseWheel {
215 pub unit: MouseScrollUnit,
217 pub x: f32,
219 pub y: f32,
221 pub window: Entity,
223 pub phase: TouchPhase,
227}
228
229pub fn mouse_button_input_system(
236 mut mouse_button_input: ResMut<ButtonInput<MouseButton>>,
237 mut mouse_button_input_events: MessageReader<MouseButtonInput>,
238) {
239 mouse_button_input.bypass_change_detection().clear();
240 for event in mouse_button_input_events.read() {
241 match event.state {
242 ButtonState::Pressed => mouse_button_input.press(event.button),
243 ButtonState::Released => mouse_button_input.release(event.button),
244 }
245 }
246}
247
248#[derive(Resource, Debug, Clone, Copy, PartialEq, Default)]
254#[cfg_attr(
255 feature = "bevy_reflect",
256 derive(Reflect),
257 reflect(Debug, Default, Resource, PartialEq, Clone)
258)]
259#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
260#[cfg_attr(
261 all(feature = "serialize", feature = "bevy_reflect"),
262 reflect(Serialize, Deserialize)
263)]
264pub struct AccumulatedMouseMotion {
265 pub delta: Vec2,
267}
268
269#[derive(Resource, Debug, Clone, Copy, PartialEq)]
275#[cfg_attr(
276 feature = "bevy_reflect",
277 derive(Reflect),
278 reflect(Debug, Default, Resource, PartialEq, Clone)
279)]
280#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
281#[cfg_attr(
282 all(feature = "serialize", feature = "bevy_reflect"),
283 reflect(Serialize, Deserialize)
284)]
285pub struct AccumulatedMouseScroll {
286 pub unit: MouseScrollUnit,
290 pub delta: Vec2,
292}
293
294impl Default for AccumulatedMouseScroll {
295 fn default() -> Self {
296 Self {
297 unit: MouseScrollUnit::Line,
298 delta: Vec2::ZERO,
299 }
300 }
301}
302
303impl AccumulatedMouseScroll {
304 pub fn to_lines(&self, conversion_ratio: &MouseScrollPixelsPerLine) -> Self {
306 if self.unit == MouseScrollUnit::Pixel {
307 AccumulatedMouseScroll {
308 unit: MouseScrollUnit::Line,
309 delta: self.delta / *conversion_ratio,
310 }
311 } else {
312 *self
313 }
314 }
315 pub fn to_pixels(&self, conversion_ratio: &MouseScrollPixelsPerLine) -> Self {
317 if self.unit == MouseScrollUnit::Line {
318 AccumulatedMouseScroll {
319 unit: MouseScrollUnit::Pixel,
320 delta: self.delta * *conversion_ratio,
321 }
322 } else {
323 *self
324 }
325 }
326}
327
328pub fn accumulate_mouse_motion_system(
331 mut mouse_motion_event: MessageReader<MouseMotion>,
332 mut accumulated_mouse_motion: ResMut<AccumulatedMouseMotion>,
333) {
334 let mut delta = Vec2::ZERO;
335 for event in mouse_motion_event.read() {
336 delta += event.delta;
337 }
338 accumulated_mouse_motion.delta = delta;
339}
340
341pub fn accumulate_mouse_scroll_system(
344 mut mouse_scroll_event: MessageReader<MouseWheel>,
345 mut accumulated_mouse_scroll: ResMut<AccumulatedMouseScroll>,
346) {
347 let mut delta = Vec2::ZERO;
348 let mut unit = MouseScrollUnit::Line;
349 for event in mouse_scroll_event.read() {
350 if event.unit != unit {
351 unit = event.unit;
352 }
353 delta += Vec2::new(event.x, event.y);
354 }
355 accumulated_mouse_scroll.delta = delta;
356 accumulated_mouse_scroll.unit = unit;
357}