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