1use crate::context::{InternalEvent, ResourceContext};
2use crate::events::EventMeta;
3use crate::prelude::*;
4#[cfg(debug_assertions)]
5use crate::systems::compute_matched_rules;
6use crate::systems::{binding_system, hover_system};
7use crate::tree::{focus_backward, focus_forward, is_navigatable};
8#[cfg(debug_assertions)]
9use log::debug;
10use std::any::Any;
11use vizia_storage::LayoutParentIterator;
12#[cfg(debug_assertions)]
13use vizia_storage::ParentIterator;
14use vizia_storage::TreeIterator;
15
16#[doc(hidden)]
21pub struct EventManager {
22 event_queue: Vec<Event>,
24}
25
26impl Default for EventManager {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl EventManager {
33 pub fn new() -> Self {
34 EventManager { event_queue: Vec::with_capacity(10) }
35 }
36
37 pub fn flush_events(
40 &mut self,
41 cx: &mut Context,
42 mut window_event_callback: impl FnMut(&WindowEvent),
43 ) {
44 while {
45 self.event_queue.clear();
47
48 self.event_queue.extend(cx.event_queue.drain(0..));
51
52 'events: for event in self.event_queue.iter_mut() {
54 let keyboard_lock_root = keyboard_event_lock_root(cx, event);
55
56 event.take(|internal_event, _| match internal_event {
58 InternalEvent::Redraw => cx.needs_redraw(Entity::root()),
59 InternalEvent::LoadImage { path, image, policy } => {
60 if let Some(image) = image.lock().unwrap().take() {
61 ResourceContext::new(cx).load_image(path, image, policy);
62 }
63 }
64 });
65
66 let mut global_listeners = vec![];
68 std::mem::swap(&mut cx.global_listeners, &mut global_listeners);
69 for listener in &global_listeners {
70 cx.with_current(Entity::root(), |cx| {
71 listener(&mut EventContext::new(cx), event)
72 });
73 }
74 std::mem::swap(&mut cx.global_listeners, &mut global_listeners);
75
76 let listeners = cx.listeners.keys().copied().collect::<Vec<Entity>>();
78 for entity in listeners {
79 if let Some(lock_root) = keyboard_lock_root {
80 if !entity.is_descendant_of(&cx.tree, lock_root) {
81 continue;
82 }
83 }
84
85 if let Some(listener) = cx.listeners.remove(&entity) {
86 if let Some(mut event_handler) = cx.views.remove(&entity) {
87 cx.with_current(entity, |cx| {
88 (listener)(
89 event_handler.as_mut(),
90 &mut EventContext::new(cx),
91 event,
92 );
93 });
94
95 cx.views.insert(entity, event_handler);
96 }
97
98 cx.listeners.insert(entity, listener);
99 }
100
101 if event.meta.consumed {
102 continue 'events;
103 }
104 }
105
106 event.map(|window_event, meta| {
108 if cx.windows.contains_key(&meta.origin) {
109 internal_state_updates(cx, window_event, meta);
110 }
111 });
112
113 if event.meta.consumed {
115 continue 'events;
116 }
117
118 let cx = &mut EventContext::new(cx);
119
120 let target = event.meta.target;
122
123 if keyboard_lock_root
125 .map(|lock_root| target.is_descendant_of(cx.tree, lock_root))
126 .unwrap_or(true)
127 {
128 visit_entity(cx, target, event);
129 }
130
131 if event.meta.consumed {
133 continue 'events;
134 }
135
136 if event.meta.propagation == Propagation::Up {
138 let iter = target.parent_iter(cx.tree).skip(1);
140
141 for entity in iter {
142 if let Some(lock_root) = keyboard_lock_root {
143 if !entity.is_descendant_of(cx.tree, lock_root) {
144 break;
145 }
146 }
147
148 visit_entity(cx, entity, event);
150
151 if event.meta.consumed {
153 continue 'events;
154 }
155 }
156 }
157
158 if event.meta.propagation == Propagation::Subtree {
160 let iter = target.branch_iter(cx.tree).skip(1);
162
163 for entity in iter {
164 if keyboard_lock_root
165 .map(|lock_root| entity.is_descendant_of(cx.tree, lock_root))
166 .unwrap_or(true)
167 {
168 visit_entity(cx, entity, event);
170 }
171
172 if event.meta.consumed {
174 continue 'events;
175 }
176 }
177 }
178
179 event.map(|window_event: &WindowEvent, _| {
180 (window_event_callback)(window_event);
181 });
182 }
183
184 binding_system(cx);
185
186 !cx.event_queue.is_empty()
188 } {}
189 }
190}
191fn is_keyboard_window_event(window_event: &WindowEvent) -> bool {
192 matches!(
193 window_event,
194 WindowEvent::KeyDown(_, _)
195 | WindowEvent::KeyUp(_, _)
196 | WindowEvent::CharInput(_)
197 | WindowEvent::ImeActivate(_)
198 | WindowEvent::ImeCommit(_)
199 | WindowEvent::ImePreedit(_, _)
200 | WindowEvent::SetImeCursorArea(_, _)
201 )
202}
203
204fn keyboard_event_lock_root(cx: &Context, event: &mut Event) -> Option<Entity> {
205 let mut lock_root = None;
206
207 event.map(|window_event: &WindowEvent, _| {
208 if is_keyboard_window_event(window_event) {
209 let candidate = cx.tree.lock_focus_within(cx.focused);
210 if candidate != Entity::root() {
211 lock_root = Some(candidate);
212 }
213 }
214 });
215
216 lock_root
217}
218
219fn visit_entity(cx: &mut EventContext, entity: Entity, event: &mut Event) {
220 if let Some(ids) =
222 cx.models.get(&entity).map(|models| models.keys().cloned().collect::<Vec<_>>())
223 {
224 for id in ids {
225 if let Some(mut model) =
226 cx.models.get_mut(&entity).and_then(|models| models.remove(&id))
227 {
228 cx.current = entity;
229
230 model.event(cx, event);
231
232 cx.models.get_mut(&entity).and_then(|models| models.insert(id, model));
233 }
234 }
235 }
236
237 if event.meta.consumed {
239 return;
240 }
241
242 if let Some(mut view) = cx.views.remove(&entity) {
244 cx.current = entity;
245 view.event(cx, event);
246
247 cx.views.insert(entity, view);
248 }
249}
250
251fn internal_state_updates(cx: &mut Context, window_event: &WindowEvent, meta: &mut EventMeta) {
253 cx.current = meta.target;
254
255 match window_event {
256 WindowEvent::Drop(drop_data) => {
257 cx.drop_data = Some(drop_data.clone());
258 }
259
260 WindowEvent::MouseMove(x, y) => {
261 if !x.is_nan() && !y.is_nan() {
262 cx.mouse.previous_cursor_x = cx.mouse.cursor_x;
263 cx.mouse.previous_cursor_y = cx.mouse.cursor_y;
264 cx.mouse.cursor_x = *x;
265 cx.mouse.cursor_y = *y;
266
267 hover_system(cx, meta.origin);
268
269 mutate_direct_or_up(meta, cx.captured, cx.hovered, false);
270 }
271
272 }
287 WindowEvent::MouseDown(button) => {
288 match button {
290 MouseButton::Left => {
291 cx.mouse.left.state = MouseButtonState::Pressed;
292
293 cx.mouse.left.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
294 cx.mouse.left.pressed = cx.hovered;
295 cx.triggered = cx.hovered;
296
297 let disabled = cx.style.disabled.get(cx.hovered).copied().unwrap_or_default();
298
299 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
300 if !disabled {
301 pseudo_classes.set(PseudoClassFlags::ACTIVE, true);
302 cx.needs_restyle(cx.triggered);
303 }
304 }
305 let focusable = cx
306 .style
307 .abilities
308 .get(cx.hovered)
309 .filter(|abilities| abilities.contains(Abilities::FOCUSABLE))
310 .is_some();
311
312 cx.drop_data = None;
314
315 cx.with_current(if focusable { cx.hovered } else { cx.focused }, |cx| {
316 cx.focus_with_visibility(false)
317 });
318 }
319 MouseButton::Right => {
320 cx.mouse.right.state = MouseButtonState::Pressed;
321 cx.mouse.right.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
322 cx.mouse.right.pressed = cx.hovered;
323 }
324 MouseButton::Middle => {
325 cx.mouse.middle.state = MouseButtonState::Pressed;
326 cx.mouse.middle.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
327 cx.mouse.middle.pressed = cx.hovered;
328 }
329 _ => {}
330 }
331
332 if matches!(button, MouseButton::Left) {
334 emit_direct_or_up(
335 cx,
336 WindowEvent::PressDown { mouse: true },
337 cx.captured,
338 cx.triggered,
339 true,
340 );
341 }
342
343 let new_click_time = Instant::now();
345 let click_duration = new_click_time - cx.click_time;
346 let new_click_pos = (cx.mouse.cursor_x, cx.mouse.cursor_y);
347 let double_click_interval = cx.environment().double_click_interval;
348 if click_duration <= double_click_interval
349 && new_click_pos == cx.click_pos
350 && *button == cx.click_button
351 {
352 if cx.clicks <= 2 {
353 cx.clicks += 1;
354 let event = if cx.clicks == 3 {
355 WindowEvent::MouseTripleClick(*button)
356 } else {
357 WindowEvent::MouseDoubleClick(*button)
358 };
359 meta.consume();
360 emit_direct_or_up(cx, event, cx.captured, cx.hovered, true);
361 }
362 } else {
363 cx.clicks = 1;
364 }
365 cx.click_time = new_click_time;
366 cx.click_pos = new_click_pos;
367 cx.click_button = *button;
368 mutate_direct_or_up(meta, cx.captured, cx.hovered, true);
369 }
370 WindowEvent::MouseUp(button) => {
371 match button {
372 MouseButton::Left => {
373 cx.mouse.left.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
374 cx.mouse.left.released = cx.hovered;
375 cx.mouse.left.state = MouseButtonState::Released;
376 }
377 MouseButton::Right => {
378 cx.mouse.right.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
379 cx.mouse.right.released = cx.hovered;
380 cx.mouse.right.state = MouseButtonState::Released;
381 }
382 MouseButton::Middle => {
383 cx.mouse.middle.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
384 cx.mouse.middle.released = cx.hovered;
385 cx.mouse.middle.state = MouseButtonState::Released;
386 }
387 _ => {}
388 }
389
390 if matches!(button, MouseButton::Left) {
391 if cx.hovered == cx.triggered {
392 let disabled = cx.style.disabled.get(cx.hovered).copied().unwrap_or_default();
393
394 if !disabled {
395 emit_direct_or_up(
396 cx,
397 WindowEvent::Press { mouse: true },
398 cx.captured,
399 cx.triggered,
400 true,
401 );
402 }
403 }
404
405 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
406 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
407 }
408
409 cx.needs_restyle(cx.triggered);
410
411 cx.triggered = Entity::null();
412 }
413
414 mutate_direct_or_up(meta, cx.captured, cx.hovered, true);
415 }
416 WindowEvent::MouseScroll(_, _) => {
417 meta.target = cx.hovered;
418 }
419 WindowEvent::KeyDown(code, _) => {
420 meta.target = cx.focused;
421
422 #[cfg(debug_assertions)]
423 if *code == Code::KeyP && cx.modifiers.ctrl() {
424 for entity in TreeIterator::full(&cx.tree) {
425 if let Some(models) = cx.models.get(&entity) {
426 if !models.is_empty() {
427 debug!("Models for {}", entity);
428 for (_, model) in models.iter() {
429 debug!("M: {:?}", model.name())
430 }
431 }
432 }
433 }
434 }
435
436 #[cfg(debug_assertions)]
437 if *code == Code::KeyI {
438 debug!("Entity tree");
439 let (tree, views, cache) = (&cx.tree, &cx.views, &cx.cache);
440 let has_next_sibling = |entity| tree.get_next_sibling(entity).is_some();
441 let root_indents = |entity: Entity| {
442 let parent_iter = ParentIterator::new(tree, Some(entity));
443 parent_iter
444 .skip(1)
445 .collect::<Vec<_>>()
446 .into_iter()
447 .rev()
448 .skip(1)
449 .map(|entity| if has_next_sibling(entity) { "│ " } else { " " })
450 .collect::<String>()
451 };
452 let local_idents =
453 |entity| if has_next_sibling(entity) { "├── " } else { "└── " };
454 let indents = |entity| root_indents(entity) + local_idents(entity);
455
456 for entity in TreeIterator::full(tree).skip(1) {
457 if let Some(element_name) = views.get(&entity).and_then(|view| view.element()) {
458 let w = cache.get_bounds(entity).w;
459 let h = cache.get_bounds(entity).h;
460 let classes = cx.style.classes.get(entity);
461 let mut class_names = String::new();
462 if let Some(classes) = classes {
463 for class in classes.iter() {
464 class_names += &format!(".{}", class);
465 }
466 }
467 println!(
468 "{}{} {}{} [x: {} y: {} w: {} h: {}]",
469 indents(entity),
470 entity,
471 element_name,
472 class_names,
473 cache.get_bounds(entity).x,
474 cache.get_bounds(entity).y,
475 if w == f32::MAX { "inf".to_string() } else { w.to_string() },
476 if h == f32::MAX { "inf".to_string() } else { h.to_string() },
477 );
478 } else if let Some(binding_name) =
479 cx.bindings.get(&entity).map(|binding| format!("{:?}", binding))
480 {
481 println!(
482 "{}{} binding observing {}",
483 indents(entity),
484 entity,
485 binding_name,
486 );
487 } else {
488 println!(
489 "{}{} {}",
490 indents(entity),
491 entity,
492 if views.get(&entity).is_some() {
493 "unnamed view"
494 } else {
495 "no binding or view"
496 }
497 );
498 }
499 }
500 }
501
502 #[cfg(debug_assertions)]
503 if *code == Code::KeyS
504 && cx.modifiers == Modifiers::CTRL | Modifiers::SHIFT | Modifiers::ALT
505 {
506 use crate::systems::compute_element_hash;
507 use vizia_style::selectors::bloom::BloomFilter;
508
509 let mut filter = BloomFilter::default();
510 compute_element_hash(cx.hovered, &cx.tree, &cx.style, &mut filter);
511 let result = compute_matched_rules(cx.hovered, &cx.style, &cx.tree, &filter);
512
513 let entity = cx.hovered;
514 debug!(
515 "/* Matched rules for Entity: {} Parent: {:?} View: {} posx: {} posy: {} width: {} height: {}",
516 entity,
517 entity.parent(&cx.tree),
518 cx.views
519 .get(&entity)
520 .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
521 cx.cache.get_posx(entity),
522 cx.cache.get_posy(entity),
523 cx.cache.get_width(entity),
524 cx.cache.get_height(entity)
525 );
526 for rule in result.into_iter() {
527 for selectors in cx.style.rules.iter() {
528 if *selectors.0 == rule.0 {
529 debug!("{:?}", selectors.1.selector);
530 }
531 }
532 }
533 }
534
535 #[cfg(debug_assertions)]
536 if *code == Code::KeyT
537 && cx.modifiers == Modifiers::CTRL | Modifiers::SHIFT | Modifiers::ALT
538 {
539 }
552
553 if *code == Code::F5 {
554 EventContext::new(cx).reload_styles().unwrap();
555 }
556
557 if *code == Code::Tab {
558 if cx.ime_state.is_composing() {
559 return;
560 }
561
562 let lock_focus_to = cx.tree.lock_focus_within(cx.focused);
563
564 let effective_lock = if lock_focus_to != Entity::root()
569 && !TreeIterator::full(&cx.tree)
570 .any(|node| is_navigatable(&cx.tree, &cx.style, node, lock_focus_to))
571 {
572 Entity::root()
573 } else {
574 lock_focus_to
575 };
576
577 if cx.modifiers.shift() {
578 let prev_focused = if let Some(prev_focused) =
579 focus_backward(&cx.tree, &cx.style, cx.focused, effective_lock)
580 {
581 prev_focused
582 } else {
583 TreeIterator::full(&cx.tree)
584 .rfind(|node| {
585 is_navigatable(&cx.tree, &cx.style, *node, effective_lock)
586 })
587 .unwrap_or(Entity::root())
588 };
589
590 if prev_focused != cx.focused {
591 cx.set_focus_pseudo_classes(cx.focused, false, true);
592 cx.set_focus_pseudo_classes(prev_focused, true, true);
593 cx.event_queue.push_back(
594 Event::new(WindowEvent::FocusOut)
595 .target(cx.focused)
596 .origin(Entity::root()),
597 );
598 cx.event_queue.push_back(
599 Event::new(WindowEvent::FocusIn)
600 .target(prev_focused)
601 .origin(Entity::root()),
602 );
603 cx.event_queue.push_back(
604 Event::new(ScrollEvent::ScrollToView(prev_focused))
605 .target(prev_focused)
606 .origin(Entity::root()),
607 );
608
609 cx.focused = prev_focused;
610
611 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered)
612 {
613 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
614 cx.needs_restyle(cx.triggered);
615 }
616 cx.triggered = Entity::null();
617 }
618 } else {
619 let next_focused = if let Some(next_focused) =
620 focus_forward(&cx.tree, &cx.style, cx.focused, effective_lock)
621 {
622 next_focused
623 } else {
624 TreeIterator::full(&cx.tree)
625 .find(|node| is_navigatable(&cx.tree, &cx.style, *node, effective_lock))
626 .unwrap_or(Entity::root())
627 };
628
629 if next_focused != cx.focused {
630 cx.set_focus_pseudo_classes(cx.focused, false, true);
631 cx.set_focus_pseudo_classes(next_focused, true, true);
632 cx.event_queue.push_back(
633 Event::new(WindowEvent::FocusOut)
634 .target(cx.focused)
635 .origin(Entity::root()),
636 );
637 cx.event_queue.push_back(
638 Event::new(WindowEvent::FocusIn)
639 .target(next_focused)
640 .origin(Entity::root()),
641 );
642 cx.event_queue.push_back(
643 Event::new(ScrollEvent::ScrollToView(next_focused))
644 .target(next_focused)
645 .origin(Entity::root()),
646 );
647
648 cx.focused = next_focused;
649
650 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered)
651 {
652 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
653 cx.needs_restyle(cx.triggered);
654 }
655 cx.triggered = Entity::null();
656 }
657 }
658 }
659
660 if matches!(*code, Code::Enter | Code::NumpadEnter | Code::Space) {
661 cx.triggered = cx.focused;
662 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
663 pseudo_classes.set(PseudoClassFlags::ACTIVE, true);
664 }
665 cx.with_current(cx.focused, |cx| cx.emit(WindowEvent::PressDown { mouse: false }));
666 }
667 }
668 WindowEvent::KeyUp(code, _) => {
669 meta.target = cx.focused;
670 if matches!(code, Code::Enter | Code::NumpadEnter | Code::Space) {
671 if cx.focused == cx.triggered {
672 cx.with_current(cx.triggered, |cx| {
673 cx.emit(WindowEvent::Press { mouse: false })
674 });
675 }
676 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
677 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
678 }
679 cx.needs_restyle(cx.triggered);
680 cx.triggered = Entity::null();
681 }
682 }
683 WindowEvent::CharInput(_) => {
684 meta.target = cx.focused;
685 }
686 WindowEvent::ImeActivate(_) => {
687 meta.target = cx.focused;
688 }
689 WindowEvent::ImeCommit(_) => {
690 meta.target = cx.focused;
691 }
692 WindowEvent::ImePreedit(_, _) => {
693 meta.target = cx.focused;
694 }
695 WindowEvent::SetImeCursorArea(_, _) => {
696 meta.target = cx.focused;
697 }
698 WindowEvent::WindowFocused(is_focused) => {
699 if *is_focused {
700 cx.set_focus_pseudo_classes(cx.focused, true, true);
701 cx.needs_restyle(cx.focused);
702 cx.needs_redraw(cx.focused);
703 } else {
704 cx.set_focus_pseudo_classes(cx.focused, false, true);
705 cx.needs_restyle(cx.focused);
706
707 cx.event_queue.push_back(
708 Event::new(WindowEvent::FocusVisibility(false))
709 .target(cx.focused)
710 .origin(Entity::root()), );
712
713 cx.event_queue.push_back(
714 Event::new(WindowEvent::MouseOut).target(cx.hovered).origin(Entity::root()), );
716 }
717 }
718 WindowEvent::MouseEnter => {
719 if let Some(pseudo_class) = cx.style.pseudo_classes.get_mut(meta.origin) {
720 pseudo_class.set(PseudoClassFlags::OVER, true);
721 }
722 }
723 WindowEvent::MouseLeave => {
724 if let Some(pseudo_class) = cx.style.pseudo_classes.get_mut(meta.origin) {
725 pseudo_class.set(PseudoClassFlags::OVER, false);
726 }
727
728 let parent_iter = LayoutParentIterator::new(&cx.tree, cx.hovered);
729 for ancestor in parent_iter {
730 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(ancestor) {
731 pseudo_classes.set(PseudoClassFlags::HOVER, false);
732 cx.style.needs_restyle(ancestor);
733 }
734 }
735
736 cx.hovered = Entity::null();
737 }
738
739 _ => {}
740 }
741}
742
743fn mutate_direct_or_up(meta: &mut EventMeta, direct: Entity, up: Entity, root: bool) {
744 if direct != Entity::null() {
745 meta.target = direct;
746 meta.propagation = Propagation::Direct;
747 } else if up != Entity::root() || root {
748 meta.target = up;
749 meta.propagation = Propagation::Up;
750 } else {
751 meta.consume();
752 }
753}
754
755fn emit_direct_or_up<M: Any + Send>(
756 cx: &mut Context,
757 message: M,
758 direct: Entity,
759 up: Entity,
760 root: bool,
761) {
762 let mut event = Event::new(message);
763 mutate_direct_or_up(&mut event.meta, direct, up, root);
764 cx.emit_custom(event);
765}