1use crate::types::Rect;
7use serde::{Deserialize, Serialize};
8
9use super::touch::TouchState;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
17pub enum MouseButton {
18 #[default]
19 Left,
20 Right,
21 Middle,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
30pub struct ModifierKeys {
31 pub shift: bool,
33
34 pub ctrl: bool,
36
37 pub alt: bool,
39
40 pub meta: bool,
42}
43
44impl ModifierKeys {
45 pub fn none() -> Self {
46 Self::default()
47 }
48
49 pub fn shift() -> Self {
50 Self {
51 shift: true,
52 ..Default::default()
53 }
54 }
55
56 pub fn ctrl() -> Self {
57 Self {
58 ctrl: true,
59 ..Default::default()
60 }
61 }
62
63 pub fn any(&self) -> bool {
64 self.shift || self.ctrl || self.alt || self.meta
65 }
66
67 #[inline]
68 pub fn ctrl_shift(&self) -> bool {
69 self.ctrl && self.shift && !self.alt && !self.meta
70 }
71
72 #[inline]
73 pub fn ctrl_alt(&self) -> bool {
74 self.ctrl && self.alt && !self.shift && !self.meta
75 }
76
77 #[inline]
78 pub fn command(&self) -> bool {
79 #[cfg(target_os = "macos")]
80 {
81 self.meta
82 }
83 #[cfg(not(target_os = "macos"))]
84 {
85 self.ctrl
86 }
87 }
88}
89
90#[derive(Clone, Debug, Default)]
96pub struct PointerState {
97 pub pos: Option<(f64, f64)>,
99
100 pub button_down: Option<MouseButton>,
102
103 pub clicked: Option<MouseButton>,
105
106 pub double_clicked: Option<MouseButton>,
108
109 pub triple_clicked: Option<MouseButton>,
111
112 pub prev_pos: Option<(f64, f64)>,
114}
115
116impl PointerState {
117 pub fn delta(&self) -> (f64, f64) {
118 match (self.pos, self.prev_pos) {
119 (Some((x, y)), Some((px, py))) => (x - px, y - py),
120 _ => (0.0, 0.0),
121 }
122 }
123
124 pub fn is_present(&self) -> bool {
125 self.pos.is_some()
126 }
127}
128
129#[derive(Clone, Debug)]
135pub struct DragState {
136 pub start: (f64, f64),
137 pub current: (f64, f64),
138 pub delta: (f64, f64),
139 pub total_delta: (f64, f64),
140 pub button: MouseButton,
141 pub initial_value: f64,
142}
143
144impl DragState {
145 pub fn new(start: (f64, f64), current: (f64, f64), button: MouseButton) -> Self {
146 let total_delta = (current.0 - start.0, current.1 - start.1);
147 Self {
148 start,
149 current,
150 delta: (0.0, 0.0),
151 total_delta,
152 button,
153 initial_value: 0.0,
154 }
155 }
156
157 pub fn update(&mut self, x: f64, y: f64) {
158 self.delta = (x - self.current.0, y - self.current.1);
159 self.current = (x, y);
160 self.total_delta = (self.current.0 - self.start.0, self.current.1 - self.start.1);
161 }
162
163 pub fn is_dragging(&self, _id: &crate::types::state::WidgetId) -> bool {
164 true
166 }
167
168 pub fn delta_tuple(&self) -> (f64, f64) {
169 self.delta
170 }
171}
172
173#[derive(Clone, Debug, Default)]
179pub struct InputState {
180 pub pointer: PointerState,
181 pub modifiers: ModifierKeys,
182 pub scroll_delta: (f64, f64),
183 pub drag: Option<DragState>,
184 pub dt: f64,
185 pub time: f64,
186 pub multi_touch: Option<TouchState>,
187}
188
189impl InputState {
190 pub fn new() -> Self {
191 Self::default()
192 }
193
194 pub fn with_pointer_pos(mut self, x: f64, y: f64) -> Self {
195 self.pointer.pos = Some((x, y));
196 self
197 }
198
199 pub fn pointer_pos(&self) -> Option<(f64, f64)> {
200 self.pointer.pos
201 }
202
203 pub fn is_hovered(&self, rect: &Rect) -> bool {
204 if let Some((px, py)) = self.pointer.pos {
205 rect.contains(px, py)
206 } else {
207 false
208 }
209 }
210
211 pub fn is_clicked(&self) -> bool {
212 self.pointer.clicked == Some(MouseButton::Left)
213 }
214
215 pub fn is_double_clicked(&self) -> bool {
216 self.pointer.double_clicked == Some(MouseButton::Left)
217 }
218
219 pub fn is_middle_clicked(&self) -> bool {
220 self.pointer.clicked == Some(MouseButton::Middle)
221 }
222
223 pub fn is_right_clicked(&self) -> bool {
224 self.pointer.clicked == Some(MouseButton::Right)
225 }
226
227 pub fn is_mouse_down(&self) -> bool {
228 self.pointer.button_down == Some(MouseButton::Left)
229 }
230
231 pub fn is_dragging(&self) -> bool {
232 self.drag.is_some()
233 }
234
235 pub fn drag_delta(&self) -> Option<(f64, f64)> {
236 self.drag.as_ref().map(|d| d.delta)
237 }
238
239 pub fn shift(&self) -> bool {
240 self.modifiers.shift
241 }
242
243 pub fn ctrl(&self) -> bool {
244 self.modifiers.ctrl
245 }
246
247 pub fn alt(&self) -> bool {
248 self.modifiers.alt
249 }
250
251 pub fn consume_click(&mut self) -> bool {
252 if self.pointer.clicked.is_some() {
253 self.pointer.clicked = None;
254 true
255 } else {
256 false
257 }
258 }
259
260 pub fn consume_scroll(&mut self) -> (f64, f64) {
261 let delta = self.scroll_delta;
262 self.scroll_delta = (0.0, 0.0);
263 delta
264 }
265
266 pub fn touch_count(&self) -> usize {
268 self.multi_touch
269 .as_ref()
270 .map(|t| t.touch_count())
271 .unwrap_or(0)
272 }
273
274 pub fn primary_pointer(&self) -> Option<(f64, f64)> {
275 self.pointer.pos.or_else(|| {
276 self.multi_touch
277 .as_ref()
278 .and_then(|t| t.primary_touch())
279 .map(|t| t.pos)
280 })
281 }
282
283 pub fn end_frame(&mut self) {
284 self.pointer.clicked = None;
285 self.pointer.double_clicked = None;
286 self.pointer.triple_clicked = None;
287 self.pointer.prev_pos = self.pointer.pos;
288 if let Some(ref mut touch) = self.multi_touch {
289 touch.clear_deltas();
290 }
291 }
292}