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
16const DOUBLE_CLICK_INTERVAL: Duration = Duration::from_millis(500);
17
18#[doc(hidden)]
23pub struct EventManager {
24 event_queue: Vec<Event>,
26}
27
28impl Default for EventManager {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl EventManager {
35 pub fn new() -> Self {
36 EventManager { event_queue: Vec::with_capacity(10) }
37 }
38
39 pub fn flush_events(
42 &mut self,
43 cx: &mut Context,
44 mut window_event_callback: impl FnMut(&WindowEvent),
45 ) {
46 while {
47 self.event_queue.clear();
49
50 self.event_queue.extend(cx.event_queue.drain(0..));
53
54 'events: for event in self.event_queue.iter_mut() {
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(listener) = cx.listeners.remove(&entity) {
80 if let Some(mut event_handler) = cx.views.remove(&entity) {
81 cx.with_current(entity, |cx| {
82 (listener)(
83 event_handler.as_mut(),
84 &mut EventContext::new(cx),
85 event,
86 );
87 });
88
89 cx.views.insert(entity, event_handler);
90 }
91
92 cx.listeners.insert(entity, listener);
93 }
94
95 if event.meta.consumed {
96 continue 'events;
97 }
98 }
99
100 event.map(|window_event, meta| {
102 if cx.windows.contains_key(&meta.origin) {
103 internal_state_updates(cx, window_event, meta);
104 }
105 });
106
107 if event.meta.consumed {
109 continue 'events;
110 }
111
112 let cx = &mut EventContext::new(cx);
113
114 let target = event.meta.target;
116
117 visit_entity(cx, target, event);
119
120 if event.meta.consumed {
122 continue 'events;
123 }
124
125 if event.meta.propagation == Propagation::Up {
127 let iter = target.parent_iter(cx.tree).skip(1);
129
130 for entity in iter {
131 visit_entity(cx, entity, event);
133
134 if event.meta.consumed {
136 continue 'events;
137 }
138 }
139 }
140
141 if event.meta.propagation == Propagation::Subtree {
143 let iter = target.branch_iter(cx.tree).skip(1);
145
146 for entity in iter {
147 visit_entity(cx, entity, event);
149
150 if event.meta.consumed {
152 continue 'events;
153 }
154 }
155 }
156
157 event.map(|window_event: &WindowEvent, _| {
158 (window_event_callback)(window_event);
159 });
160 }
161
162 binding_system(cx);
163
164 !cx.event_queue.is_empty()
166 } {}
167 }
168}
169
170fn visit_entity(cx: &mut EventContext, entity: Entity, event: &mut Event) {
171 if let Some(ids) =
173 cx.models.get(&entity).map(|models| models.keys().cloned().collect::<Vec<_>>())
174 {
175 for id in ids {
176 if let Some(mut model) =
177 cx.models.get_mut(&entity).and_then(|models| models.remove(&id))
178 {
179 cx.current = entity;
180
181 model.event(cx, event);
182
183 cx.models.get_mut(&entity).and_then(|models| models.insert(id, model));
184 }
185 }
186 }
187
188 if event.meta.consumed {
190 return;
191 }
192
193 if let Some(mut view) = cx.views.remove(&entity) {
195 cx.current = entity;
196 view.event(cx, event);
197
198 cx.views.insert(entity, view);
199 }
200}
201
202fn internal_state_updates(cx: &mut Context, window_event: &WindowEvent, meta: &mut EventMeta) {
204 cx.current = meta.target;
205
206 match window_event {
207 WindowEvent::Drop(drop_data) => {
208 cx.drop_data = Some(drop_data.clone());
209 }
210
211 WindowEvent::MouseMove(x, y) => {
212 if !x.is_nan() && !y.is_nan() {
213 cx.mouse.previous_cursor_x = cx.mouse.cursor_x;
214 cx.mouse.previous_cursor_y = cx.mouse.cursor_y;
215 cx.mouse.cursor_x = *x;
216 cx.mouse.cursor_y = *y;
217
218 hover_system(cx, meta.origin);
219
220 mutate_direct_or_up(meta, cx.captured, cx.hovered, false);
221 }
222
223 }
238 WindowEvent::MouseDown(button) => {
239 match button {
241 MouseButton::Left => {
242 cx.mouse.left.state = MouseButtonState::Pressed;
243
244 cx.mouse.left.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
245 cx.mouse.left.pressed = cx.hovered;
246 cx.triggered = cx.hovered;
247
248 let disabled = cx.style.disabled.get(cx.hovered).copied().unwrap_or_default();
249
250 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
251 if !disabled {
252 pseudo_classes.set(PseudoClassFlags::ACTIVE, true);
253 cx.needs_restyle(cx.triggered);
254 }
255 }
256 let focusable = cx
257 .style
258 .abilities
259 .get(cx.hovered)
260 .filter(|abilities| abilities.contains(Abilities::FOCUSABLE))
261 .is_some();
262
263 cx.drop_data = None;
265
266 cx.with_current(if focusable { cx.hovered } else { cx.focused }, |cx| {
267 cx.focus_with_visibility(false)
268 });
269 }
270 MouseButton::Right => {
271 cx.mouse.right.state = MouseButtonState::Pressed;
272 cx.mouse.right.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
273 cx.mouse.right.pressed = cx.hovered;
274 }
275 MouseButton::Middle => {
276 cx.mouse.middle.state = MouseButtonState::Pressed;
277 cx.mouse.middle.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
278 cx.mouse.middle.pressed = cx.hovered;
279 }
280 _ => {}
281 }
282
283 if matches!(button, MouseButton::Left) {
285 emit_direct_or_up(
286 cx,
287 WindowEvent::PressDown { mouse: true },
288 cx.captured,
289 cx.triggered,
290 true,
291 );
292 }
293
294 let new_click_time = Instant::now();
296 let click_duration = new_click_time - cx.click_time;
297 let new_click_pos = (cx.mouse.cursor_x, cx.mouse.cursor_y);
298 if click_duration <= DOUBLE_CLICK_INTERVAL
299 && new_click_pos == cx.click_pos
300 && *button == cx.click_button
301 {
302 if cx.clicks <= 2 {
303 cx.clicks += 1;
304 let event = if cx.clicks == 3 {
305 WindowEvent::MouseTripleClick(*button)
306 } else {
307 WindowEvent::MouseDoubleClick(*button)
308 };
309 meta.consume();
310 emit_direct_or_up(cx, event, cx.captured, cx.hovered, true);
311 }
312 } else {
313 cx.clicks = 1;
314 }
315 cx.click_time = new_click_time;
316 cx.click_pos = new_click_pos;
317 cx.click_button = *button;
318 mutate_direct_or_up(meta, cx.captured, cx.hovered, true);
319 }
320 WindowEvent::MouseUp(button) => {
321 match button {
322 MouseButton::Left => {
323 cx.mouse.left.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
324 cx.mouse.left.released = cx.hovered;
325 cx.mouse.left.state = MouseButtonState::Released;
326 }
327 MouseButton::Right => {
328 cx.mouse.right.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
329 cx.mouse.right.released = cx.hovered;
330 cx.mouse.right.state = MouseButtonState::Released;
331 }
332 MouseButton::Middle => {
333 cx.mouse.middle.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
334 cx.mouse.middle.released = cx.hovered;
335 cx.mouse.middle.state = MouseButtonState::Released;
336 }
337 _ => {}
338 }
339
340 if matches!(button, MouseButton::Left) {
341 if cx.hovered == cx.triggered {
342 let disabled = cx.style.disabled.get(cx.hovered).copied().unwrap_or_default();
343
344 if !disabled {
345 emit_direct_or_up(
346 cx,
347 WindowEvent::Press { mouse: true },
348 cx.captured,
349 cx.triggered,
350 true,
351 );
352 }
353 }
354
355 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
356 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
357 }
358
359 cx.needs_restyle(cx.triggered);
360
361 cx.triggered = Entity::null();
362 }
363
364 mutate_direct_or_up(meta, cx.captured, cx.hovered, true);
365 }
366 WindowEvent::MouseScroll(_, _) => {
367 meta.target = cx.hovered;
368 }
369 WindowEvent::KeyDown(code, _) => {
370 meta.target = cx.focused;
371
372 #[cfg(debug_assertions)]
373 if *code == Code::KeyP && cx.modifiers.ctrl() {
374 for entity in TreeIterator::full(&cx.tree) {
375 if let Some(models) = cx.models.get(&entity) {
376 if !models.is_empty() {
377 debug!("Models for {}", entity);
378 for (_, model) in models.iter() {
379 debug!("M: {:?}", model.name())
380 }
381 }
382 }
383
384 if let Some(stores) = cx.stores.get(&entity) {
385 if !stores.is_empty() {
386 debug!("Stores for {}", entity);
387 for (_, store) in stores.iter() {
388 debug!("S: [{}] - Observers {:?}", store.name(), store.observers())
389 }
390 }
391 }
392 }
393 }
394
395 #[cfg(debug_assertions)]
396 if *code == Code::KeyI {
397 debug!("Entity tree");
398 let (tree, views, cache) = (&cx.tree, &cx.views, &cx.cache);
399 let has_next_sibling = |entity| tree.get_next_sibling(entity).is_some();
400 let root_indents = |entity: Entity| {
401 let parent_iter = ParentIterator::new(tree, Some(entity));
402 parent_iter
403 .skip(1)
404 .collect::<Vec<_>>()
405 .into_iter()
406 .rev()
407 .skip(1)
408 .map(|entity| if has_next_sibling(entity) { "│ " } else { " " })
409 .collect::<String>()
410 };
411 let local_idents =
412 |entity| if has_next_sibling(entity) { "├── " } else { "└── " };
413 let indents = |entity| root_indents(entity) + local_idents(entity);
414
415 for entity in TreeIterator::full(tree).skip(1) {
416 if let Some(element_name) = views.get(&entity).and_then(|view| view.element()) {
417 let w = cache.get_bounds(entity).w;
418 let h = cache.get_bounds(entity).h;
419 let classes = cx.style.classes.get(entity);
420 let mut class_names = String::new();
421 if let Some(classes) = classes {
422 for class in classes.iter() {
423 class_names += &format!(".{}", class);
424 }
425 }
426 println!(
427 "{}{} {}{} [x: {} y: {} w: {} h: {}]",
428 indents(entity),
429 entity,
430 element_name,
431 class_names,
432 cache.get_bounds(entity).x,
433 cache.get_bounds(entity).y,
434 if w == f32::MAX { "inf".to_string() } else { w.to_string() },
435 if h == f32::MAX { "inf".to_string() } else { h.to_string() },
436 );
437 } else if let Some(binding_name) =
438 cx.bindings.get(&entity).map(|binding| format!("{:?}", binding))
439 {
440 println!(
441 "{}{} binding observing {}",
442 indents(entity),
443 entity,
444 binding_name,
445 );
446 } else {
447 println!(
448 "{}{} {}",
449 indents(entity),
450 entity,
451 if views.get(&entity).is_some() {
452 "unnamed view"
453 } else {
454 "no binding or view"
455 }
456 );
457 }
458 }
459 }
460
461 #[cfg(debug_assertions)]
462 if *code == Code::KeyS
463 && cx.modifiers == Modifiers::CTRL | Modifiers::SHIFT | Modifiers::ALT
464 {
465 use crate::systems::compute_element_hash;
466 use vizia_style::selectors::bloom::BloomFilter;
467
468 let mut filter = BloomFilter::default();
469 compute_element_hash(cx.hovered, &cx.tree, &cx.style, &mut filter);
470 let result = compute_matched_rules(cx.hovered, &cx.style, &cx.tree, &filter);
471
472 let entity = cx.hovered;
473 debug!("/* Matched rules for Entity: {} Parent: {:?} View: {} posx: {} posy: {} width: {} height: {}",
474 entity,
475 entity.parent(&cx.tree),
476 cx
477 .views
478 .get(&entity)
479 .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
480 cx.cache.get_posx(entity),
481 cx.cache.get_posy(entity),
482 cx.cache.get_width(entity),
483 cx.cache.get_height(entity)
484 );
485 for rule in result.into_iter() {
486 for selectors in cx.style.rules.iter() {
487 if *selectors.0 == rule.0 {
488 debug!("{:?}", selectors.1.selector);
489 }
490 }
491 }
492 }
493
494 #[cfg(debug_assertions)]
495 if *code == Code::KeyT
496 && cx.modifiers == Modifiers::CTRL | Modifiers::SHIFT | Modifiers::ALT
497 {
498 }
511
512 if *code == Code::F5 {
513 EventContext::new(cx).reload_styles().unwrap();
514 }
515
516 if *code == Code::Tab {
517 if cx.ime_state.is_composing() {
518 return;
519 }
520
521 let lock_focus_to = cx.tree.lock_focus_within(cx.focused);
522 if cx.modifiers.shift() {
523 let prev_focused = if let Some(prev_focused) =
524 focus_backward(&cx.tree, &cx.style, cx.focused, lock_focus_to)
525 {
526 prev_focused
527 } else {
528 TreeIterator::full(&cx.tree)
529 .filter(|node| {
530 is_navigatable(&cx.tree, &cx.style, *node, lock_focus_to)
531 })
532 .next_back()
533 .unwrap_or(Entity::root())
534 };
535
536 if prev_focused != cx.focused {
537 cx.set_focus_pseudo_classes(cx.focused, false, true);
538 cx.set_focus_pseudo_classes(prev_focused, true, true);
539 cx.event_queue.push_back(
540 Event::new(WindowEvent::FocusOut)
541 .target(cx.focused)
542 .origin(Entity::root()),
543 );
544 cx.event_queue.push_back(
545 Event::new(WindowEvent::FocusIn)
546 .target(prev_focused)
547 .origin(Entity::root()),
548 );
549
550 cx.focused = prev_focused;
551
552 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered)
553 {
554 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
555 cx.needs_restyle(cx.triggered);
556 }
557 cx.triggered = Entity::null();
558 }
559 } else {
560 let next_focused = if let Some(next_focused) =
561 focus_forward(&cx.tree, &cx.style, cx.focused, lock_focus_to)
562 {
563 next_focused
564 } else {
565 TreeIterator::full(&cx.tree)
566 .find(|node| is_navigatable(&cx.tree, &cx.style, *node, lock_focus_to))
567 .unwrap_or(Entity::root())
568 };
569
570 if next_focused != cx.focused {
571 cx.set_focus_pseudo_classes(cx.focused, false, true);
572 cx.set_focus_pseudo_classes(next_focused, true, true);
573 cx.event_queue.push_back(
574 Event::new(WindowEvent::FocusOut)
575 .target(cx.focused)
576 .origin(Entity::root()),
577 );
578 cx.event_queue.push_back(
579 Event::new(WindowEvent::FocusIn)
580 .target(next_focused)
581 .origin(Entity::root()),
582 );
583
584 cx.focused = next_focused;
585
586 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered)
587 {
588 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
589 cx.needs_restyle(cx.triggered);
590 }
591 cx.triggered = Entity::null();
592 }
593 }
594 }
595
596 if matches!(*code, Code::Enter | Code::NumpadEnter | Code::Space) {
597 cx.triggered = cx.focused;
598 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
599 pseudo_classes.set(PseudoClassFlags::ACTIVE, true);
600 }
601 cx.with_current(cx.focused, |cx| cx.emit(WindowEvent::PressDown { mouse: false }));
602 }
603 }
604 WindowEvent::KeyUp(code, _) => {
605 meta.target = cx.focused;
606 if matches!(code, Code::Enter | Code::NumpadEnter | Code::Space) {
607 if cx.focused == cx.triggered {
608 cx.with_current(cx.triggered, |cx| {
609 cx.emit(WindowEvent::Press { mouse: false })
610 });
611 }
612 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
613 pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
614 }
615 cx.needs_restyle(cx.triggered);
616 cx.triggered = Entity::null();
617 }
618 }
619 WindowEvent::CharInput(_) => {
620 meta.target = cx.focused;
621 }
622 WindowEvent::ImeActivate(_) => {
623 meta.target = cx.focused;
624 }
625 WindowEvent::ImeCommit(_) => {
626 meta.target = cx.focused;
627 }
628 WindowEvent::ImePreedit(_, _) => {
629 meta.target = cx.focused;
630 }
631 WindowEvent::SetImeCursorArea(_, _) => {
632 meta.target = cx.focused;
633 }
634 WindowEvent::WindowFocused(is_focused) => {
635 if *is_focused {
636 cx.set_focus_pseudo_classes(cx.focused, true, true);
637 cx.needs_restyle(cx.focused);
638 cx.needs_redraw(cx.focused);
639 } else {
640 cx.set_focus_pseudo_classes(cx.focused, false, true);
641 cx.needs_restyle(cx.focused);
642
643 cx.event_queue.push_back(
644 Event::new(WindowEvent::FocusVisibility(false))
645 .target(cx.focused)
646 .origin(Entity::root()), );
648
649 cx.event_queue.push_back(
650 Event::new(WindowEvent::MouseOut).target(cx.hovered).origin(Entity::root()), );
652 }
653 }
654 WindowEvent::MouseEnter => {
655 if let Some(pseudo_class) = cx.style.pseudo_classes.get_mut(meta.origin) {
656 pseudo_class.set(PseudoClassFlags::OVER, true);
657 }
658 }
659 WindowEvent::MouseLeave => {
660 if let Some(pseudo_class) = cx.style.pseudo_classes.get_mut(meta.origin) {
661 pseudo_class.set(PseudoClassFlags::OVER, false);
662 }
663
664 let parent_iter = LayoutParentIterator::new(&cx.tree, cx.hovered);
665 for ancestor in parent_iter {
666 if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(ancestor) {
667 pseudo_classes.set(PseudoClassFlags::HOVER, false);
668 cx.style.needs_restyle(ancestor);
669 }
670 }
671
672 cx.hovered = Entity::null();
673 }
674
675 _ => {}
676 }
677}
678
679fn mutate_direct_or_up(meta: &mut EventMeta, direct: Entity, up: Entity, root: bool) {
680 if direct != Entity::null() {
681 meta.target = direct;
682 meta.propagation = Propagation::Direct;
683 } else if up != Entity::root() || root {
684 meta.target = up;
685 meta.propagation = Propagation::Up;
686 } else {
687 meta.consume();
688 }
689}
690
691fn emit_direct_or_up<M: Any + Send>(
692 cx: &mut Context,
693 message: M,
694 direct: Entity,
695 up: Entity,
696 root: bool,
697) {
698 let mut event = Event::new(message);
699 mutate_direct_or_up(&mut event.meta, direct, up, root);
700 cx.emit_custom(event);
701}