Skip to main content

ferroui_base/input/
focus_manager.rs

1use super::navigation::{XYFocus, XYFocusOptions};
2use super::{
3    FindNextElementOptions, FocusHelpers, IFocusManager, InputElement, KeyboardNavigation, KeyboardNavigationMode,
4    NavigationDirection, KeyModifiers, KeyboardDevice, MouseButton, NavigationMethod, PointerEventArgs,
5    PointerPressedEventArgs, PointerReleasedEventArgs, PointerType,
6};
7use crate::interactivity::{IRoutedEventArgs, Interactive, RoutingStrategies};
8use crate::{
9    ferro_property, AttachedProperty, FerroLocator, FerroProperty, LocatorExtensions, Ref, StyledElement, Visual,
10};
11use std::cell::RefCell;
12use std::rc::{Rc, Weak};
13
14type Element = Ref<InputElement>;
15
16/// Manages focus for the application.
17pub struct FocusManager {
18    this: Weak<FocusManager>,
19    xy_focus: XYFocus,
20    reusable_focus_options: RefCell<Option<XYFocusOptions>>,
21    focus_root: RefCell<Option<Ref<StyledElement>>>,
22    content_root: RefCell<Option<Ref<InputElement>>>,
23}
24
25crate::ferro_static_type!(FocusManager);
26
27crate::ferro_properties! { impl FocusManager {
28    ferro_property!(
29        /// The element that currently has focus within a focus scope, set
30        /// on the scope.
31        ///
32        /// A scope does not own its focused element, which can be the scope
33        /// itself (a focused menu or top-level), so the value is an element
34        /// reference.
35        fn focused_element_property() -> AttachedProperty<Option<crate::ElementRef<InputElement>>> {
36            crate::data::core::ValueTypes::register_element_ref::<InputElement>();
37            FerroProperty::register_attached::<FocusManager, StyledElement, _>("FocusedElement", None)
38        }
39    );
40} }
41
42impl FocusManager {
43    /// Registers the class handlers that move focus to the element under a
44    /// pointer press or release.
45    fn static_constructor() {
46        // The class handlers of the input element itself come first.
47        InputElement::TYPE.ensure_class_init();
48
49        InputElement::pointer_pressed_event().add_class_handler_untyped(
50            InputElement::TYPE,
51            Self::on_preview_pointer_event_handler,
52            RoutingStrategies::TUNNEL,
53            false,
54        );
55        InputElement::pointer_released_event().add_class_handler_untyped(
56            InputElement::TYPE,
57            Self::on_preview_pointer_event_handler,
58            RoutingStrategies::TUNNEL,
59            false,
60        );
61    }
62
63    /// Creates a focus manager.
64    pub fn new() -> Rc<FocusManager> {
65        Self::TYPE.ensure_class_init();
66        Rc::new_cyclic(|this| FocusManager {
67            this: this.clone(),
68            xy_focus: XYFocus::new(),
69            reusable_focus_options: RefCell::new(None),
70            focus_root: RefCell::new(None),
71            content_root: RefCell::new(None),
72        })
73    }
74
75    /// The focus manager registered with the locator (as
76    /// `dyn IFocusManager`): used for elements that are not attached to an
77    /// input root.
78    fn locator_instance() -> Option<Rc<FocusManager>> {
79        FerroLocator::current()
80            .get_service::<dyn IFocusManager>()
81            .and_then(|manager| manager.as_any().downcast_ref::<FocusManager>().and_then(|m| m.this.upgrade()))
82    }
83
84    /// The root of the content the focus manager navigates within.
85    pub fn content_root(&self) -> Option<Ref<InputElement>> {
86        self.content_root.borrow().clone()
87    }
88
89    /// Sets the root of the content the focus manager navigates within.
90    pub fn set_content_root(&self, value: Option<Ref<InputElement>>) {
91        let old = self.content_root.replace(value);
92        drop(old);
93    }
94
95    fn current() -> Option<Ref<InputElement>> {
96        KeyboardDevice::instance().and_then(|keyboard| keyboard.focused_element())
97    }
98
99    fn focus_root(&self) -> Option<Ref<StyledElement>> {
100        self.focus_root.borrow().clone()
101    }
102
103    fn set_focus_root(&self, value: Option<Ref<StyledElement>>) {
104        let old = self.focus_root.replace(value);
105        drop(old);
106    }
107
108    /// Gets the currently focused element.
109    pub fn get_focused_element(&self) -> Option<Ref<InputElement>> {
110        Self::current()
111    }
112
113    /// Focuses a control.
114    ///
115    /// `element` is the control to focus; `None` restores the focus of the
116    /// current focus root or clears the focus. `method` is the method by
117    /// which focus was changed and `key_modifiers` any key modifiers active
118    /// at the time of focus. Returns true if the focus moved to a control.
119    pub fn focus(
120        &self,
121        element: Option<&Ref<InputElement>>,
122        method: NavigationMethod,
123        key_modifiers: KeyModifiers,
124    ) -> bool {
125        let Some(keyboard_device) = KeyboardDevice::instance() else { return false };
126
127        if let Some(element) = element {
128            return self.focus_core(&keyboard_device, element, method, key_modifiers);
129        }
130
131        if let Some(focus_root) = self.focus_root() {
132            let current = Self::current();
133            let restore = crate::ElementRef::resolve(&focus_root.get_value(Self::focused_element_property()));
134
135            if let Some(restore) = restore.filter(|restore| Some(restore) != current.as_ref()) {
136                if !Self::can_focus(&restore) {
137                    // The previous effective focus is no longer part of the
138                    // focus root's visual tree. We clear the focused
139                    // element.
140                    focus_root.clear_value(Self::focused_element_property());
141
142                    // Keep focus in another scope (e.g. window), unless the focused element was removed or hidden.
143                    if let Some(current) = &current {
144                        if Self::is_visible(current) && Self::get_focus_scope(current) != Some(focus_root.clone()) {
145                            self.set_focus_root(None);
146                            return false;
147                        }
148                    }
149                } else {
150                    return self.focus_core(&keyboard_device, &restore, method, key_modifiers);
151                }
152            }
153        }
154
155        self.set_focus_root(None);
156        keyboard_device.set_focused_element_with(None, NavigationMethod::Unspecified, KeyModifiers::NONE, false);
157        false
158    }
159
160    fn focus_core(
161        &self,
162        keyboard_device: &KeyboardDevice,
163        element: &Ref<InputElement>,
164        method: NavigationMethod,
165        key_modifiers: KeyModifiers,
166    ) -> bool {
167        if !Self::can_focus(element) {
168            return false;
169        }
170
171        keyboard_device.set_focused_element(Some(element), method, key_modifiers);
172
173        if let Some(effectively_focused_element) = keyboard_device.focused_element() {
174            if let Some(scope) = Self::get_focus_scope(&effectively_focused_element) {
175                scope.set_value(
176                    Self::focused_element_property(),
177                    Some(crate::ElementRef::new(&effectively_focused_element)),
178                );
179                self.set_focus_root(Self::get_focus_root(&scope));
180            }
181
182            return effectively_focused_element == *element;
183        }
184
185        self.set_focus_root(None);
186        keyboard_device.set_focused_element_with(None, NavigationMethod::Unspecified, KeyModifiers::NONE, false);
187        false
188    }
189
190    pub(crate) fn clear_focus_on_element_removed(&self, removed_element: &InputElement, old_parent: &Visual) {
191        if let Some(parent_element) = old_parent.downcast_ref::<InputElement>() {
192            if let Some(scope) = Self::get_focus_scope(parent_element) {
193                if let Some(focused) = crate::ElementRef::resolve(&scope.get_value(Self::focused_element_property())) {
194                    if std::ptr::eq::<InputElement>(&*focused, removed_element) {
195                        scope.clear_value(Self::focused_element_property());
196                    }
197                }
198            }
199        }
200
201        if Self::current().is_some_and(|current| std::ptr::eq::<InputElement>(&*current, removed_element)) {
202            self.focus(None, NavigationMethod::Unspecified, KeyModifiers::NONE);
203        }
204    }
205
206    /// Gets the element that is focused within a focus scope.
207    pub fn get_focused_element_in_scope(&self, scope: &StyledElement) -> Option<Ref<InputElement>> {
208        crate::ElementRef::resolve(&scope.get_value(Self::focused_element_property()))
209    }
210
211    /// Sets the currently focused scope: focus moves to the element that
212    /// was last focused in the scope, or to the scope itself.
213    pub fn set_focus_scope(&self, scope: &Ref<InputElement>) {
214        let Some(keyboard_device) = KeyboardDevice::instance() else { return };
215
216        if let Some(focused) = self.get_focused_element_in_scope(scope) {
217            self.focus(Some(&focused), NavigationMethod::Unspecified, KeyModifiers::NONE);
218        } else if Self::can_focus(scope) {
219            // Focus the scope itself. Selecting the first focusable control
220            // or a control with default focus is left to keyboard
221            // navigation.
222            self.focus(Some(scope), NavigationMethod::Unspecified, KeyModifiers::NONE);
223        } else {
224            // If the scope isn't focusable, make sure we still set it as
225            // the current focus root, otherwise it will be completely
226            // ignored.
227            self.set_focus_root(Some(scope.clone().upcast()));
228            keyboard_device.set_focused_element_with(None, NavigationMethod::Unspecified, KeyModifiers::NONE, false);
229        }
230    }
231
232    /// Clears the focus if `scope` is the current focus root.
233    pub fn remove_focus_root(&self, scope: &StyledElement) {
234        if self.focus_root().is_some_and(|root| std::ptr::eq::<StyledElement>(&*root, scope)) {
235            self.focus(None, NavigationMethod::Unspecified, KeyModifiers::NONE);
236        }
237    }
238
239    /// Whether an element is a focus scope.
240    pub fn get_is_focus_scope(e: &InputElement) -> bool {
241        e.is_focus_scope()
242    }
243
244    /// The focus manager responsible for an element: the one of the input
245    /// root the element is attached to, or the fallback instance.
246    pub fn get_focus_manager(element: &InputElement) -> Option<Rc<FocusManager>> {
247        element.get_input_root().and_then(|root| root.focus_manager()).or_else(Self::locator_instance)
248    }
249
250    /// Whether an element can receive focus: it is focusable, effectively
251    /// enabled and visible.
252    pub fn can_focus(e: &InputElement) -> bool {
253        e.focusable() && e.is_effectively_enabled() && Self::is_visible(e)
254    }
255
256    fn can_pointer_focus(e: &InputElement, ev: &dyn IRoutedEventArgs) -> bool {
257        if !Self::can_focus(e) {
258            return false;
259        }
260
261        if let Some(released) = ev.downcast_ref::<PointerReleasedEventArgs>() {
262            return released.pointer().type_() != PointerType::Mouse;
263        }
264
265        if let Some(pressed) = ev.downcast_ref::<PointerPressedEventArgs>() {
266            return pressed.pointer().type_() == PointerType::Mouse;
267        }
268
269        false
270    }
271
272    fn get_focus_scope(control: &InputElement) -> Option<Ref<StyledElement>> {
273        let mut c = Some(control.to_ref());
274
275        while let Some(current) = c {
276            if current.is_focus_scope() && current.visual_root().is_some_and(|root| root.is_visible()) {
277                return Some(current.upcast());
278            }
279
280            c = current.get_visual_parent_of_type::<InputElement>().or_else(|| {
281                current
282                    .as_hosted_visual_tree_root()
283                    .and_then(|hosted| hosted.host())
284                    .and_then(|host| host.downcast::<InputElement>().ok())
285            });
286        }
287
288        None
289    }
290
291    fn get_focus_root(scope: &StyledElement) -> Option<Ref<StyledElement>> {
292        let visual = scope.downcast_ref::<Visual>()?;
293        let mut root = visual.get_input_root()?.focus_root();
294
295        loop {
296            let parent_root = root
297                .as_hosted_visual_tree_root()
298                .and_then(|hosted| hosted.host())
299                .and_then(|host| host.get_input_root())
300                .map(|input_root| input_root.focus_root());
301
302            match parent_root {
303                Some(parent_root) => root = parent_root,
304                None => break,
305            }
306        }
307
308        Some(root.upcast())
309    }
310
311    /// Global handler for pointer pressed and released: moves focus to the
312    /// nearest focusable element under the pointer.
313    fn on_preview_pointer_event_handler(sender: &Interactive, e: &dyn IRoutedEventArgs) {
314        let Some(ev) = e.downcast_ref::<PointerEventArgs>() else { return };
315
316        if !e.is_source(sender) {
317            return;
318        }
319
320        let left_pressed = ev.get_current_point(Some(sender)).properties.is_left_button_pressed;
321        let left_released = e
322            .downcast_ref::<PointerReleasedEventArgs>()
323            .is_some_and(|released| released.initial_press_mouse_button() == MouseButton::Left);
324
325        if !(left_pressed || left_released) {
326            return;
327        }
328
329        let mut element: Option<Ref<Visual>> = match ev.pointer().captured() {
330            Some(captured) => Some(captured.upcast()),
331            None => e.source().and_then(|source| source.downcast::<Visual>().ok()),
332        };
333
334        while let Some(current) = element {
335            if let Some(input_element) = current.downcast_ref::<InputElement>() {
336                if Self::can_pointer_focus(input_element, e) {
337                    input_element.focus_with(NavigationMethod::Pointer, ev.key_modifiers());
338                    break;
339                }
340            }
341
342            element = current.visual_parent();
343        }
344    }
345
346    fn is_visible(e: &InputElement) -> bool {
347        e.is_attached_to_visual_tree() && e.is_effectively_visible()
348    }
349
350    // --- navigation -------------------------------------------------------------
351
352    /// Attempts to change focus from the element with focus to the next
353    /// focusable element in the specified direction.
354    ///
355    /// Panics for directions other than next, previous, up, down, left and
356    /// right.
357    pub fn try_move_focus(&self, direction: NavigationDirection, options: Option<&FindNextElementOptions>) -> bool {
358        Self::validate_direction(direction);
359
360        let mut focus_options = self.to_focus_options(options, true);
361        let start = options.and_then(|o| o.focused_element.clone()).or_else(Self::current);
362        let result = self.find_and_set_next_focus(start.as_ref(), direction, &mut focus_options);
363        self.put_back_focus_options(focus_options);
364
365        result
366    }
367
368    fn content_root_has_input_element(&self) -> bool {
369        self.content_root().is_some()
370    }
371
372    /// Retrieves the first element that can receive focus within the
373    /// content root.
374    pub fn find_first_focusable_element(&self) -> Option<Element> {
375        if !self.content_root_has_input_element() {
376            return None;
377        }
378
379        self.get_first_focusable_element_from_root(false)
380    }
381
382    /// Retrieves the first element that can receive focus based on the
383    /// specified scope.
384    pub fn find_first_focusable_element_in(search_scope: &Element) -> Option<Element> {
385        Self::get_first_focusable_element(search_scope, None)
386    }
387
388    /// Retrieves the last element that can receive focus within the
389    /// content root.
390    pub fn find_last_focusable_element(&self) -> Option<Element> {
391        if !self.content_root_has_input_element() {
392            return None;
393        }
394
395        self.get_first_focusable_element_from_root(true)
396    }
397
398    /// Retrieves the last element that can receive focus based on the
399    /// specified scope.
400    pub fn find_last_focusable_element_in(search_scope: &Element) -> Option<Element> {
401        Self::get_focus_manager(search_scope).and_then(|manager| manager.get_last_focusable_element(search_scope, None))
402    }
403
404    /// Retrieves the element that should receive focus based on the
405    /// specified navigation direction, without moving focus.
406    ///
407    /// Panics for directions other than next, previous, up, down, left and
408    /// right.
409    pub fn find_next_element(
410        &self,
411        direction: NavigationDirection,
412        options: Option<&FindNextElementOptions>,
413    ) -> Option<Element> {
414        Self::validate_direction(direction);
415
416        let mut focus_options = self.to_focus_options(options, false);
417        let start = options.and_then(|o| o.focused_element.clone()).or_else(Self::current);
418        let result = self.find_next_focus(start.as_ref(), direction, &mut focus_options, true);
419        self.put_back_focus_options(focus_options);
420
421        result
422    }
423
424    fn validate_direction(direction: NavigationDirection) {
425        if !matches!(
426            direction,
427            NavigationDirection::Next
428                | NavigationDirection::Previous
429                | NavigationDirection::Up
430                | NavigationDirection::Down
431                | NavigationDirection::Left
432                | NavigationDirection::Right
433        ) {
434            panic!(
435                "Only Next, Previous, Up, Down, Left and Right directions are supported (got {direction:?})"
436            );
437        }
438    }
439
440    fn to_focus_options(&self, options: Option<&FindNextElementOptions>, update_manifold: bool) -> XYFocusOptions {
441        // XYFocus only uses the options and never modifies them; we can
442        // cache and reset them between calls.
443        let mut focus_options = match self.reusable_focus_options.borrow_mut().take() {
444            Some(mut options) => {
445                options.reset();
446                options
447            }
448            None => XYFocusOptions::new(),
449        };
450
451        if let Some(options) = options {
452            focus_options.search_root = options.search_root.clone();
453            focus_options.exclusion_rect = options.exclusion_rect;
454            focus_options.focus_hint_rectangle = options.focus_hint_rectangle;
455            focus_options.navigation_strategy_override = options.navigation_strategy_override;
456            focus_options.ignore_occlusivity = options.ignore_occlusivity;
457        }
458
459        focus_options.update_manifold = update_manifold;
460
461        focus_options
462    }
463
464    fn put_back_focus_options(&self, options: XYFocusOptions) {
465        let old = self.reusable_focus_options.replace(Some(options));
466        drop(old);
467    }
468
469    fn find_next_focus(
470        &self,
471        focused_element: Option<&Element>,
472        direction: NavigationDirection,
473        focus_options: &mut XYFocusOptions,
474        update_manifolds: bool,
475    ) -> Option<Element> {
476        match focused_element {
477            Some(focused) if !matches!(direction, NavigationDirection::Previous | NavigationDirection::Next) => {
478                if let Some(bounds) = XYFocus::get_bounds_for_ranking(focused, focus_options.ignore_clipping) {
479                    focus_options.focused_element_bounds = Some(bounds);
480                }
481
482                self.xy_focus.get_next_focusable_element(direction, Some(focused), None, update_manifolds, focus_options)
483            }
484            _ => {
485                let is_reverse = direction == NavigationDirection::Previous;
486                self.process_tab_stop_internal(focused_element, is_reverse, true)
487            }
488        }
489    }
490
491    pub(crate) fn get_first_focusable_element_internal(
492        search_start: &Element,
493        focus_candidate: Option<Element>,
494    ) -> Option<Element> {
495        let mut focus_candidate = focus_candidate;
496        let first_focusable_from_callback = search_start.get_first_focusable_element_override();
497        let use_first_focusable_from_callback = first_focusable_from_callback.as_ref().is_some_and(|first| {
498            FocusHelpers::is_focusable(Some(first)) || FocusHelpers::can_have_focusable_children(Some(first))
499        });
500
501        if use_first_focusable_from_callback {
502            let better = match &focus_candidate {
503                None => true,
504                Some(candidate) => {
505                    Self::get_tab_index(first_focusable_from_callback.as_ref()) < Self::get_tab_index(Some(candidate))
506                }
507            };
508            if better {
509                focus_candidate = first_focusable_from_callback;
510            }
511        } else {
512            for child in FocusHelpers::get_input_element_children(search_start) {
513                if !FocusHelpers::is_visible(&child) {
514                    continue;
515                }
516
517                let has_focusable_children = FocusHelpers::can_have_focusable_children(Some(&child));
518
519                if FocusHelpers::is_potential_tab_stop(Some(&child)) {
520                    if (FocusHelpers::is_focusable(Some(&child)) || has_focusable_children)
521                        && focus_candidate.as_ref().is_none_or(|candidate| {
522                            Self::get_tab_index(Some(&child)) < Self::get_tab_index(Some(candidate))
523                        })
524                    {
525                        focus_candidate = Some(child);
526                    }
527                } else if has_focusable_children {
528                    focus_candidate = Self::get_first_focusable_element_internal(&child, focus_candidate);
529                }
530            }
531        }
532
533        focus_candidate
534    }
535
536    pub(crate) fn get_last_focusable_element_internal(
537        search_start: &Element,
538        last_focus: Option<Element>,
539    ) -> Option<Element> {
540        let mut last_focus = last_focus;
541        let last_focusable_from_callback = search_start.get_last_focusable_element_override();
542        let use_last_focusable_from_callback = last_focusable_from_callback.as_ref().is_some_and(|last| {
543            FocusHelpers::is_focusable(Some(last)) || FocusHelpers::can_have_focusable_children(Some(last))
544        });
545
546        if use_last_focusable_from_callback {
547            let better = match &last_focus {
548                None => true,
549                Some(last) => Self::get_tab_index(last_focusable_from_callback.as_ref()) > Self::get_tab_index(Some(last)),
550            };
551            if better {
552                last_focus = last_focusable_from_callback;
553            }
554        } else {
555            for child in FocusHelpers::get_input_element_children(search_start) {
556                if !FocusHelpers::is_visible(&child) {
557                    continue;
558                }
559
560                let has_focusable_children = FocusHelpers::can_have_focusable_children(Some(&child));
561
562                if FocusHelpers::is_potential_tab_stop(Some(&child)) {
563                    if (FocusHelpers::is_focusable(Some(&child)) || has_focusable_children)
564                        && last_focus
565                            .as_ref()
566                            .is_none_or(|last| Self::get_tab_index(Some(&child)) >= Self::get_tab_index(Some(last)))
567                    {
568                        last_focus = Some(child);
569                    }
570                } else if has_focusable_children {
571                    last_focus = Self::get_last_focusable_element_internal(&child, last_focus);
572                }
573            }
574        }
575
576        last_focus
577    }
578
579    fn process_tab_stop_internal(
580        &self,
581        focused_element: Option<&Element>,
582        is_reverse: bool,
583        query_only: bool,
584    ) -> Option<Element> {
585        let (default_candidate_tab_stop, did_cycle_focus_at_root_visual_scope) =
586            self.get_tab_stop_candidate_element(focused_element, is_reverse, query_only);
587
588        let (is_tab_stop_overriden, new_tab_stop_from_callback) = InputElement::process_tab_stop(
589            self.content_root().as_ref(),
590            focused_element,
591            default_candidate_tab_stop.as_ref(),
592            is_reverse,
593            did_cycle_focus_at_root_visual_scope,
594        );
595
596        if is_tab_stop_overriden {
597            new_tab_stop_from_callback
598        } else {
599            default_candidate_tab_stop
600        }
601    }
602
603    fn get_tab_stop_candidate_element(
604        &self,
605        focused_element: Option<&Element>,
606        is_reverse: bool,
607        query_only: bool,
608    ) -> (Option<Element>, bool) {
609        let mut did_cycle_focus_at_root_visual_scope = false;
610        let Some(root) = self.content_root() else { return (None, false) };
611
612        let internal_cycle_workaround =
613            focused_element.is_some_and(|focused| self.can_process_tab_stop(focused, is_reverse));
614
615        let new_tab_stop = match focused_element {
616            None => {
617                did_cycle_focus_at_root_visual_scope = true;
618                if !is_reverse {
619                    Self::get_first_focusable_element(&root, None)
620                } else {
621                    self.get_last_focusable_element(&root, None)
622                }
623            }
624            Some(focused) if !is_reverse => {
625                let mut new_tab_stop = self.get_next_tab_stop(focused, false);
626
627                if new_tab_stop.is_none() && (internal_cycle_workaround || query_only) {
628                    new_tab_stop = Self::get_first_focusable_element(&root, None);
629                    did_cycle_focus_at_root_visual_scope = true;
630                }
631
632                new_tab_stop
633            }
634            Some(focused) => {
635                let mut new_tab_stop = self.get_previous_tab_stop(focused);
636
637                if new_tab_stop.is_none() && (internal_cycle_workaround || query_only) {
638                    new_tab_stop = self.get_last_focusable_element(&root, None);
639                    did_cycle_focus_at_root_visual_scope = true;
640                }
641
642                new_tab_stop
643            }
644        };
645
646        (new_tab_stop, did_cycle_focus_at_root_visual_scope)
647    }
648
649    fn content_root_visual_root(&self) -> Option<Element> {
650        self.content_root().and_then(|root| root.visual_root()).and_then(|root| root.downcast::<InputElement>().ok())
651    }
652
653    fn tab_navigation_of(element: &InputElement) -> KeyboardNavigationMode {
654        KeyboardNavigation::get_tab_navigation(element)
655    }
656
657    fn get_next_tab_stop(&self, focused: &Element, ignore_current_tab_stop: bool) -> Option<Element> {
658        self.content_root()?;
659
660        let mut current_compare = Some(focused.clone());
661        let mut new_tab_stop = focused.get_next_tab_stop_override();
662
663        if new_tab_stop.is_none() && !ignore_current_tab_stop && FocusHelpers::is_visible(focused) {
664            new_tab_stop = Self::get_first_focusable_element(focused, new_tab_stop);
665        }
666
667        if new_tab_stop.is_none() {
668            let mut current_passed = false;
669            let mut current = focused.clone();
670            let mut parent = FocusHelpers::get_focus_parent(Some(focused));
671            let visual_root = self.content_root_visual_root();
672            let mut parent_is_root_visual = parent == visual_root;
673
674            while let Some(p) = parent.clone() {
675                if parent_is_root_visual || new_tab_stop.is_some() {
676                    break;
677                }
678                let mut p = p;
679
680                if Self::is_valid_tab_stop_search_candidate(Some(&current))
681                    && Self::tab_navigation_of(&current) == KeyboardNavigationMode::Cycle
682                {
683                    new_tab_stop = if Some(&current) == Self::get_parent_tab_stop_element(Some(focused)).as_ref() {
684                        Self::get_first_focusable_element(focused, None)
685                    } else {
686                        Self::get_first_focusable_element(&current, Some(current.clone()))
687                    };
688                    break;
689                }
690
691                if Self::is_valid_tab_stop_search_candidate(Some(&p))
692                    && Self::tab_navigation_of(&p) == KeyboardNavigationMode::Once
693                {
694                    current = p;
695                    match FocusHelpers::get_focus_parent(Some(&current)) {
696                        Some(next_parent) => p = next_parent,
697                        None => break,
698                    }
699                } else if !Self::is_valid_tab_stop_search_candidate(Some(&p)) {
700                    match Self::get_parent_tab_stop_element(Some(&p)) {
701                        None => {
702                            // There is no popup sub tree to look into: fall
703                            // back to the root of the visual tree.
704                            match visual_root.clone() {
705                                Some(root) => p = root,
706                                None => {
707                                    new_tab_stop = Self::get_next_or_previous_tab_stop_internal(
708                                        None,
709                                        Some(&current),
710                                        new_tab_stop,
711                                        true,
712                                        &mut current_passed,
713                                        &mut current_compare,
714                                    );
715                                    break;
716                                }
717                            }
718                        }
719                        Some(parent_element)
720                            if Self::tab_navigation_of(&parent_element) == KeyboardNavigationMode::None =>
721                        {
722                            current = parent_element;
723                            match FocusHelpers::get_focus_parent(Some(&current)) {
724                                Some(next_parent) => p = next_parent,
725                                None => break,
726                            }
727                        }
728                        Some(parent_element) => p = parent_element,
729                    }
730                }
731
732                new_tab_stop = Self::get_next_or_previous_tab_stop_internal(
733                    Some(&p),
734                    Some(&current),
735                    new_tab_stop,
736                    true,
737                    &mut current_passed,
738                    &mut current_compare,
739                );
740
741                if let Some(stop) = &new_tab_stop {
742                    if !FocusHelpers::is_focusable(Some(stop)) && FocusHelpers::can_have_focusable_children(Some(stop)) {
743                        new_tab_stop = Self::get_first_focusable_element(stop, None);
744                    }
745                }
746
747                if new_tab_stop.is_some() {
748                    break;
749                }
750
751                if Self::is_valid_tab_stop_search_candidate(Some(&p)) {
752                    current = p.clone();
753                }
754
755                parent = FocusHelpers::get_focus_parent(Some(&p));
756                current_passed = false;
757                parent_is_root_visual = parent == visual_root;
758            }
759        }
760
761        new_tab_stop
762    }
763
764    fn get_previous_tab_stop(&self, focused: &Element) -> Option<Element> {
765        self.content_root()?;
766
767        let mut new_tab_stop = focused.get_previous_tab_stop_override();
768        let mut current_compare = Some(focused.clone());
769
770        if new_tab_stop.is_none() {
771            let mut current_passed = false;
772            let mut current = focused.clone();
773            let mut parent = FocusHelpers::get_focus_parent(Some(focused));
774            let visual_root = self.content_root_visual_root();
775            let parent_is_root_visual = parent == visual_root;
776
777            while let Some(p) = parent.clone() {
778                if parent_is_root_visual || new_tab_stop.is_some() {
779                    break;
780                }
781                let mut p = p;
782
783                if Self::is_valid_tab_stop_search_candidate(Some(&current))
784                    && Self::tab_navigation_of(&current) == KeyboardNavigationMode::Cycle
785                {
786                    new_tab_stop = self.get_last_focusable_element(&current, Some(current.clone()));
787                    break;
788                }
789
790                if Self::is_valid_tab_stop_search_candidate(Some(&p))
791                    && Self::tab_navigation_of(&p) == KeyboardNavigationMode::Once
792                {
793                    if FocusHelpers::is_focusable(Some(&p)) {
794                        new_tab_stop = Some(p.clone());
795                    } else {
796                        current = p;
797                        match FocusHelpers::get_focus_parent(Some(&current)) {
798                            Some(next_parent) => p = next_parent,
799                            None => break,
800                        }
801                    }
802                } else if !Self::is_valid_tab_stop_search_candidate(Some(&p)) {
803                    match Self::get_parent_tab_stop_element(Some(&p)) {
804                        None => match visual_root.clone() {
805                            Some(root) => p = root,
806                            None => {
807                                new_tab_stop = Self::get_next_or_previous_tab_stop_internal(
808                                    None,
809                                    Some(&current),
810                                    new_tab_stop,
811                                    false,
812                                    &mut current_passed,
813                                    &mut current_compare,
814                                );
815                                break;
816                            }
817                        },
818                        Some(parent_element)
819                            if Self::tab_navigation_of(&parent_element) == KeyboardNavigationMode::None =>
820                        {
821                            if FocusHelpers::is_focusable(Some(&p)) {
822                                new_tab_stop = Some(p.clone());
823                            } else {
824                                current = p;
825                                match FocusHelpers::get_focus_parent(Some(&current)) {
826                                    Some(next_parent) => p = next_parent,
827                                    None => break,
828                                }
829                            }
830                        }
831                        Some(parent_element) => p = parent_element,
832                    }
833                }
834
835                new_tab_stop = Self::get_next_or_previous_tab_stop_internal(
836                    Some(&p),
837                    Some(&current),
838                    new_tab_stop,
839                    false,
840                    &mut current_passed,
841                    &mut current_compare,
842                );
843
844                if new_tab_stop.is_none()
845                    && FocusHelpers::is_potential_tab_stop(Some(&p))
846                    && FocusHelpers::is_focusable(Some(&p))
847                {
848                    new_tab_stop = if Self::tab_navigation_of(&p) == KeyboardNavigationMode::Cycle {
849                        self.get_last_focusable_element(&p, None)
850                    } else {
851                        Some(p.clone())
852                    };
853                } else if let Some(stop) = &new_tab_stop {
854                    if FocusHelpers::can_have_focusable_children(Some(stop)) {
855                        new_tab_stop = self.get_last_focusable_element(stop, None);
856                    }
857                }
858
859                if new_tab_stop.is_some() {
860                    break;
861                }
862
863                if Self::is_valid_tab_stop_search_candidate(Some(&p)) {
864                    current = p.clone();
865                }
866
867                parent = FocusHelpers::get_focus_parent(Some(&p));
868                current_passed = false;
869            }
870        }
871
872        new_tab_stop
873    }
874
875    fn get_next_or_previous_tab_stop_internal(
876        parent: Option<&Element>,
877        current: Option<&Element>,
878        candidate: Option<Element>,
879        find_next: bool,
880        current_passed: &mut bool,
881        current_compare: &mut Option<Element>,
882    ) -> Option<Element> {
883        let mut new_tab_stop = candidate;
884
885        if Self::is_valid_tab_stop_search_candidate(current) {
886            *current_compare = current.cloned();
887        }
888
889        let Some(parent) = parent else { return new_tab_stop };
890        let mut found_current = false;
891
892        for child in FocusHelpers::get_input_element_children(parent) {
893            let mut child_stop: Option<Element> = None;
894            let mut compare_current_for_previous_element = false;
895
896            if Some(&child) == current {
897                found_current = true;
898                *current_passed = true;
899                continue;
900            }
901
902            if FocusHelpers::is_visible(&child) {
903                if Self::is_valid_tab_stop_search_candidate(Some(&child)) {
904                    if !FocusHelpers::is_potential_tab_stop(Some(&child)) {
905                        // The recursion is made on the (still empty) child
906                        // stop upstream, which yields the current candidate.
907                        child_stop = Self::get_next_or_previous_tab_stop_internal(
908                            None,
909                            current,
910                            new_tab_stop.clone(),
911                            find_next,
912                            current_passed,
913                            current_compare,
914                        );
915                        compare_current_for_previous_element = true;
916                    } else {
917                        child_stop = Some(child.clone());
918                    }
919                } else if FocusHelpers::can_have_focusable_children(Some(&child)) {
920                    child_stop = Self::get_next_or_previous_tab_stop_internal(
921                        Some(&child),
922                        current,
923                        new_tab_stop.clone(),
924                        find_next,
925                        current_passed,
926                        current_compare,
927                    );
928                    compare_current_for_previous_element = true;
929                }
930            }
931
932            let Some(child_stop) = child_stop else { continue };
933
934            if FocusHelpers::is_focusable(Some(&child_stop))
935                || FocusHelpers::can_have_focusable_children(Some(&child_stop))
936            {
937                let compare_index_result = Self::compare_tab_index(Some(&child_stop), current_compare.as_ref());
938
939                let accept = if find_next {
940                    (compare_index_result > 0 || ((found_current || *current_passed) && compare_index_result == 0))
941                        && new_tab_stop
942                            .as_ref()
943                            .is_none_or(|stop| Self::compare_tab_index(Some(&child_stop), Some(stop)) < 0)
944                } else {
945                    (compare_index_result < 0
946                        || (((!found_current && !*current_passed) || compare_current_for_previous_element)
947                            && compare_index_result == 0))
948                        && new_tab_stop
949                            .as_ref()
950                            .is_none_or(|stop| Self::compare_tab_index(Some(&child_stop), Some(stop)) >= 0)
951                };
952
953                if accept {
954                    new_tab_stop = Some(child_stop);
955                }
956            }
957        }
958
959        new_tab_stop
960    }
961
962    fn compare_tab_index(control1: Option<&Element>, control2: Option<&Element>) -> i32 {
963        match Self::get_tab_index(control1).cmp(&Self::get_tab_index(control2)) {
964            std::cmp::Ordering::Less => -1,
965            std::cmp::Ordering::Equal => 0,
966            std::cmp::Ordering::Greater => 1,
967        }
968    }
969
970    fn get_tab_index(element: Option<&Element>) -> i32 {
971        element.map_or(i32::MAX, |element| element.tab_index())
972    }
973
974    fn can_process_tab_stop(&self, focused_element: &Element, is_reverse: bool) -> bool {
975        let mut is_focus_on_first = false;
976        let mut is_focus_on_last = false;
977        let mut can_process_tab = true;
978
979        if is_reverse {
980            is_focus_on_first = self.is_focus_on_first_tab_stop(focused_element);
981        } else {
982            is_focus_on_last = self.is_focus_on_last_tab_stop(focused_element);
983        }
984
985        if is_focus_on_first || is_focus_on_last {
986            can_process_tab = false;
987        }
988
989        if can_process_tab {
990            match self.get_first_focusable_element_from_root(!is_reverse) {
991                Some(edge) => {
992                    let edge_parent = Self::get_parent_tab_stop_element(Some(&edge));
993                    if let Some(edge_parent) = &edge_parent {
994                        if Self::tab_navigation_of(edge_parent) == KeyboardNavigationMode::Once
995                            && Some(edge_parent) == Self::get_parent_tab_stop_element(Some(focused_element)).as_ref()
996                        {
997                            can_process_tab = false;
998                        }
999                    }
1000                }
1001                None => can_process_tab = false,
1002            }
1003        } else if Self::tab_navigation_of(focused_element) == KeyboardNavigationMode::Cycle {
1004            can_process_tab = true;
1005        } else {
1006            let mut focused_parent = Self::get_parent_tab_stop_element(Some(focused_element));
1007            while let Some(parent) = focused_parent {
1008                if Self::tab_navigation_of(&parent) == KeyboardNavigationMode::Cycle {
1009                    can_process_tab = true;
1010                    break;
1011                }
1012
1013                focused_parent = Self::get_parent_tab_stop_element(Some(&parent));
1014            }
1015        }
1016
1017        can_process_tab
1018    }
1019
1020    fn get_parent_tab_stop_element(current: Option<&Element>) -> Option<Element> {
1021        let mut parent = FocusHelpers::get_focus_parent(current.map(|c| &**c));
1022
1023        while let Some(p) = parent {
1024            if Self::is_valid_tab_stop_search_candidate(Some(&p)) {
1025                return Some(p);
1026            }
1027
1028            parent = FocusHelpers::get_focus_parent(Some(&p));
1029        }
1030
1031        None
1032    }
1033
1034    fn is_valid_tab_stop_search_candidate(element: Option<&Element>) -> bool {
1035        FocusHelpers::is_potential_tab_stop(element.map(|e| &**e))
1036            || element.is_some_and(|e| e.is_set(KeyboardNavigation::tab_navigation_property()))
1037    }
1038
1039    fn get_first_focusable_element_from_root(&self, is_reverse: bool) -> Option<Element> {
1040        let root = self.content_root_visual_root()?;
1041
1042        if !is_reverse {
1043            Self::get_first_focusable_element(&root, None)
1044        } else {
1045            self.get_last_focusable_element(&root, None)
1046        }
1047    }
1048
1049    fn is_focus_on_last_tab_stop(&self, focused_element: &Element) -> bool {
1050        let Some(root) = self.content_root_visual_root() else { return false };
1051        self.get_last_focusable_element(&root, None).as_ref() == Some(focused_element)
1052    }
1053
1054    fn is_focus_on_first_tab_stop(&self, focused_element: &Element) -> bool {
1055        let Some(root) = self.content_root_visual_root() else { return false };
1056        Self::get_first_focusable_element(&root, None).as_ref() == Some(focused_element)
1057    }
1058
1059    fn get_first_focusable_element(search_start: &Element, first_focus: Option<Element>) -> Option<Element> {
1060        let mut first_focus = Self::get_first_focusable_element_internal(search_start, first_focus);
1061
1062        if let Some(first) = &first_focus {
1063            if !first.focusable() && FocusHelpers::can_have_focusable_children(Some(first)) {
1064                first_focus = Self::get_first_focusable_element(first, None);
1065            }
1066        }
1067
1068        first_focus
1069    }
1070
1071    fn get_last_focusable_element(&self, search_start: &Element, last_focus: Option<Element>) -> Option<Element> {
1072        let mut last_focus = Self::get_last_focusable_element_internal(search_start, last_focus);
1073
1074        if let Some(last) = &last_focus {
1075            if !last.focusable() && FocusHelpers::can_have_focusable_children(Some(last)) {
1076                last_focus = self.get_last_focusable_element(last, None);
1077            }
1078        }
1079
1080        last_focus
1081    }
1082
1083    fn find_and_set_next_focus(
1084        &self,
1085        focused_element: Option<&Element>,
1086        direction: NavigationDirection,
1087        xy_focus_options: &mut XYFocusOptions,
1088    ) -> bool {
1089        let mut focus_changed = false;
1090
1091        if xy_focus_options.update_manifolds_from_focus_hint_rect {
1092            if let Some(hint) = xy_focus_options.focus_hint_rectangle {
1093                self.xy_focus.set_manifolds_from_bounds(hint);
1094            }
1095        }
1096
1097        if let Some(next_focused_element) = self.find_next_focus(focused_element, direction, xy_focus_options, false) {
1098            focus_changed = next_focused_element.focus();
1099
1100            if focus_changed && xy_focus_options.update_manifold {
1101                let bounds = xy_focus_options
1102                    .focus_hint_rectangle
1103                    .or(xy_focus_options.focused_element_bounds)
1104                    .unwrap_or_default();
1105
1106                self.xy_focus.update_manifolds(
1107                    direction,
1108                    bounds,
1109                    &next_focused_element,
1110                    xy_focus_options.ignore_clipping,
1111                );
1112            }
1113        }
1114
1115        focus_changed
1116    }
1117}
1118
1119impl IFocusManager for FocusManager {
1120    fn get_focused_element(&self) -> Option<Ref<InputElement>> {
1121        FocusManager::get_focused_element(self)
1122    }
1123
1124    fn focus(
1125        &self,
1126        element: Option<&Ref<InputElement>>,
1127        method: NavigationMethod,
1128        key_modifiers: KeyModifiers,
1129    ) -> bool {
1130        FocusManager::focus(self, element, method, key_modifiers)
1131    }
1132
1133    fn try_move_focus(&self, direction: NavigationDirection, options: Option<&FindNextElementOptions>) -> bool {
1134        FocusManager::try_move_focus(self, direction, options)
1135    }
1136
1137    fn find_first_focusable_element(&self) -> Option<Ref<InputElement>> {
1138        FocusManager::find_first_focusable_element(self)
1139    }
1140
1141    fn find_last_focusable_element(&self) -> Option<Ref<InputElement>> {
1142        FocusManager::find_last_focusable_element(self)
1143    }
1144
1145    fn find_next_element(
1146        &self,
1147        direction: NavigationDirection,
1148        options: Option<&FindNextElementOptions>,
1149    ) -> Option<Ref<InputElement>> {
1150        FocusManager::find_next_element(self, direction, options)
1151    }
1152
1153    fn as_any(&self) -> &dyn std::any::Any {
1154        self
1155    }
1156}