1use std::cell::{Cell, RefCell};
2use std::collections::HashMap;
3
4use glam::Vec2;
5use smallvec::SmallVec;
6
7use crate::dom::{Dom, DomNode};
8use crate::event::{Event, EventInterest, EventResponse, WidgetEvent};
9use crate::id::WidgetId;
10use crate::layout::LayoutDom;
11use crate::widget::EventContext;
12
13use super::mouse::MouseButton;
14use super::{KeyCode, Modifiers};
15
16#[derive(Debug)]
19pub struct InputState {
20 mouse: RefCell<Mouse>,
22
23 modifiers: Cell<Modifiers>,
25
26 intersections: RefCell<Intersections>,
28
29 selection: Cell<Option<WidgetId>>,
31
32 last_selection: Cell<Option<WidgetId>>,
34}
35
36#[derive(Debug)]
37struct Mouse {
38 position: Option<Vec2>,
40
41 buttons: HashMap<MouseButton, ButtonState>,
44}
45
46#[derive(Debug)]
47struct Intersections {
48 mouse_hit: Vec<WidgetId>,
53
54 mouse_entered: Vec<WidgetId>,
58
59 mouse_entered_and_sunk: Vec<WidgetId>,
64
65 #[allow(unused)]
68 mouse_down_in: HashMap<MouseButton, Vec<WidgetId>>,
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub(crate) enum ButtonState {
73 JustDown,
74 Down,
75 JustUp,
76 Up,
77}
78
79impl ButtonState {
80 pub fn is_down(&self) -> bool {
81 matches!(self, Self::JustDown | Self::Down)
82 }
83
84 pub fn settle(&mut self) {
85 match self {
86 Self::JustDown => {
87 *self = Self::Down;
88 }
89 Self::JustUp => {
90 *self = Self::Up;
91 }
92 _ => (),
93 }
94 }
95}
96
97impl InputState {
98 pub fn new() -> Self {
100 Self {
101 mouse: RefCell::new(Mouse {
102 position: None,
103 buttons: HashMap::new(),
104 }),
105 modifiers: Cell::new(Modifiers::default()),
106 intersections: RefCell::new(Intersections {
107 mouse_hit: Vec::new(),
108 mouse_entered: Vec::new(),
109 mouse_entered_and_sunk: Vec::new(),
110 mouse_down_in: HashMap::new(),
111 }),
112 last_selection: Cell::new(None),
113 selection: Cell::new(None),
114 }
115 }
116
117 pub fn start(&self, dom: &Dom, layout: &LayoutDom) {
119 self.notify_selection(dom, layout);
120 }
121
122 pub fn finish(&self) {
124 self.settle_buttons();
125 }
126
127 pub fn selection(&self) -> Option<WidgetId> {
129 self.selection.get()
130 }
131
132 pub fn set_selection(&self, id: Option<WidgetId>) {
134 self.selection.set(id);
135 }
136
137 pub(crate) fn handle_event(
138 &self,
139 dom: &Dom,
140 layout: &LayoutDom,
141 event: &Event,
142 ) -> EventResponse {
143 match event {
144 Event::CursorMoved(pos) => {
145 self.mouse_moved(dom, layout, *pos);
146 EventResponse::Bubble
147 }
148 Event::MouseButtonChanged { button, down } => {
149 let response = self.mouse_button_changed(dom, layout, *button, *down);
150
151 if response == EventResponse::Bubble {
159 if *button == MouseButton::One && *down {
160 self.set_selection(None);
161 self.notify_selection(dom, layout);
162 }
163 }
164
165 response
166 }
167 Event::MouseScroll { delta } => self.send_mouse_scroll(dom, layout, *delta),
168 Event::KeyChanged { key, down } => self.keyboard_key_changed(dom, layout, *key, *down),
169 Event::ModifiersChanged(modifiers) => self.modifiers_changed(modifiers),
170 Event::TextInput(c) => self.text_input(dom, layout, *c),
171 _ => EventResponse::Bubble,
172 }
173 }
174
175 fn notify_selection(&self, dom: &Dom, layout: &LayoutDom) {
176 let mut current = self.selection.get();
177 let last = self.last_selection.get();
178
179 if current == last {
180 return;
181 }
182
183 if let Some(entered) = current {
184 if let Some(mut node) = dom.get_mut(entered) {
185 self.fire_event(
186 dom,
187 layout,
188 entered,
189 &mut node,
190 &WidgetEvent::FocusChanged(true),
191 );
192 } else {
193 self.selection.set(None);
194 current = None;
195 }
196 }
197
198 if let Some(left) = last {
199 if let Some(mut node) = dom.get_mut(left) {
200 self.fire_event(
201 dom,
202 layout,
203 left,
204 &mut node,
205 &WidgetEvent::FocusChanged(false),
206 );
207 }
208 }
209
210 self.last_selection.set(current);
211 }
212
213 fn mouse_moved(&self, dom: &Dom, layout: &LayoutDom, pos: Option<Vec2>) {
215 let pos = pos.map(|pos| pos - layout.unscaled_viewport().pos());
216
217 {
218 let mut mouse = self.mouse.borrow_mut();
219 mouse.position = pos;
220 }
221
222 self.send_mouse_move(dom, layout);
223 self.mouse_hit_test(dom, layout);
224 self.send_mouse_enter(dom, layout);
225 self.send_mouse_leave(dom, layout);
226 }
227
228 fn mouse_button_changed(
230 &self,
231 dom: &Dom,
232 layout: &LayoutDom,
233 button: MouseButton,
234 down: bool,
235 ) -> EventResponse {
236 {
237 let mut mouse = self.mouse.borrow_mut();
238 let state = mouse.buttons.entry(button).or_insert(ButtonState::Up);
239
240 match (state.is_down(), down) {
241 (true, true) | (false, false) => (),
244
245 (false, true) => {
246 *state = ButtonState::JustDown;
247 }
248
249 (true, false) => {
250 *state = ButtonState::JustUp;
251 }
252 }
253 }
254
255 self.send_button_change(dom, layout, button, down)
256 }
257
258 fn keyboard_key_changed(
259 &self,
260 dom: &Dom,
261 layout: &LayoutDom,
262 key: KeyCode,
263 down: bool,
264 ) -> EventResponse {
265 let selected = self.selection.get();
266 if let Some(id) = selected {
267 let Some(layout_node) = layout.get(id) else {
268 return EventResponse::Bubble;
269 };
270
271 if layout_node
272 .event_interest
273 .contains(EventInterest::FOCUSED_KEYBOARD)
274 {
275 let mut node = dom.get_mut(id).unwrap();
278 let event = WidgetEvent::KeyChanged {
279 key,
280 down,
281 modifiers: self.modifiers.get(),
282 };
283 return self.fire_event(dom, layout, id, &mut node, &event);
284 }
285 }
286
287 EventResponse::Bubble
288 }
289
290 fn modifiers_changed(&self, modifiers: &Modifiers) -> EventResponse {
291 self.modifiers.set(*modifiers);
292 EventResponse::Bubble
293 }
294
295 fn text_input(&self, dom: &Dom, layout: &LayoutDom, c: char) -> EventResponse {
296 let selected = self.selection.get();
297 if let Some(id) = selected {
298 let Some(layout_node) = layout.get(id) else {
299 return EventResponse::Bubble;
300 };
301
302 if layout_node
303 .event_interest
304 .contains(EventInterest::FOCUSED_KEYBOARD)
305 {
306 let mut node = dom.get_mut(id).unwrap();
309 let event = WidgetEvent::TextInput(c);
310 return self.fire_event(dom, layout, id, &mut node, &event);
311 }
312 }
313
314 EventResponse::Bubble
315 }
316
317 fn send_button_change(
318 &self,
319 dom: &Dom,
320 layout: &LayoutDom,
321 button: MouseButton,
322 down: bool,
323 ) -> EventResponse {
324 let mouse = self.mouse.borrow();
325 let intersections = self.intersections.borrow();
326 let mut overall_response = EventResponse::Bubble;
327
328 for &id in &intersections.mouse_hit {
329 if let Some(mut node) = dom.get_mut(id) {
330 let event = WidgetEvent::MouseButtonChanged {
331 button,
332 down,
333 inside: true,
334 position: mouse.position.unwrap_or(Vec2::ZERO) / layout.scale_factor(),
335 modifiers: self.modifiers.get(),
336 };
337 let response = self.fire_event(dom, layout, id, &mut node, &event);
338
339 if response == EventResponse::Sink {
340 overall_response = response;
341 break;
342 }
343 }
344 }
345
346 for (id, interest) in layout.interest_mouse.iter() {
347 if interest.contains(EventInterest::MOUSE_OUTSIDE)
348 && !intersections.mouse_hit.contains(&id)
349 {
350 if let Some(mut node) = dom.get_mut(id) {
351 let event = WidgetEvent::MouseButtonChanged {
352 button,
353 down,
354 inside: false,
355 position: mouse.position.unwrap_or(Vec2::ZERO) / layout.scale_factor(),
356 modifiers: self.modifiers.get(),
357 };
358 self.fire_event(dom, layout, id, &mut node, &event);
359 }
360 }
361 }
362
363 overall_response
364 }
365
366 fn send_mouse_scroll(&self, dom: &Dom, layout: &LayoutDom, delta: Vec2) -> EventResponse {
367 let intersections = self.intersections.borrow();
368
369 let mut overall_response = EventResponse::Bubble;
370
371 for &id in &intersections.mouse_hit {
372 if let Some(mut node) = dom.get_mut(id) {
373 let event = WidgetEvent::MouseScroll { delta };
374 let response = self.fire_event(dom, layout, id, &mut node, &event);
375
376 if response == EventResponse::Sink {
377 overall_response = response;
378 break;
379 }
380 }
381 }
382
383 overall_response
384 }
385
386 fn send_mouse_move(&self, dom: &Dom, layout: &LayoutDom) {
387 let mouse = self.mouse.borrow();
388 let pos = mouse.position.map(|pos| pos / layout.scale_factor());
389 let event = WidgetEvent::MouseMoved(pos);
390
391 for (id, interest) in layout.interest_mouse.iter() {
392 if interest.intersects(EventInterest::MOUSE_MOVE) {
393 if let Some(mut node) = dom.get_mut(id) {
394 self.fire_event(dom, layout, id, &mut node, &event);
395 }
396 }
397 }
398 }
399
400 fn send_mouse_enter(&self, dom: &Dom, layout: &LayoutDom) {
401 let mut intersections = self.intersections.borrow_mut();
402 let intersections = &mut *intersections;
403
404 for &hit in &intersections.mouse_hit {
405 if let Some(mut node) = dom.get_mut(hit) {
406 if !intersections.mouse_entered.contains(&hit) {
407 intersections.mouse_entered.push(hit);
408
409 let response =
410 self.fire_event(dom, layout, hit, &mut node, &WidgetEvent::MouseEnter);
411
412 if response == EventResponse::Sink {
413 intersections.mouse_entered_and_sunk.push(hit);
414 break;
415 }
416 } else if intersections.mouse_entered_and_sunk.contains(&hit) {
417 break;
422 }
423 }
424 }
425 }
426
427 fn send_mouse_leave(&self, dom: &Dom, layout: &LayoutDom) {
428 let mut intersections = self.intersections.borrow_mut();
429
430 let mut to_remove = SmallVec::<[WidgetId; 4]>::new();
431
432 for &hit in &intersections.mouse_entered {
433 if !intersections.mouse_hit.contains(&hit) {
434 if let Some(mut node) = dom.get_mut(hit) {
435 self.fire_event(dom, layout, hit, &mut node, &WidgetEvent::MouseLeave);
436 }
437
438 to_remove.push(hit);
439 }
440 }
441
442 for remove in to_remove {
443 intersections.mouse_entered.retain(|&id| id != remove);
444 intersections
445 .mouse_entered_and_sunk
446 .retain(|&id| id != remove);
447 }
448 }
449
450 fn mouse_hit_test(&self, dom: &Dom, layout: &LayoutDom) {
451 let mut intersections = self.intersections.borrow_mut();
452 let mouse = self.mouse.borrow();
453
454 intersections.mouse_hit.clear();
455
456 if let Some(mut mouse_pos) = mouse.position {
457 mouse_pos /= layout.scale_factor();
458 hit_test(dom, layout, mouse_pos, &mut intersections.mouse_hit);
459 }
460 }
461
462 fn settle_buttons(&self) {
463 let mut mouse = self.mouse.borrow_mut();
464
465 for state in mouse.buttons.values_mut() {
466 state.settle();
467 }
468 }
469
470 fn fire_event(
474 &self,
475 dom: &Dom,
476 layout: &LayoutDom,
477 id: WidgetId,
478 node: &mut DomNode,
479 event: &WidgetEvent,
480 ) -> EventResponse {
481 let context = EventContext {
482 dom,
483 layout,
484 input: self,
485 };
486
487 dom.enter(id);
488 let response = node.widget.event(context, event);
489 dom.exit(id);
490
491 response
492 }
493}
494
495#[profiling::function]
496fn hit_test(_dom: &Dom, layout: &LayoutDom, coords: Vec2, output: &mut Vec<WidgetId>) {
497 for (id, _interest) in layout.interest_mouse.iter() {
498 let Some(layout_node) = layout.get(id) else {
499 continue;
500 };
501
502 let mut rect = layout_node.rect;
503 let mut node = layout_node;
504 while let Some(parent) = node.clipped_by {
505 node = layout.get(parent).unwrap();
506 rect = rect.constrain(node.rect);
507 }
508
509 if rect.contains_point(coords) {
510 output.push(id);
511 }
512 }
513}