Skip to main content

vizia_core/events/
event_manager.rs

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/// Dispatches events to views and models.
17///
18/// The [EventManager] is responsible for taking the events in the event queue in cx
19/// and dispatching them to views and models based on the target and propagation metadata of the event.
20#[doc(hidden)]
21pub struct EventManager {
22    // Queue of events to be processed.
23    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    /// Flush the event queue, dispatching events to their targets.
38    /// Returns whether there are still more events to process, i.e. the event handlers sent events.
39    pub fn flush_events(
40        &mut self,
41        cx: &mut Context,
42        mut window_event_callback: impl FnMut(&WindowEvent),
43    ) {
44        while {
45            // Clear the event queue in the event manager.
46            self.event_queue.clear();
47
48            // Move events from cx to event manager. This is so the cx can be passed
49            // mutably to the view when handling events.
50            self.event_queue.extend(cx.event_queue.drain(0..));
51
52            // Loop over the events in the event queue.
53            'events: for event in self.event_queue.iter_mut() {
54                let keyboard_lock_root = keyboard_event_lock_root(cx, event);
55                let mut is_drop_event = false;
56                event.map(|window_event: &WindowEvent, _| {
57                    is_drop_event = matches!(window_event, WindowEvent::Drop(_));
58                });
59
60                // Handle internal events.
61                event.take(|internal_event, _| match internal_event {
62                    InternalEvent::Redraw => cx.needs_redraw(Entity::root()),
63                    InternalEvent::LoadImage { path, image, policy } => {
64                        if let Some(image) = image.lock().unwrap().take() {
65                            ResourceContext::new(cx).load_image(path, image, policy);
66                        }
67                    }
68                });
69
70                // Send events to any global listeners.
71                let mut global_listeners = vec![];
72                std::mem::swap(&mut cx.global_listeners, &mut global_listeners);
73                for listener in &global_listeners {
74                    cx.with_current(Entity::root(), |cx| {
75                        listener(&mut EventContext::new(cx), event)
76                    });
77                }
78                std::mem::swap(&mut cx.global_listeners, &mut global_listeners);
79
80                // Send events to any local listeners.
81                let listeners = cx.listeners.keys().copied().collect::<Vec<Entity>>();
82                for entity in listeners {
83                    if let Some(lock_root) = keyboard_lock_root {
84                        if !entity.is_descendant_of(&cx.tree, lock_root) {
85                            continue;
86                        }
87                    }
88
89                    if let Some(listener) = cx.listeners.remove(&entity) {
90                        if let Some(mut event_handler) = cx.views.remove(&entity) {
91                            cx.with_current(entity, |cx| {
92                                (listener)(
93                                    event_handler.as_mut(),
94                                    &mut EventContext::new(cx),
95                                    event,
96                                );
97                            });
98
99                            cx.views.insert(entity, event_handler);
100                        }
101
102                        cx.listeners.insert(entity, listener);
103                    }
104
105                    if event.meta.consumed {
106                        clear_drop_state_for_drop_event(is_drop_event, &mut cx.drop_data);
107                        continue 'events;
108                    }
109                }
110
111                // Handle state updates for window events.
112                event.map(|window_event, meta| {
113                    if cx.windows.contains_key(&meta.origin) {
114                        internal_state_updates(cx, window_event, meta);
115                    }
116                });
117
118                // Skip to next event if the current event was consumed when handling internal state updates.
119                if event.meta.consumed {
120                    clear_drop_state_for_drop_event(is_drop_event, &mut cx.drop_data);
121                    continue 'events;
122                }
123
124                let cx = &mut EventContext::new(cx);
125
126                // Copy the target to prevent multiple mutable borrows error.
127                let target = event.meta.target;
128
129                // Send event to target.
130                if keyboard_lock_root
131                    .map(|lock_root| target.is_descendant_of(cx.tree, lock_root))
132                    .unwrap_or(true)
133                {
134                    visit_entity(cx, target, event);
135                }
136
137                // Skip to next event if the current event was consumed.
138                if event.meta.consumed {
139                    clear_drop_state_for_drop_event(is_drop_event, &mut *cx.drop_data);
140                    continue 'events;
141                }
142
143                // Propagate up from target to root (not including the target).
144                if event.meta.propagation == Propagation::Up {
145                    // Create a parent iterator and skip the first element which is the target.
146                    let iter = target.parent_iter(cx.tree).skip(1);
147
148                    for entity in iter {
149                        if let Some(lock_root) = keyboard_lock_root {
150                            if !entity.is_descendant_of(cx.tree, lock_root) {
151                                break;
152                            }
153                        }
154
155                        // Send event to all ancestors of the target.
156                        visit_entity(cx, entity, event);
157
158                        // Skip to the next event if the current event was consumed.
159                        if event.meta.consumed {
160                            clear_drop_state_for_drop_event(is_drop_event, &mut *cx.drop_data);
161                            continue 'events;
162                        }
163                    }
164                }
165
166                // Propagate the event down the subtree from the target (not including the target).
167                if event.meta.propagation == Propagation::Subtree {
168                    // Create a branch (subtree) iterator and skip the first element which is the target.
169                    let iter = target.branch_iter(cx.tree).skip(1);
170
171                    for entity in iter {
172                        if keyboard_lock_root
173                            .map(|lock_root| entity.is_descendant_of(cx.tree, lock_root))
174                            .unwrap_or(true)
175                        {
176                            // Send event to all entities in the subtree after the target.
177                            visit_entity(cx, entity, event);
178                        }
179
180                        // Skip to the next event if the current event was consumed.
181                        if event.meta.consumed {
182                            clear_drop_state_for_drop_event(is_drop_event, &mut *cx.drop_data);
183                            continue 'events;
184                        }
185                    }
186                }
187
188                event.map(|window_event: &WindowEvent, _| {
189                    (window_event_callback)(window_event);
190                });
191
192                clear_drop_state_for_drop_event(is_drop_event, &mut *cx.drop_data);
193            }
194
195            binding_system(cx);
196
197            // Return true if there are new events in the queue.
198            !cx.event_queue.is_empty()
199        } {}
200    }
201}
202
203fn clear_drop_state_for_drop_event(is_drop_event: bool, drop_data: &mut Option<DropData>) {
204    if is_drop_event && drop_data.is_some() {
205        *drop_data = None;
206    }
207}
208
209fn is_keyboard_window_event(window_event: &WindowEvent) -> bool {
210    matches!(
211        window_event,
212        WindowEvent::KeyDown(_, _)
213            | WindowEvent::KeyUp(_, _)
214            | WindowEvent::CharInput(_)
215            | WindowEvent::ImeActivate(_)
216            | WindowEvent::ImeCommit(_)
217            | WindowEvent::ImePreedit(_, _)
218            | WindowEvent::SetImeCursorArea(_, _)
219    )
220}
221
222fn keyboard_event_lock_root(cx: &Context, event: &mut Event) -> Option<Entity> {
223    let mut lock_root = None;
224
225    event.map(|window_event: &WindowEvent, _| {
226        if is_keyboard_window_event(window_event) {
227            let candidate = cx.tree.lock_focus_within(cx.focused);
228            if candidate != Entity::root() {
229                lock_root = Some(candidate);
230            }
231        }
232    });
233
234    lock_root
235}
236
237fn visit_entity(cx: &mut EventContext, entity: Entity, event: &mut Event) {
238    // Send event to models attached to the entity
239    if let Some(ids) =
240        cx.models.get(&entity).map(|models| models.keys().cloned().collect::<Vec<_>>())
241    {
242        for id in ids {
243            if let Some(mut model) =
244                cx.models.get_mut(&entity).and_then(|models| models.remove(&id))
245            {
246                cx.current = entity;
247
248                model.event(cx, event);
249
250                cx.models.get_mut(&entity).and_then(|models| models.insert(id, model));
251            }
252        }
253    }
254
255    // Return early if the event was consumed by a model
256    if event.meta.consumed {
257        return;
258    }
259
260    // Send event to the view attached to the entity
261    if let Some(mut view) = cx.views.remove(&entity) {
262        cx.current = entity;
263        view.event(cx, event);
264
265        cx.views.insert(entity, view);
266    }
267}
268
269/// Update the internal state of the cx based on received window event and emit window event to relevant target.
270fn internal_state_updates(cx: &mut Context, window_event: &WindowEvent, meta: &mut EventMeta) {
271    cx.current = meta.target;
272
273    match window_event {
274        WindowEvent::Drop(drop_data) => {
275            cx.drop_data = Some(drop_data.clone());
276        }
277
278        WindowEvent::MouseMove(x, y) => {
279            if !x.is_nan() && !y.is_nan() {
280                cx.mouse.previous_cursor_x = cx.mouse.cursor_x;
281                cx.mouse.previous_cursor_y = cx.mouse.cursor_y;
282                cx.mouse.cursor_x = *x;
283                cx.mouse.cursor_y = *y;
284
285                hover_system(cx, meta.origin);
286                if cx.drop_data.is_some() || cx.drag_hovered != Entity::null() {
287                    dispatch_drag_events(cx, *x, *y);
288                }
289
290                if let Some(drag_view) = cx.active_drag_view {
291                    if cx.drop_data.is_some() {
292                        position_drag_view(cx, drag_view, *x, *y);
293                    } else {
294                        hide_drag_view(cx, drag_view);
295                        cx.active_drag_view = None;
296                    }
297                }
298
299                mutate_direct_or_up(meta, cx.captured, cx.hovered, false);
300            }
301
302            // if cx.mouse.cursor_x != cx.mouse.previous_cursor_x
303            //     || cx.mouse.cursor_y != cx.mouse.previous_cursor_y
304            // {
305            // }
306
307            // if let Some(dropped_file) = cx.dropped_file.take() {
308            //     emit_direct_or_up(
309            //         cx,
310            //         WindowEvent::DroppedFile(dropped_file),
311            //         cx.captured,
312            //         cx.hovered,
313            //         true,
314            //     );
315            // }
316        }
317        WindowEvent::MouseDown(button) => {
318            // do direct state-updates
319            match button {
320                MouseButton::Left => {
321                    cx.mouse.left.state = MouseButtonState::Pressed;
322
323                    cx.mouse.left.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
324                    cx.mouse.left.pressed = cx.hovered;
325                    cx.triggered = cx.hovered;
326
327                    let disabled = cx.style.disabled.get(cx.hovered).copied().unwrap_or_default();
328
329                    if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
330                        if !disabled {
331                            pseudo_classes.set(PseudoClassFlags::ACTIVE, true);
332                            cx.needs_restyle(cx.triggered);
333                        }
334                    }
335                    let focusable = cx
336                        .style
337                        .abilities
338                        .get(cx.hovered)
339                        .filter(|abilities| abilities.contains(Abilities::FOCUSABLE))
340                        .is_some();
341
342                    // Reset drag data
343                    cx.drop_data = None;
344                    cx.drag_hovered = Entity::null();
345                    if let Some(drag_view) = cx.active_drag_view.take() {
346                        hide_drag_view(cx, drag_view);
347                    }
348
349                    cx.with_current(if focusable { cx.hovered } else { cx.focused }, |cx| {
350                        cx.focus_with_visibility(false)
351                    });
352                }
353                MouseButton::Right => {
354                    cx.mouse.right.state = MouseButtonState::Pressed;
355                    cx.mouse.right.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
356                    cx.mouse.right.pressed = cx.hovered;
357                }
358                MouseButton::Middle => {
359                    cx.mouse.middle.state = MouseButtonState::Pressed;
360                    cx.mouse.middle.pos_down = (cx.mouse.cursor_x, cx.mouse.cursor_y);
361                    cx.mouse.middle.pressed = cx.hovered;
362                }
363                _ => {}
364            }
365
366            // emit trigger events
367            if matches!(button, MouseButton::Left) {
368                emit_direct_or_up(
369                    cx,
370                    WindowEvent::PressDown { mouse: true },
371                    cx.captured,
372                    cx.triggered,
373                    true,
374                );
375            }
376
377            // track double/triple -click
378            let new_click_time = Instant::now();
379            let click_duration = new_click_time - cx.click_time;
380            let new_click_pos = (cx.mouse.cursor_x, cx.mouse.cursor_y);
381            let double_click_interval = cx.environment().double_click_interval;
382            if click_duration <= double_click_interval
383                && new_click_pos == cx.click_pos
384                && *button == cx.click_button
385            {
386                if cx.clicks <= 2 {
387                    cx.clicks += 1;
388                    let event = if cx.clicks == 3 {
389                        WindowEvent::MouseTripleClick(*button)
390                    } else {
391                        WindowEvent::MouseDoubleClick(*button)
392                    };
393                    meta.consume();
394                    emit_direct_or_up(cx, event, cx.captured, cx.hovered, true);
395                }
396            } else {
397                cx.clicks = 1;
398            }
399            cx.click_time = new_click_time;
400            cx.click_pos = new_click_pos;
401            cx.click_button = *button;
402            mutate_direct_or_up(meta, cx.captured, cx.hovered, true);
403        }
404        WindowEvent::MouseUp(button) => {
405            let had_drop_data = cx.drop_data.is_some();
406
407            if let Some(drag_view) = cx.active_drag_view.take() {
408                hide_drag_view(cx, drag_view);
409            }
410
411            match button {
412                MouseButton::Left => {
413                    cx.mouse.left.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
414                    cx.mouse.left.released = cx.hovered;
415                    cx.mouse.left.state = MouseButtonState::Released;
416                }
417                MouseButton::Right => {
418                    cx.mouse.right.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
419                    cx.mouse.right.released = cx.hovered;
420                    cx.mouse.right.state = MouseButtonState::Released;
421                }
422                MouseButton::Middle => {
423                    cx.mouse.middle.pos_up = (cx.mouse.cursor_x, cx.mouse.cursor_y);
424                    cx.mouse.middle.released = cx.hovered;
425                    cx.mouse.middle.state = MouseButtonState::Released;
426                }
427                _ => {}
428            }
429
430            if matches!(button, MouseButton::Left) {
431                if cx.hovered == cx.triggered {
432                    let disabled = cx.style.disabled.get(cx.hovered).copied().unwrap_or_default();
433
434                    if !disabled {
435                        emit_direct_or_up(
436                            cx,
437                            WindowEvent::Press { mouse: true },
438                            cx.captured,
439                            cx.triggered,
440                            true,
441                        );
442                    }
443                }
444
445                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
446                    pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
447                }
448
449                cx.needs_restyle(cx.triggered);
450
451                cx.triggered = Entity::null();
452            }
453
454            if had_drop_data {
455                let drop_data = cx.drop_data.take();
456
457                // Dispatch Drop to the hovered drop target.
458                if cx.drag_hovered != Entity::null() {
459                    if let Some(data) = drop_data {
460                        cx.event_queue
461                            .push_back(Event::new(WindowEvent::Drop(data)).target(cx.drag_hovered));
462                    }
463
464                    // Drag is ending, so notify the last hovered drop target that the pointer left.
465                    cx.event_queue
466                        .push_back(Event::new(WindowEvent::DragLeave).target(cx.drag_hovered));
467                }
468                cx.drag_hovered = Entity::null();
469            }
470            // Always route MouseUp through the captured entity (the drag source) so it
471            // receives the release and can reset its dragging state via DragModel::MouseUp.
472            // Capture is cleared by DragModel calling cx.release(). Drop and DragLeave are
473            // already queued to drag_hovered and will fire on the next event cycle.
474            mutate_direct_or_up(meta, cx.captured, cx.hovered, true);
475        }
476        WindowEvent::MouseScroll(_, _) => {
477            meta.target = cx.hovered;
478        }
479        WindowEvent::KeyDown(code, _) => {
480            meta.target = cx.focused;
481
482            #[cfg(debug_assertions)]
483            if *code == Code::KeyP && cx.modifiers.ctrl() {
484                for entity in TreeIterator::full(&cx.tree) {
485                    if let Some(models) = cx.models.get(&entity) {
486                        if !models.is_empty() {
487                            debug!("Models for {}", entity);
488                            for (_, model) in models.iter() {
489                                debug!("M: {:?}", model.name())
490                            }
491                        }
492                    }
493                }
494            }
495
496            #[cfg(debug_assertions)]
497            if *code == Code::KeyI {
498                debug!("Entity tree");
499                let (tree, views, cache) = (&cx.tree, &cx.views, &cx.cache);
500                let has_next_sibling = |entity| tree.get_next_sibling(entity).is_some();
501                let root_indents = |entity: Entity| {
502                    let parent_iter = ParentIterator::new(tree, Some(entity));
503                    parent_iter
504                        .skip(1)
505                        .collect::<Vec<_>>()
506                        .into_iter()
507                        .rev()
508                        .skip(1)
509                        .map(|entity| if has_next_sibling(entity) { "│   " } else { "    " })
510                        .collect::<String>()
511                };
512                let local_idents =
513                    |entity| if has_next_sibling(entity) { "├── " } else { "└── " };
514                let indents = |entity| root_indents(entity) + local_idents(entity);
515
516                for entity in TreeIterator::full(tree).skip(1) {
517                    if let Some(element_name) = views.get(&entity).and_then(|view| view.element()) {
518                        let w = cache.get_bounds(entity).w;
519                        let h = cache.get_bounds(entity).h;
520                        let classes = cx.style.classes.get(entity);
521                        let mut class_names = String::new();
522                        if let Some(classes) = classes {
523                            for class in classes.iter() {
524                                class_names += &format!(".{}", class);
525                            }
526                        }
527                        println!(
528                            "{}{} {}{} [x: {} y: {} w: {} h: {}]",
529                            indents(entity),
530                            entity,
531                            element_name,
532                            class_names,
533                            cache.get_bounds(entity).x,
534                            cache.get_bounds(entity).y,
535                            if w == f32::MAX { "inf".to_string() } else { w.to_string() },
536                            if h == f32::MAX { "inf".to_string() } else { h.to_string() },
537                        );
538                    } else if let Some(binding_name) =
539                        cx.bindings.get(&entity).map(|binding| format!("{:?}", binding))
540                    {
541                        println!(
542                            "{}{} binding observing {}",
543                            indents(entity),
544                            entity,
545                            binding_name,
546                        );
547                    } else {
548                        println!(
549                            "{}{} {}",
550                            indents(entity),
551                            entity,
552                            if views.get(&entity).is_some() {
553                                "unnamed view"
554                            } else {
555                                "no binding or view"
556                            }
557                        );
558                    }
559                }
560            }
561
562            #[cfg(debug_assertions)]
563            if *code == Code::KeyS
564                && cx.modifiers == Modifiers::CTRL | Modifiers::SHIFT | Modifiers::ALT
565            {
566                use crate::systems::compute_element_hash;
567                use vizia_style::selectors::bloom::BloomFilter;
568
569                let mut filter = BloomFilter::default();
570                compute_element_hash(cx.hovered, &cx.tree, &cx.style, &mut filter);
571                let result = compute_matched_rules(cx.hovered, &cx.style, &cx.tree, &filter);
572
573                let entity = cx.hovered;
574                debug!(
575                    "/* Matched rules for Entity: {} Parent: {:?} View: {} posx: {} posy: {} width: {} height: {}",
576                    entity,
577                    entity.parent(&cx.tree),
578                    cx.views
579                        .get(&entity)
580                        .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
581                    cx.cache.get_posx(entity),
582                    cx.cache.get_posy(entity),
583                    cx.cache.get_width(entity),
584                    cx.cache.get_height(entity)
585                );
586                for rule in result.into_iter() {
587                    for selectors in cx.style.rules.iter() {
588                        if *selectors.0 == rule.0 {
589                            debug!("{:?}", selectors.1.selector);
590                        }
591                    }
592                }
593            }
594
595            #[cfg(debug_assertions)]
596            if *code == Code::KeyT
597                && cx.modifiers == Modifiers::CTRL | Modifiers::SHIFT | Modifiers::ALT
598            {
599                // debug!("Loaded font face info:");
600                // for face in cx.text_context.font_system().db().faces() {
601                //     debug!(
602                //         "family: {:?}\npost_script_name: {:?}\nstyle: {:?}\nweight: {:?}\nstretch: {:?}\nmonospaced: {:?}\n",
603                //         face.families,
604                //         face.post_script_name,
605                //         face.style,
606                //         face.weight,
607                //         face.stretch,
608                //         face.monospaced,
609                //     );
610                // }
611            }
612
613            if *code == Code::F5 {
614                EventContext::new(cx).reload_styles().unwrap();
615            }
616
617            if *code == Code::Tab {
618                if cx.ime_state.is_composing() {
619                    return;
620                }
621
622                let lock_focus_to = cx.tree.lock_focus_within(cx.focused);
623
624                // If the locked subtree contains no navigatable items (e.g. a menu popup
625                // where items are focusable but not navigatable), fall back to global
626                // navigation so Tab can escape the lock. Dialog boxes with navigatable
627                // items inside are unaffected.
628                let effective_lock = if lock_focus_to != Entity::root()
629                    && !TreeIterator::full(&cx.tree)
630                        .any(|node| is_navigatable(&cx.tree, &cx.style, node, lock_focus_to))
631                {
632                    Entity::root()
633                } else {
634                    lock_focus_to
635                };
636
637                if cx.modifiers.shift() {
638                    let prev_focused = if let Some(prev_focused) =
639                        focus_backward(&cx.tree, &cx.style, cx.focused, effective_lock)
640                    {
641                        prev_focused
642                    } else {
643                        TreeIterator::full(&cx.tree)
644                            .rfind(|node| {
645                                is_navigatable(&cx.tree, &cx.style, *node, effective_lock)
646                            })
647                            .unwrap_or(Entity::root())
648                    };
649
650                    if prev_focused != cx.focused {
651                        cx.set_focus_pseudo_classes(cx.focused, false, true);
652                        cx.set_focus_pseudo_classes(prev_focused, true, true);
653                        cx.event_queue.push_back(
654                            Event::new(WindowEvent::FocusOut)
655                                .target(cx.focused)
656                                .origin(Entity::root()),
657                        );
658                        cx.event_queue.push_back(
659                            Event::new(WindowEvent::FocusIn)
660                                .target(prev_focused)
661                                .origin(Entity::root()),
662                        );
663                        cx.event_queue.push_back(
664                            Event::new(ScrollEvent::ScrollToView(prev_focused))
665                                .target(prev_focused)
666                                .origin(Entity::root()),
667                        );
668
669                        cx.focused = prev_focused;
670
671                        if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered)
672                        {
673                            pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
674                            cx.needs_restyle(cx.triggered);
675                        }
676                        cx.triggered = Entity::null();
677                    }
678                } else {
679                    let next_focused = if let Some(next_focused) =
680                        focus_forward(&cx.tree, &cx.style, cx.focused, effective_lock)
681                    {
682                        next_focused
683                    } else {
684                        TreeIterator::full(&cx.tree)
685                            .find(|node| is_navigatable(&cx.tree, &cx.style, *node, effective_lock))
686                            .unwrap_or(Entity::root())
687                    };
688
689                    if next_focused != cx.focused {
690                        cx.set_focus_pseudo_classes(cx.focused, false, true);
691                        cx.set_focus_pseudo_classes(next_focused, true, true);
692                        cx.event_queue.push_back(
693                            Event::new(WindowEvent::FocusOut)
694                                .target(cx.focused)
695                                .origin(Entity::root()),
696                        );
697                        cx.event_queue.push_back(
698                            Event::new(WindowEvent::FocusIn)
699                                .target(next_focused)
700                                .origin(Entity::root()),
701                        );
702                        cx.event_queue.push_back(
703                            Event::new(ScrollEvent::ScrollToView(next_focused))
704                                .target(next_focused)
705                                .origin(Entity::root()),
706                        );
707
708                        cx.focused = next_focused;
709
710                        if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered)
711                        {
712                            pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
713                            cx.needs_restyle(cx.triggered);
714                        }
715                        cx.triggered = Entity::null();
716                    }
717                }
718            }
719
720            if matches!(*code, Code::Enter | Code::NumpadEnter | Code::Space) {
721                cx.triggered = cx.focused;
722                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
723                    pseudo_classes.set(PseudoClassFlags::ACTIVE, true);
724                }
725                cx.with_current(cx.focused, |cx| cx.emit(WindowEvent::PressDown { mouse: false }));
726            }
727        }
728        WindowEvent::KeyUp(code, _) => {
729            meta.target = cx.focused;
730            if matches!(code, Code::Enter | Code::NumpadEnter | Code::Space) {
731                if cx.focused == cx.triggered {
732                    cx.with_current(cx.triggered, |cx| {
733                        cx.emit(WindowEvent::Press { mouse: false })
734                    });
735                }
736                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(cx.triggered) {
737                    pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
738                }
739                cx.needs_restyle(cx.triggered);
740                cx.triggered = Entity::null();
741            }
742        }
743        WindowEvent::CharInput(_) => {
744            meta.target = cx.focused;
745        }
746        WindowEvent::ImeActivate(_) => {
747            meta.target = cx.focused;
748        }
749        WindowEvent::ImeCommit(_) => {
750            meta.target = cx.focused;
751        }
752        WindowEvent::ImePreedit(_, _) => {
753            meta.target = cx.focused;
754        }
755        WindowEvent::SetImeCursorArea(_, _) => {
756            meta.target = cx.focused;
757        }
758        WindowEvent::WindowFocused(is_focused) => {
759            if *is_focused {
760                cx.set_focus_pseudo_classes(cx.focused, true, true);
761                cx.needs_restyle(cx.focused);
762                cx.needs_redraw(cx.focused);
763            } else {
764                cx.set_focus_pseudo_classes(cx.focused, false, true);
765                cx.needs_restyle(cx.focused);
766
767                cx.event_queue.push_back(
768                    Event::new(WindowEvent::FocusVisibility(false))
769                        .target(cx.focused)
770                        .origin(Entity::root()), //.propagate(Propagation::Direct),
771                );
772
773                cx.event_queue.push_back(
774                    Event::new(WindowEvent::MouseOut).target(cx.hovered).origin(Entity::root()), // .propagate(Propagation::Direct),
775                );
776            }
777        }
778        WindowEvent::MouseEnter => {
779            if let Some(pseudo_class) = cx.style.pseudo_classes.get_mut(meta.origin) {
780                pseudo_class.set(PseudoClassFlags::OVER, true);
781            }
782        }
783        WindowEvent::MouseLeave => {
784            if let Some(pseudo_class) = cx.style.pseudo_classes.get_mut(meta.origin) {
785                pseudo_class.set(PseudoClassFlags::OVER, false);
786            }
787
788            let parent_iter = LayoutParentIterator::new(&cx.tree, cx.hovered);
789            for ancestor in parent_iter {
790                if let Some(pseudo_classes) = cx.style.pseudo_classes.get_mut(ancestor) {
791                    pseudo_classes.set(PseudoClassFlags::HOVER, false);
792                    cx.style.needs_restyle(ancestor);
793                }
794            }
795
796            cx.hovered = Entity::null();
797        }
798
799        _ => {}
800    }
801}
802
803fn position_drag_view(cx: &mut Context, drag_view: Entity, x: f32, y: f32) {
804    if !cx.entity_manager.is_alive(drag_view) {
805        cx.active_drag_view = None;
806        return;
807    }
808
809    let left = cx.style.physical_to_logical(x);
810    let top = cx.style.physical_to_logical(y);
811
812    cx.with_current(drag_view, |cx| {
813        let mut ex = EventContext::new(cx);
814        ex.set_display(Display::Flex);
815        ex.set_left(Units::Pixels(left));
816        ex.set_top(Units::Pixels(top));
817    });
818}
819
820fn hide_drag_view(cx: &mut Context, drag_view: Entity) {
821    if !cx.entity_manager.is_alive(drag_view) {
822        return;
823    }
824
825    cx.with_current(drag_view, |cx| {
826        let mut ex = EventContext::new(cx);
827        ex.set_display(Display::None);
828    });
829}
830
831fn dispatch_drag_events(cx: &mut Context, x: f32, y: f32) {
832    if cx.drop_data.is_some() {
833        let hovered = cx.hovered;
834
835        if hovered != cx.drag_hovered {
836            if cx.drag_hovered != Entity::null() {
837                cx.event_queue
838                    .push_back(Event::new(WindowEvent::DragLeave).target(cx.drag_hovered));
839            }
840
841            if hovered != Entity::null() {
842                cx.event_queue.push_back(Event::new(WindowEvent::DragEnter).target(hovered));
843            }
844
845            cx.drag_hovered = hovered;
846        }
847
848        if hovered != Entity::null() {
849            cx.event_queue.push_back(Event::new(WindowEvent::DragMove(x, y)).target(hovered));
850        }
851    } else if cx.drag_hovered != Entity::null() {
852        cx.event_queue.push_back(Event::new(WindowEvent::DragLeave).target(cx.drag_hovered));
853        cx.drag_hovered = Entity::null();
854    }
855}
856
857fn mutate_direct_or_up(meta: &mut EventMeta, direct: Entity, up: Entity, root: bool) {
858    if direct != Entity::null() {
859        meta.target = direct;
860        meta.propagation = Propagation::Direct;
861    } else if up != Entity::root() || root {
862        meta.target = up;
863        meta.propagation = Propagation::Up;
864    } else {
865        meta.consume();
866    }
867}
868
869fn emit_direct_or_up<M: Any + Send>(
870    cx: &mut Context,
871    message: M,
872    direct: Entity,
873    up: Entity,
874    root: bool,
875) {
876    let mut event = Event::new(message);
877    mutate_direct_or_up(&mut event.meta, direct, up, root);
878    cx.emit_custom(event);
879}