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
16pub 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 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 fn static_constructor() {
46 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 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 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 pub fn content_root(&self) -> Option<Ref<InputElement>> {
86 self.content_root.borrow().clone()
87 }
88
89 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 pub fn get_focused_element(&self) -> Option<Ref<InputElement>> {
110 Self::current()
111 }
112
113 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 focus_root.clear_value(Self::focused_element_property());
141
142 if let Some(current) = ¤t {
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 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 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 self.focus(Some(scope), NavigationMethod::Unspecified, KeyModifiers::NONE);
223 } else {
224 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 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 pub fn get_is_focus_scope(e: &InputElement) -> bool {
241 e.is_focus_scope()
242 }
243
244 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 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 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 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 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 pub fn find_first_focusable_element_in(search_scope: &Element) -> Option<Element> {
385 Self::get_first_focusable_element(search_scope, None)
386 }
387
388 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 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 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 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(¤t))
681 && Self::tab_navigation_of(¤t) == KeyboardNavigationMode::Cycle
682 {
683 new_tab_stop = if Some(¤t) == 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(¤t, 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(¤t)) {
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 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(¤t),
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(¤t)) {
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(¤t),
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(¤t))
784 && Self::tab_navigation_of(¤t) == KeyboardNavigationMode::Cycle
785 {
786 new_tab_stop = self.get_last_focusable_element(¤t, 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(¤t)) {
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(¤t),
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(¤t)) {
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(¤t),
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 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}