1use std::fmt;
2use std::sync::atomic::Ordering::Relaxed;
3
4use atomic::Atomic;
5use parking_lot::Mutex;
6use zng_app::{
7 widget::{
8 WidgetId,
9 info::{TreeFilter, Visibility, WeakWidgetInfoTree, WidgetInfo, WidgetInfoBuilder, WidgetInfoTree, WidgetPath},
10 },
11 window::WindowId,
12};
13use zng_ext_window::NestedWindowWidgetInfoExt;
14use zng_layout::unit::{DistanceKey, Orientation2D, Px, PxBox, PxPoint, PxRect, PxSize};
15use zng_state_map::{StateId, static_id};
16use zng_unique_id::IdSet;
17use zng_var::impl_from_and_into_var;
18use zng_view_api::window::FocusIndicator;
19
20use zng_app::widget::info::iter as w_iter;
21
22use super::iter::IterFocusableExt;
23
24#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
28pub struct TabIndex(pub u32);
29impl TabIndex {
30 pub const SKIP: TabIndex = TabIndex(u32::MAX);
34
35 pub const AUTO: TabIndex = TabIndex(u32::MAX / 2);
42
43 pub const LAST: TabIndex = TabIndex(u32::MAX - 1);
45
46 pub fn is_skip(self) -> bool {
48 self == Self::SKIP
49 }
50
51 pub fn is_auto(self) -> bool {
53 self == Self::AUTO
54 }
55
56 pub fn is_before_auto(self) -> bool {
58 self.0 < Self::AUTO.0
59 }
60
61 pub fn is_after_auto(self) -> bool {
63 self.0 > Self::AUTO.0
64 }
65
66 pub fn not_skip(index: u32) -> Self {
70 TabIndex(if index == Self::SKIP.0 { Self::SKIP.0 - 1 } else { index })
71 }
72
73 pub fn before_auto(index: u32) -> Self {
77 TabIndex(if index >= Self::AUTO.0 { Self::AUTO.0 - 1 } else { index })
78 }
79
80 pub fn after_auto(index: u32) -> Self {
86 Self::not_skip((Self::AUTO.0 + 1).saturating_add(index))
87 }
88}
89impl fmt::Debug for TabIndex {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 if f.alternate() {
92 if self.is_auto() {
93 write!(f, "TabIndex::AUTO")
94 } else if self.is_skip() {
95 write!(f, "TabIndex::SKIP")
96 } else if self.is_after_auto() {
97 write!(f, "TabIndex::after_auto({})", self.0 - Self::AUTO.0 - 1)
98 } else {
99 write!(f, "TabIndex({})", self.0)
100 }
101 } else {
102 if self.is_auto() {
104 write!(f, "AUTO")
105 } else if self.is_skip() {
106 write!(f, "SKIP")
107 } else if self.is_after_auto() {
108 write!(f, "after_auto({})", self.0 - Self::AUTO.0 - 1)
109 } else {
110 write!(f, "{}", self.0)
111 }
112 }
113 }
114}
115impl Default for TabIndex {
116 fn default() -> Self {
118 TabIndex::AUTO
119 }
120}
121impl_from_and_into_var! {
122 fn from(index: u32) -> TabIndex {
124 TabIndex::not_skip(index)
125 }
126}
127#[derive(serde::Serialize, serde::Deserialize)]
128#[serde(untagged)]
129enum TabIndexSerde<'s> {
130 Named(&'s str),
131 Unnamed(u32),
132}
133impl serde::Serialize for TabIndex {
134 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
135 where
136 S: serde::Serializer,
137 {
138 if serializer.is_human_readable() {
139 let name = if self.is_auto() {
140 Some("AUTO")
141 } else if self.is_skip() {
142 Some("SKIP")
143 } else {
144 None
145 };
146 if let Some(name) = name {
147 return TabIndexSerde::Named(name).serialize(serializer);
148 }
149 }
150 TabIndexSerde::Unnamed(self.0).serialize(serializer)
151 }
152}
153impl<'de> serde::Deserialize<'de> for TabIndex {
154 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155 where
156 D: serde::Deserializer<'de>,
157 {
158 use serde::de::Error;
159
160 match TabIndexSerde::deserialize(deserializer)? {
161 TabIndexSerde::Named(name) => match name {
162 "AUTO" => Ok(TabIndex::AUTO),
163 "SKIP" => Ok(TabIndex::SKIP),
164 unknown => Err(D::Error::unknown_variant(unknown, &["AUTO", "SKIP"])),
165 },
166 TabIndexSerde::Unnamed(i) => Ok(TabIndex(i)),
167 }
168 }
169}
170
171#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
175pub enum TabNav {
176 None,
178 Continue,
180 Contained,
182 Cycle,
184 Once,
186}
187impl fmt::Debug for TabNav {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 if f.alternate() {
190 write!(f, "TabNav::")?;
191 }
192 match self {
193 TabNav::None => write!(f, "None"),
194 TabNav::Continue => write!(f, "Continue"),
195 TabNav::Contained => write!(f, "Contained"),
196 TabNav::Cycle => write!(f, "Cycle"),
197 TabNav::Once => write!(f, "Once"),
198 }
199 }
200}
201
202#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
206pub enum DirectionalNav {
207 None,
209 Continue,
211 Contained,
213 Cycle,
215}
216impl fmt::Debug for DirectionalNav {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 if f.alternate() {
219 write!(f, "DirectionalNav::")?;
220 }
221 match self {
222 DirectionalNav::None => write!(f, "None"),
223 DirectionalNav::Continue => write!(f, "Continue"),
224 DirectionalNav::Contained => write!(f, "Contained"),
225 DirectionalNav::Cycle => write!(f, "Cycle"),
226 }
227 }
228}
229
230#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
236pub struct FocusRequest {
237 pub target: FocusTarget,
239 pub highlight: bool,
241
242 pub force_window_focus: bool,
247
248 pub window_indicator: Option<FocusIndicator>,
251
252 pub fallback_only: bool,
254}
255
256impl FocusRequest {
257 pub fn new(target: FocusTarget, highlight: bool) -> Self {
259 Self {
260 target,
261 highlight,
262 force_window_focus: false,
263 window_indicator: None,
264 fallback_only: false,
265 }
266 }
267
268 pub fn direct(widget_id: WidgetId, highlight: bool) -> Self {
270 Self::new(FocusTarget::Direct { target: widget_id }, highlight)
271 }
272 pub fn direct_or_exit(widget_id: WidgetId, navigation_origin: bool, highlight: bool) -> Self {
274 Self::new(
275 FocusTarget::DirectOrExit {
276 target: widget_id,
277 navigation_origin,
278 },
279 highlight,
280 )
281 }
282 pub fn direct_or_enter(widget_id: WidgetId, navigation_origin: bool, highlight: bool) -> Self {
284 Self::new(
285 FocusTarget::DirectOrEnter {
286 target: widget_id,
287 navigation_origin,
288 },
289 highlight,
290 )
291 }
292 pub fn direct_or_related(widget_id: WidgetId, navigation_origin: bool, highlight: bool) -> Self {
294 Self::new(
295 FocusTarget::DirectOrRelated {
296 target: widget_id,
297 navigation_origin,
298 },
299 highlight,
300 )
301 }
302 pub fn enter(highlight: bool) -> Self {
304 Self::new(FocusTarget::Enter, highlight)
305 }
306 pub fn exit(recursive_alt: bool, highlight: bool) -> Self {
308 Self::new(FocusTarget::Exit { recursive_alt }, highlight)
309 }
310 pub fn next(highlight: bool) -> Self {
312 Self::new(FocusTarget::Next, highlight)
313 }
314 pub fn prev(highlight: bool) -> Self {
316 Self::new(FocusTarget::Prev, highlight)
317 }
318 pub fn up(highlight: bool) -> Self {
320 Self::new(FocusTarget::Up, highlight)
321 }
322 pub fn right(highlight: bool) -> Self {
324 Self::new(FocusTarget::Right, highlight)
325 }
326 pub fn down(highlight: bool) -> Self {
328 Self::new(FocusTarget::Down, highlight)
329 }
330 pub fn left(highlight: bool) -> Self {
332 Self::new(FocusTarget::Left, highlight)
333 }
334 pub fn alt(highlight: bool) -> Self {
336 Self::new(FocusTarget::Alt, highlight)
337 }
338
339 pub fn with_force_window_focus(mut self) -> Self {
341 self.force_window_focus = true;
342 self
343 }
344
345 pub fn with_indicator(mut self, indicator: FocusIndicator) -> Self {
347 self.window_indicator = Some(indicator);
348 self
349 }
350}
351
352#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
354pub enum FocusTarget {
355 Direct {
357 target: WidgetId,
359 },
360 DirectOrExit {
362 target: WidgetId,
364 navigation_origin: bool,
368 },
369 DirectOrEnter {
371 target: WidgetId,
373 navigation_origin: bool,
378 },
379 DirectOrRelated {
382 target: WidgetId,
384 navigation_origin: bool,
389 },
390
391 Enter,
393 Exit {
395 recursive_alt: bool,
397 },
398
399 Next,
401 Prev,
403
404 Up,
406 Right,
408 Down,
410 Left,
412
413 Alt,
415}
416
417bitflags! {
418 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
420 pub struct FocusNavAction: u16 {
421 const ENTER = 0b0000_0000_0001;
423 const EXIT = 0b0000_0000_0010;
425
426 const NEXT = 0b0000_0000_0100;
428 const PREV = 0b0000_0000_1000;
430
431 const UP = 0b0000_0001_0000;
433 const RIGHT = 0b0000_0010_0000;
435 const DOWN = 0b0000_0100_0000;
437 const LEFT = 0b0000_1000_0000;
439
440 const ALT = 0b0001_0000_0000;
442
443 const DIRECTIONAL =
445 FocusNavAction::UP.bits() | FocusNavAction::RIGHT.bits() | FocusNavAction::DOWN.bits() | FocusNavAction::LEFT.bits();
446 }
447}
448
449bitflags! {
450 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
451 pub(super) struct FocusMode: u8 {
452 const DISABLED = 1;
454 const HIDDEN = 2;
456 }
457}
458impl FocusMode {
459 pub fn new(focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Self {
460 let mut mode = FocusMode::empty();
461 mode.set(FocusMode::DISABLED, focus_disabled_widgets);
462 mode.set(FocusMode::HIDDEN, focus_hidden_widgets);
463 mode
464 }
465}
466
467#[derive(Clone, Debug)]
471pub struct FocusInfoTree {
472 tree: WidgetInfoTree,
473 mode: FocusMode,
474}
475impl FocusInfoTree {
476 pub fn new(tree: WidgetInfoTree, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Self {
483 FocusInfoTree {
484 tree,
485 mode: FocusMode::new(focus_disabled_widgets, focus_hidden_widgets),
486 }
487 }
488
489 pub fn tree(&self) -> &WidgetInfoTree {
491 &self.tree
492 }
493
494 pub fn focus_disabled_widgets(&self) -> bool {
501 self.mode.contains(FocusMode::DISABLED)
502 }
503
504 pub fn focus_hidden_widgets(&self) -> bool {
511 self.mode.contains(FocusMode::HIDDEN)
512 }
513
514 pub fn root(&self) -> WidgetFocusInfo {
519 WidgetFocusInfo {
520 info: self.tree.root(),
521 mode: self.mode,
522 }
523 }
524
525 pub fn focusable_root(&self) -> Option<WidgetFocusInfo> {
530 let root = self.root();
531 if root.is_focusable() {
532 return Some(root);
533 }
534
535 let mut candidate = None;
536 let mut candidate_weight = usize::MAX;
537
538 for w in root.descendants().tree_filter(|_| TreeFilter::SkipDescendants) {
539 let weight = w.info.prev_siblings().count() + w.info.ancestors().count();
540 if weight < candidate_weight {
541 candidate = Some(w);
542 candidate_weight = weight;
543 }
544 }
545
546 candidate
547 }
548
549 pub fn get(&self, widget_id: impl Into<WidgetId>) -> Option<WidgetFocusInfo> {
551 self.tree
552 .get(widget_id)
553 .and_then(|i| i.into_focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets()))
554 }
555
556 pub fn get_or_parent(&self, path: &WidgetPath) -> Option<WidgetFocusInfo> {
558 self.get(path.widget_id())
559 .or_else(|| path.ancestors().iter().rev().find_map(|&id| self.get(id)))
560 }
561
562 pub fn contains(&self, widget_id: impl Into<WidgetId>) -> bool {
564 self.get(widget_id).is_some()
565 }
566}
567
568pub trait WidgetInfoFocusExt {
572 fn into_focus_info(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> WidgetFocusInfo;
580 fn into_focusable(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Option<WidgetFocusInfo>;
588}
589impl WidgetInfoFocusExt for WidgetInfo {
590 fn into_focus_info(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> WidgetFocusInfo {
591 WidgetFocusInfo::new(self, focus_disabled_widgets, focus_hidden_widgets)
592 }
593 fn into_focusable(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Option<WidgetFocusInfo> {
594 let r = self.into_focus_info(focus_disabled_widgets, focus_hidden_widgets);
595 if r.is_focusable() { Some(r) } else { None }
596 }
597}
598
599#[derive(Clone, Eq, PartialEq, Hash, Debug)]
603pub struct WidgetFocusInfo {
604 info: WidgetInfo,
605 mode: FocusMode,
606}
607impl WidgetFocusInfo {
608 pub fn new(widget_info: WidgetInfo, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Self {
615 WidgetFocusInfo {
616 info: widget_info,
617 mode: FocusMode::new(focus_disabled_widgets, focus_hidden_widgets),
618 }
619 }
620
621 pub fn info(&self) -> &WidgetInfo {
623 &self.info
624 }
625
626 pub fn focus_disabled_widgets(&self) -> bool {
633 self.mode.contains(FocusMode::DISABLED)
634 }
635
636 pub fn focus_hidden_widgets(&self) -> bool {
643 self.mode.contains(FocusMode::HIDDEN)
644 }
645
646 pub fn root(&self) -> Self {
648 self.ancestors().last().unwrap_or_else(|| self.clone())
649 }
650
651 pub fn focus_tree(&self) -> FocusInfoTree {
653 FocusInfoTree {
654 tree: self.info.tree().clone(),
655 mode: self.mode,
656 }
657 }
658
659 pub fn is_focusable(&self) -> bool {
668 self.focus_info().is_focusable()
669 }
670
671 pub fn is_scope(&self) -> bool {
673 self.focus_info().is_scope()
674 }
675
676 pub fn is_alt_scope(&self) -> bool {
678 self.focus_info().is_alt_scope()
679 }
680
681 pub fn nested_window(&self) -> Option<WindowId> {
685 self.info.nested_window()
686 }
687
688 pub fn nested_window_tree(&self) -> Option<FocusInfoTree> {
690 self.info
691 .nested_window_tree()
692 .map(|t| FocusInfoTree::new(t, self.focus_disabled_widgets(), self.focus_hidden_widgets()))
693 }
694
695 fn mode_allows_focus(&self) -> bool {
696 let int = self.info.interactivity();
697 if self.mode.contains(FocusMode::DISABLED) {
698 if int.is_blocked() {
699 return false;
700 }
701 } else if !int.is_enabled() {
702 return false;
703 }
704
705 let vis = self.info.visibility();
706 if self.mode.contains(FocusMode::HIDDEN) {
707 if vis == Visibility::Collapsed {
708 return false;
709 }
710 } else if vis != Visibility::Visible {
711 return false;
712 }
713
714 true
715 }
716
717 fn mode_allows_focus_ignore_blocked(&self) -> bool {
718 let int = self.info.interactivity();
719 if !self.mode.contains(FocusMode::DISABLED) && int.is_vis_disabled() {
720 return false;
721 }
722
723 let vis = self.info.visibility();
724 if self.mode.contains(FocusMode::HIDDEN) {
725 if vis == Visibility::Collapsed {
726 return false;
727 }
728 } else if vis != Visibility::Visible {
729 return false;
730 }
731
732 true
733 }
734
735 pub fn focus_info(&self) -> FocusInfo {
737 if self.mode_allows_focus() {
738 if let Some(builder) = self.info.meta().get(*FOCUS_INFO_ID) {
739 return builder.build();
740 } else if self.info.nested_window().is_some() {
741 return FocusInfo::FocusScope {
743 tab_index: TabIndex::AUTO,
744 skip_directional: false,
745 tab_nav: TabNav::Contained,
746 directional_nav: DirectionalNav::Contained,
747 on_focus: FocusScopeOnFocus::FirstDescendant,
748 alt: false,
749 };
750 }
751 }
752 FocusInfo::NotFocusable
753 }
754
755 pub fn focus_info_ignore_blocked(&self) -> FocusInfo {
757 if self.mode_allows_focus_ignore_blocked()
758 && let Some(builder) = self.info.meta().get(*FOCUS_INFO_ID)
759 {
760 return builder.build();
761 }
762 FocusInfo::NotFocusable
763 }
764
765 pub fn ancestors(&self) -> impl Iterator<Item = WidgetFocusInfo> {
767 let focus_disabled_widgets = self.focus_disabled_widgets();
768 let focus_hidden_widgets = self.focus_hidden_widgets();
769 self.info.ancestors().focusable(focus_disabled_widgets, focus_hidden_widgets)
770 }
771
772 pub fn self_and_ancestors(&self) -> impl Iterator<Item = WidgetFocusInfo> {
774 [self.clone()].into_iter().chain(self.ancestors())
775 }
776
777 pub fn scopes(&self) -> impl Iterator<Item = WidgetFocusInfo> {
779 let focus_disabled_widgets = self.focus_disabled_widgets();
780 let focus_hidden_widgets = self.focus_hidden_widgets();
781 self.info.ancestors().filter_map(move |i| {
782 let i = i.into_focus_info(focus_disabled_widgets, focus_hidden_widgets);
783 if i.is_scope() { Some(i) } else { None }
784 })
785 }
786
787 pub fn parent(&self) -> Option<WidgetFocusInfo> {
789 self.ancestors().next()
790 }
791
792 pub fn scope(&self) -> Option<WidgetFocusInfo> {
794 self.scopes().next()
795 }
796
797 pub fn alt_scope(&self) -> Option<WidgetFocusInfo> {
805 if self.in_alt_scope() {
806 let mut alt_scope = self.clone();
808 for scope in self.scopes() {
809 if scope.is_alt_scope() {
810 alt_scope = scope;
811 } else {
812 return scope.inner_alt_scope_skip(&alt_scope);
813 }
814 }
815 return None;
816 }
817
818 if self.is_scope() {
819 let r = self.inner_alt_scope();
821 if r.is_some() {
822 return r;
823 }
824 }
825
826 let mut skip = self.clone();
828 for scope in self.scopes() {
829 let r = scope.inner_alt_scope_skip(&skip);
830 if r.is_some() {
831 return r;
832 }
833 skip = scope;
834 }
835
836 None
837 }
838 fn inner_alt_scope(&self) -> Option<WidgetFocusInfo> {
839 let inner_alt = self.info.meta().get(*FOCUS_INFO_ID)?.inner_alt.load(Relaxed);
840 if let Some(id) = inner_alt
841 && let Some(wgt) = self.info.tree().get(id)
842 {
843 let wgt = wgt.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
844 if wgt.is_alt_scope() && wgt.info.is_descendant(&self.info) {
845 return Some(wgt);
846 }
847 }
848 None
849 }
850 fn inner_alt_scope_skip(&self, skip: &WidgetFocusInfo) -> Option<WidgetFocusInfo> {
851 if let Some(alt) = self.inner_alt_scope()
852 && !alt.info.is_descendant(&skip.info)
853 && alt.info != skip.info
854 {
855 return Some(alt);
856 }
857 None
858 }
859
860 pub fn in_alt_scope(&self) -> bool {
862 self.is_alt_scope() || self.scopes().any(|s| s.is_alt_scope())
863 }
864
865 pub fn on_focus_scope_move(
879 &self,
880 last_focused: impl FnOnce(WidgetId) -> Option<WidgetId>,
881 is_tab_cycle_reentry: bool,
882 reverse: bool,
883 ) -> Option<WidgetFocusInfo> {
884 match self.focus_info() {
885 FocusInfo::FocusScope { on_focus, .. } => {
886 let candidate = match on_focus {
887 FocusScopeOnFocus::FirstDescendant | FocusScopeOnFocus::FirstDescendantIgnoreBounds => {
888 if reverse {
889 self.last_tab_descendant()
890 } else {
891 self.first_tab_descendant()
892 }
893 }
894 FocusScopeOnFocus::LastFocused | FocusScopeOnFocus::LastFocusedIgnoreBounds => {
895 if is_tab_cycle_reentry { None } else { last_focused(self.info.id()) }
896 .and_then(|id| self.info.tree().get(id))
897 .and_then(|w| w.into_focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets()))
898 .and_then(|f| {
899 if f.info.is_descendant(&self.info) {
900 Some(f) } else {
902 None
903 }
904 })
905 .or_else(|| {
906 if reverse {
907 self.last_tab_descendant()
908 } else {
909 self.first_tab_descendant()
910 }
911 })
912 } FocusScopeOnFocus::Widget => None,
914 };
915
916 if let FocusScopeOnFocus::FirstDescendant | FocusScopeOnFocus::LastFocused = on_focus
918 && let Some(candidate) = &candidate
919 && !self.info.inner_bounds().contains_rect(&candidate.info().inner_bounds())
920 {
921 return None;
923 }
924
925 candidate
926 }
927 FocusInfo::NotFocusable | FocusInfo::Focusable { .. } => None,
928 }
929 }
930
931 pub fn descendants(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
933 super::iter::FocusTreeIter::new(self.info.descendants(), self.mode)
934 }
935
936 pub fn self_and_descendants(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
938 super::iter::FocusTreeIter::new(self.info.self_and_descendants(), self.mode)
939 }
940
941 pub fn has_tab_descendant(&self) -> bool {
943 self.descendants().tree_find(Self::filter_tab_skip).is_some()
944 }
945
946 pub fn first_tab_descendant(&self) -> Option<WidgetFocusInfo> {
948 let mut best = (TabIndex::SKIP, self.clone());
949
950 for d in self.descendants().tree_filter(Self::filter_tab_skip) {
951 let idx = d.focus_info().tab_index();
952
953 if idx < best.0 {
954 best = (idx, d);
955 }
956 }
957
958 if best.0.is_skip() { None } else { Some(best.1) }
959 }
960
961 pub fn last_tab_descendant(&self) -> Option<WidgetFocusInfo> {
963 let mut best = (-1i64, self.clone());
964
965 for d in self.descendants().tree_rev().tree_filter(Self::filter_tab_skip) {
966 let idx = d.focus_info().tab_index().0 as i64;
967
968 if idx > best.0 {
969 best = (idx, d);
970 }
971 }
972
973 if best.0 < 0 { None } else { Some(best.1) }
974 }
975
976 pub fn next_focusables(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
978 if let Some(scope) = self.scope() {
979 super::iter::FocusTreeIter::new(self.info.next_siblings_in(&scope.info), self.mode)
980 } else {
981 super::iter::FocusTreeIter::new(self.info.next_siblings_in(&self.info), self.mode)
983 }
984 }
985
986 pub fn next_focusable(&self) -> Option<WidgetFocusInfo> {
988 self.next_focusables().next()
989 }
990
991 fn filter_tab_skip(w: &WidgetFocusInfo) -> TreeFilter {
992 if w.focus_info().tab_index().is_skip() {
993 TreeFilter::SkipAll
994 } else {
995 TreeFilter::Include
996 }
997 }
998
999 pub fn next_tab_focusable(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1005 self.next_tab_focusable_impl(skip_self, false)
1006 }
1007 fn next_tab_focusable_impl(&self, skip_self: bool, any: bool) -> Option<WidgetFocusInfo> {
1008 let self_index = self.focus_info().tab_index();
1009
1010 if self_index == TabIndex::SKIP {
1011 return self.next_focusables().tree_find(Self::filter_tab_skip);
1013 }
1014
1015 let mut best = (TabIndex::SKIP, self.clone());
1016
1017 if !skip_self {
1018 for d in self.descendants().tree_filter(Self::filter_tab_skip) {
1019 let idx = d.focus_info().tab_index();
1020
1021 if idx == self_index {
1022 return Some(d);
1023 } else if idx < best.0 && idx > self_index {
1024 if any {
1025 return Some(d);
1026 }
1027 best = (idx, d);
1028 }
1029 }
1030 }
1031
1032 for s in self.next_focusables().tree_filter(Self::filter_tab_skip) {
1033 let idx = s.focus_info().tab_index();
1034
1035 if idx == self_index {
1036 return Some(s);
1037 } else if idx < best.0 && idx > self_index {
1038 if any {
1039 return Some(s);
1040 }
1041 best = (idx, s);
1042 }
1043 }
1044
1045 for s in self.prev_focusables().tree_filter(Self::filter_tab_skip) {
1046 let idx = s.focus_info().tab_index();
1047
1048 if idx <= best.0 && idx > self_index {
1049 if any {
1050 return Some(s);
1051 }
1052 best = (idx, s);
1053 }
1054 }
1055
1056 if best.0.is_skip() { None } else { Some(best.1) }
1057 }
1058
1059 pub fn prev_focusables(&self) -> super::iter::FocusTreeIter<w_iter::RevTreeIter> {
1061 if let Some(scope) = self.scope() {
1062 super::iter::FocusTreeIter::new(self.info.prev_siblings_in(&scope.info), self.mode)
1063 } else {
1064 super::iter::FocusTreeIter::new(self.info.prev_siblings_in(&self.info), self.mode)
1066 }
1067 }
1068
1069 pub fn prev_focusable(&self) -> Option<WidgetFocusInfo> {
1071 self.prev_focusables().next()
1072 }
1073
1074 pub fn prev_tab_focusable(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1080 self.prev_tab_focusable_impl(skip_self, false)
1081 }
1082 fn prev_tab_focusable_impl(&self, skip_self: bool, any: bool) -> Option<WidgetFocusInfo> {
1083 let self_index = self.focus_info().tab_index();
1084
1085 if self_index == TabIndex::SKIP {
1086 return self.prev_focusables().tree_find(Self::filter_tab_skip);
1088 }
1089
1090 let self_index = self_index.0 as i64;
1091 let mut best = (-1i64, self.clone());
1092
1093 if !skip_self {
1094 for d in self.descendants().tree_rev().tree_filter(Self::filter_tab_skip) {
1095 let idx = d.focus_info().tab_index().0 as i64;
1096
1097 if idx == self_index {
1098 return Some(d);
1099 } else if idx > best.0 && idx < self_index {
1100 if any {
1101 return Some(d);
1102 }
1103 best = (idx, d);
1104 }
1105 }
1106 }
1107
1108 for s in self.prev_focusables().tree_filter(Self::filter_tab_skip) {
1109 let idx = s.focus_info().tab_index().0 as i64;
1110
1111 if idx == self_index {
1112 return Some(s);
1113 } else if idx > best.0 && idx < self_index {
1114 if any {
1115 return Some(s);
1116 }
1117 best = (idx, s);
1118 }
1119 }
1120
1121 for s in self.next_focusables().tree_filter(Self::filter_tab_skip) {
1122 let idx = s.focus_info().tab_index().0 as i64;
1123
1124 if idx >= best.0 && idx < self_index {
1125 if any {
1126 return Some(s);
1127 }
1128 best = (idx, s);
1129 }
1130 }
1131
1132 if best.0 < 0 { None } else { Some(best.1) }
1133 }
1134
1135 pub fn next_tab(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1141 let _span = tracing::trace_span!("next_tab").entered();
1142
1143 if let Some(scope) = self.scope() {
1144 let scope_info = scope.focus_info();
1145 match scope_info.tab_nav() {
1146 TabNav::None => None,
1147 TabNav::Continue => self.next_tab_focusable(skip_self).or_else(|| scope.next_tab(true)),
1148 TabNav::Contained => self.next_tab_focusable(skip_self),
1149 TabNav::Cycle => self.next_tab_focusable(skip_self).or_else(|| scope.first_tab_descendant()),
1150 TabNav::Once => scope.next_tab(true),
1151 }
1152 } else {
1153 None
1154 }
1155 }
1156
1157 pub fn prev_tab(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1163 let _span = tracing::trace_span!("prev_tab").entered();
1164 if let Some(scope) = self.scope() {
1165 let scope_info = scope.focus_info();
1166 match scope_info.tab_nav() {
1167 TabNav::None => None,
1168 TabNav::Continue => self.prev_tab_focusable(skip_self).or_else(|| scope.prev_tab(true)),
1169 TabNav::Contained => self.prev_tab_focusable(skip_self),
1170 TabNav::Cycle => self.prev_tab_focusable(skip_self).or_else(|| scope.last_tab_descendant()),
1171 TabNav::Once => scope.prev_tab(true),
1172 }
1173 } else {
1174 None
1175 }
1176 }
1177
1178 pub fn nearest(&self, origin: PxPoint, max_radius: Px) -> Option<WidgetFocusInfo> {
1180 let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1181 self.info
1182 .nearest_filtered(origin, max_radius, |w| cast(w.clone()).is_focusable())
1183 .map(cast)
1184 }
1185
1186 pub fn nearest_filtered(
1188 &self,
1189 origin: PxPoint,
1190 max_radius: Px,
1191 mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1192 ) -> Option<WidgetFocusInfo> {
1193 let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1194 self.info
1195 .nearest_filtered(origin, max_radius, |w| {
1196 let w = cast(w.clone());
1197 w.is_focusable() && filter(w)
1198 })
1199 .map(cast)
1200 }
1201
1202 pub fn nearest_bounded_filtered(
1204 &self,
1205 origin: PxPoint,
1206 max_radius: Px,
1207 bounds: PxRect,
1208 mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1209 ) -> Option<WidgetFocusInfo> {
1210 let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1211 self.info
1212 .nearest_bounded_filtered(origin, max_radius, bounds, move |w| {
1213 let w = cast(w.clone());
1214 w.is_focusable() && filter(w)
1215 })
1216 .map(cast)
1217 }
1218
1219 pub fn nearest_oriented(&self, origin: PxPoint, max_distance: Px, orientation: Orientation2D) -> Option<WidgetFocusInfo> {
1221 let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1222 self.info
1223 .nearest_oriented_filtered(origin, max_distance, orientation, |w| cast(w.clone()).is_focusable())
1224 .map(cast)
1225 }
1226
1227 pub fn nearest_oriented_filtered(
1230 &self,
1231 origin: PxPoint,
1232 max_distance: Px,
1233 orientation: Orientation2D,
1234 mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1235 ) -> Option<WidgetFocusInfo> {
1236 let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1237 self.info
1238 .nearest_oriented_filtered(origin, max_distance, orientation, |w| {
1239 let w = cast(w.clone());
1240 w.is_focusable() && filter(w)
1241 })
1242 .map(cast)
1243 }
1244
1245 fn directional_from(
1246 &self,
1247 scope: &WidgetFocusInfo,
1248 origin: PxBox,
1249 orientation: Orientation2D,
1250 skip_self: bool,
1251 any: bool,
1252 ) -> Option<WidgetFocusInfo> {
1253 let self_id = self.info.id();
1254 let scope_id = scope.info.id();
1255
1256 let skip_parent = if self.is_focusable() {
1258 None
1259 } else {
1260 self.ancestors().next().map(|w| w.info.id())
1261 };
1262
1263 let filter = |w: &WidgetFocusInfo| {
1264 let mut up_to_scope = w.self_and_ancestors().take_while(|w| w.info.id() != scope_id);
1265
1266 if skip_self {
1267 up_to_scope.all(|w| w.info.id() != self_id && !w.focus_info().skip_directional())
1268 } else {
1269 up_to_scope.all(|w| !w.focus_info().skip_directional())
1270 }
1271 };
1272
1273 let origin_center = origin.center();
1274
1275 let mut oriented = scope
1276 .info
1277 .oriented(origin_center, Px::MAX, orientation)
1278 .chain(
1279 scope
1281 .info
1282 .oriented_box(origin, origin.width().max(origin.height()) * Px(2), orientation)
1283 .filter(|w| !w.inner_bounds().to_box2d().intersects(&origin)),
1284 )
1285 .focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets())
1286 .filter(|w| w.info.id() != scope_id && Some(w.info.id()) != skip_parent);
1287
1288 if any {
1289 return oriented.find(filter);
1290 }
1291
1292 let parent_range = self.parent().map(|w| w.info.descendants_range()).unwrap_or_default();
1293
1294 let mut ancestor_dist = DistanceKey::NONE_MAX;
1295 let mut ancestor = None;
1296 let mut sibling_dist = DistanceKey::NONE_MAX;
1297 let mut sibling = None;
1298 let mut other_dist = DistanceKey::NONE_MAX;
1299 let mut other = None;
1300
1301 for w in oriented {
1302 if filter(&w) {
1303 let dist = w.info.distance_key(origin_center);
1304
1305 let mut is_ancestor = None;
1306 let mut is_ancestor = || *is_ancestor.get_or_insert_with(|| w.info.is_ancestor(&self.info));
1307
1308 let mut is_sibling = None;
1309 let mut is_sibling = || *is_sibling.get_or_insert_with(|| parent_range.contains(&w.info));
1310
1311 if dist <= ancestor_dist && is_ancestor() {
1312 ancestor_dist = dist;
1313 ancestor = Some(w);
1314 } else if dist <= sibling_dist && is_sibling() {
1315 sibling_dist = dist;
1316 sibling = Some(w);
1317 } else if dist <= other_dist && !is_ancestor() && !is_sibling() {
1318 other_dist = dist;
1319 other = Some(w);
1320 }
1321 }
1322 }
1323
1324 if other_dist <= ancestor_dist && other_dist <= sibling_dist {
1325 other
1326 } else {
1327 sibling.or(ancestor)
1328 }
1329 }
1330
1331 fn directional_next(&self, orientation: Orientation2D) -> Option<WidgetFocusInfo> {
1332 self.directional_next_from(orientation, self.info.inner_bounds().to_box2d())
1333 }
1334
1335 fn directional_next_from(&self, orientation: Orientation2D, from: PxBox) -> Option<WidgetFocusInfo> {
1336 self.scope()
1337 .and_then(|s| self.directional_from(&s, from, orientation, false, false))
1338 }
1339
1340 pub fn focusable_up(&self) -> Option<WidgetFocusInfo> {
1342 self.directional_next(Orientation2D::Above)
1343 }
1344
1345 pub fn focusable_down(&self) -> Option<WidgetFocusInfo> {
1347 self.directional_next(Orientation2D::Below)
1348 }
1349
1350 pub fn focusable_left(&self) -> Option<WidgetFocusInfo> {
1352 self.directional_next(Orientation2D::Left)
1353 }
1354
1355 pub fn focusable_right(&self) -> Option<WidgetFocusInfo> {
1357 self.directional_next(Orientation2D::Right)
1358 }
1359
1360 pub fn next_up(&self) -> Option<WidgetFocusInfo> {
1362 let _span = tracing::trace_span!("next_up").entered();
1363 self.next_up_from(self.info.inner_bounds().to_box2d())
1364 }
1365 fn next_up_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1366 if let Some(scope) = self.scope() {
1367 let scope_info = scope.focus_info();
1368 match scope_info.directional_nav() {
1369 DirectionalNav::None => None,
1370 DirectionalNav::Continue => self.directional_next_from(Orientation2D::Above, origin).or_else(|| {
1371 let mut from = scope.info.inner_bounds();
1372 from.origin.y -= Px(1);
1373 from.size.height = Px(1);
1374 scope.next_up_from(from.to_box2d())
1375 }),
1376 DirectionalNav::Contained => self.directional_next_from(Orientation2D::Above, origin),
1377 DirectionalNav::Cycle => {
1378 self.directional_next_from(Orientation2D::Above, origin).or_else(|| {
1379 let mut from_pt = origin.center();
1381 from_pt.y = scope.info.spatial_bounds().max.y;
1382 self.directional_from(
1383 &scope,
1384 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1385 Orientation2D::Above,
1386 false,
1387 false,
1388 )
1389 })
1390 }
1391 }
1392 } else {
1393 None
1394 }
1395 }
1396
1397 pub fn next_right(&self) -> Option<WidgetFocusInfo> {
1399 let _span = tracing::trace_span!("next_right").entered();
1400 self.next_right_from(self.info.inner_bounds().to_box2d())
1401 }
1402 fn next_right_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1403 if let Some(scope) = self.scope() {
1404 let scope_info = scope.focus_info();
1405 match scope_info.directional_nav() {
1406 DirectionalNav::None => None,
1407 DirectionalNav::Continue => self.directional_next_from(Orientation2D::Right, origin).or_else(|| {
1408 let mut from = scope.info.inner_bounds();
1409 from.origin.x += from.size.width + Px(1);
1410 from.size.width = Px(1);
1411 scope.next_right_from(from.to_box2d())
1412 }),
1413 DirectionalNav::Contained => self.directional_next_from(Orientation2D::Right, origin),
1414 DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Right, origin).or_else(|| {
1415 let mut from_pt = origin.center();
1417 from_pt.x = scope.info.spatial_bounds().min.x;
1418 self.directional_from(
1419 &scope,
1420 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1421 Orientation2D::Right,
1422 false,
1423 false,
1424 )
1425 }),
1426 }
1427 } else {
1428 None
1429 }
1430 }
1431
1432 pub fn next_down(&self) -> Option<WidgetFocusInfo> {
1434 let _span = tracing::trace_span!("next_down").entered();
1435 self.next_down_from(self.info.inner_bounds().to_box2d())
1436 }
1437 fn next_down_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1438 if let Some(scope) = self.scope() {
1439 let scope_info = scope.focus_info();
1440 match scope_info.directional_nav() {
1441 DirectionalNav::None => None,
1442 DirectionalNav::Continue => self.directional_next_from(Orientation2D::Below, origin).or_else(|| {
1443 let mut from = scope.info.inner_bounds();
1444 from.origin.y += from.size.height + Px(1);
1445 from.size.height = Px(1);
1446 scope.next_down_from(from.to_box2d())
1447 }),
1448 DirectionalNav::Contained => self.directional_next_from(Orientation2D::Below, origin),
1449 DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Below, origin).or_else(|| {
1450 let mut from_pt = origin.center();
1452 from_pt.y = scope.info.spatial_bounds().min.y;
1453 self.directional_from(
1454 &scope,
1455 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1456 Orientation2D::Below,
1457 false,
1458 false,
1459 )
1460 }),
1461 }
1462 } else {
1463 None
1464 }
1465 }
1466
1467 pub fn next_left(&self) -> Option<WidgetFocusInfo> {
1469 let _span = tracing::trace_span!("next_left").entered();
1470 self.next_left_from(self.info.inner_bounds().to_box2d())
1471 }
1472 fn next_left_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1473 if let Some(scope) = self.scope() {
1474 let scope_info = scope.focus_info();
1475 match scope_info.directional_nav() {
1476 DirectionalNav::None => None,
1477 DirectionalNav::Continue => self.directional_next_from(Orientation2D::Left, origin).or_else(|| {
1478 let mut from = scope.info.inner_bounds();
1479 from.origin.x -= Px(1);
1480 from.size.width = Px(1);
1481 scope.next_left_from(from.to_box2d())
1482 }),
1483 DirectionalNav::Contained => self.directional_next_from(Orientation2D::Left, origin),
1484 DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Left, origin).or_else(|| {
1485 let mut from_pt = origin.center();
1487 from_pt.x = scope.info.spatial_bounds().max.x;
1488 self.directional_from(
1489 &scope,
1490 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1491 Orientation2D::Left,
1492 false,
1493 false,
1494 )
1495 }),
1496 }
1497 } else {
1498 None
1499 }
1500 }
1501
1502 fn enabled_tab_nav(
1503 &self,
1504 scope: &WidgetFocusInfo,
1505 scope_info: FocusInfo,
1506 skip_self: bool,
1507 already_found: FocusNavAction,
1508 ) -> FocusNavAction {
1509 match scope_info.tab_nav() {
1510 TabNav::None => FocusNavAction::empty(),
1511 tab_nav @ (TabNav::Continue | TabNav::Contained) => {
1512 let mut nav = already_found;
1513
1514 if !nav.contains(FocusNavAction::PREV) && self.prev_tab_focusable_impl(skip_self, true).is_some() {
1515 nav |= FocusNavAction::PREV;
1516 }
1517 if !nav.contains(FocusNavAction::NEXT) && self.next_tab_focusable_impl(skip_self, true).is_some() {
1518 nav |= FocusNavAction::NEXT;
1519 }
1520
1521 if !nav.contains(FocusNavAction::PREV | FocusNavAction::NEXT)
1522 && tab_nav == TabNav::Continue
1523 && let Some(p_scope) = scope.scope()
1524 {
1525 nav |= scope.enabled_tab_nav(&p_scope, p_scope.focus_info(), true, nav)
1526 }
1527 nav
1528 }
1529 TabNav::Cycle => {
1530 if scope.descendants().tree_filter(Self::filter_tab_skip).any(|w| &w != self) {
1531 FocusNavAction::PREV | FocusNavAction::NEXT
1532 } else {
1533 FocusNavAction::empty()
1534 }
1535 }
1536 TabNav::Once => {
1537 if let Some(p_scope) = scope.scope() {
1538 scope.enabled_tab_nav(&p_scope, p_scope.focus_info(), true, already_found)
1539 } else {
1540 FocusNavAction::empty()
1541 }
1542 }
1543 }
1544 }
1545
1546 fn enabled_directional_nav(
1547 &self,
1548 scope: &WidgetFocusInfo,
1549 scope_info: FocusInfo,
1550 skip_self: bool,
1551 already_found: FocusNavAction,
1552 ) -> FocusNavAction {
1553 let directional_nav = scope_info.directional_nav();
1554
1555 if directional_nav == DirectionalNav::None {
1556 return FocusNavAction::empty();
1557 }
1558
1559 let mut nav = already_found;
1560 let from_pt = self.info.inner_bounds().to_box2d();
1561
1562 if !nav.contains(FocusNavAction::UP)
1563 && self
1564 .directional_from(scope, from_pt, Orientation2D::Above, skip_self, true)
1565 .is_some()
1566 {
1567 nav |= FocusNavAction::UP;
1568 }
1569 if !nav.contains(FocusNavAction::RIGHT)
1570 && self
1571 .directional_from(scope, from_pt, Orientation2D::Right, skip_self, true)
1572 .is_some()
1573 {
1574 nav |= FocusNavAction::RIGHT;
1575 }
1576 if !nav.contains(FocusNavAction::DOWN)
1577 && self
1578 .directional_from(scope, from_pt, Orientation2D::Below, skip_self, true)
1579 .is_some()
1580 {
1581 nav |= FocusNavAction::DOWN;
1582 }
1583 if !nav.contains(FocusNavAction::LEFT)
1584 && self
1585 .directional_from(scope, from_pt, Orientation2D::Left, skip_self, true)
1586 .is_some()
1587 {
1588 nav |= FocusNavAction::LEFT;
1589 }
1590
1591 if !nav.contains(FocusNavAction::DIRECTIONAL) {
1592 match directional_nav {
1593 DirectionalNav::Continue => {
1594 if let Some(p_scope) = scope.scope() {
1595 nav |= scope.enabled_directional_nav(&p_scope, p_scope.focus_info(), true, nav);
1596 }
1597 }
1598 DirectionalNav::Cycle => {
1599 let scope_bounds = scope.info.inner_bounds();
1600 if !nav.contains(FocusNavAction::UP) {
1601 let mut from_pt = from_pt.center();
1602 from_pt.y = scope_bounds.max().y;
1603 if self
1604 .directional_from(
1605 scope,
1606 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1607 Orientation2D::Above,
1608 true,
1609 true,
1610 )
1611 .is_some()
1612 {
1613 nav |= FocusNavAction::UP;
1614 }
1615 }
1616 if !nav.contains(FocusNavAction::RIGHT) {
1617 let mut from_pt = from_pt.center();
1618 from_pt.x = scope_bounds.min().x;
1619 if self
1620 .directional_from(
1621 scope,
1622 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1623 Orientation2D::Right,
1624 true,
1625 true,
1626 )
1627 .is_some()
1628 {
1629 nav |= FocusNavAction::RIGHT;
1630 }
1631 }
1632 if !nav.contains(FocusNavAction::DOWN) {
1633 let mut from_pt = from_pt.center();
1634 from_pt.y = scope_bounds.min().y;
1635 if self
1636 .directional_from(
1637 scope,
1638 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1639 Orientation2D::Below,
1640 true,
1641 true,
1642 )
1643 .is_some()
1644 {
1645 nav |= FocusNavAction::DOWN;
1646 }
1647 }
1648 if !nav.contains(FocusNavAction::LEFT) {
1649 let mut from_pt = from_pt.center();
1650 from_pt.x = scope_bounds.max().x;
1651 if self
1652 .directional_from(
1653 scope,
1654 PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1655 Orientation2D::Left,
1656 true,
1657 true,
1658 )
1659 .is_some()
1660 {
1661 nav |= FocusNavAction::LEFT;
1662 }
1663 }
1664
1665 if !nav.contains(FocusNavAction::DIRECTIONAL) {
1666 let info = self.focus_info();
1667
1668 if info.is_scope() && matches!(info.directional_nav(), DirectionalNav::Continue) {
1669 if nav.contains(FocusNavAction::UP) || nav.contains(FocusNavAction::DOWN) {
1671 nav |= FocusNavAction::UP | FocusNavAction::DOWN;
1672 }
1673 if nav.contains(FocusNavAction::LEFT) || nav.contains(FocusNavAction::RIGHT) {
1674 nav |= FocusNavAction::LEFT | FocusNavAction::RIGHT;
1675 }
1676 }
1677 }
1678 }
1679 _ => {}
1680 }
1681 }
1682
1683 nav
1684 }
1685
1686 pub fn enabled_nav(&self) -> FocusNavAction {
1688 let _span = tracing::trace_span!("enabled_nav").entered();
1689
1690 let mut nav = FocusNavAction::empty();
1691
1692 if let Some(scope) = self.scope() {
1693 nav |= FocusNavAction::EXIT;
1694 nav.set(FocusNavAction::ENTER, self.descendants().next().is_some());
1695
1696 let scope_info = scope.focus_info();
1697
1698 nav |= self.enabled_tab_nav(&scope, scope_info, false, FocusNavAction::empty());
1699 nav |= self.enabled_directional_nav(&scope, scope_info, false, FocusNavAction::empty());
1700 }
1701
1702 nav.set(FocusNavAction::ALT, self.in_alt_scope() || self.alt_scope().is_some());
1703
1704 nav
1705 }
1706}
1707impl_from_and_into_var! {
1708 fn from(focus_info: WidgetFocusInfo) -> WidgetInfo {
1709 focus_info.info
1710 }
1711}
1712
1713#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
1715pub enum FocusInfo {
1716 NotFocusable,
1718 Focusable {
1720 tab_index: TabIndex,
1722 skip_directional: bool,
1724 },
1725 FocusScope {
1727 tab_index: TabIndex,
1729 skip_directional: bool,
1731 tab_nav: TabNav,
1733 directional_nav: DirectionalNav,
1735 on_focus: FocusScopeOnFocus,
1737 alt: bool,
1739 },
1740}
1741
1742#[derive(Clone, Copy, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
1744pub enum FocusScopeOnFocus {
1745 Widget,
1747 FirstDescendant,
1757 LastFocused,
1769
1770 FirstDescendantIgnoreBounds,
1778
1779 LastFocusedIgnoreBounds,
1787}
1788impl fmt::Debug for FocusScopeOnFocus {
1789 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1790 if f.alternate() {
1791 write!(f, "FocusScopeOnFocus::")?;
1792 }
1793 match self {
1794 FocusScopeOnFocus::Widget => write!(f, "Widget"),
1795 FocusScopeOnFocus::FirstDescendant => write!(f, "FirstDescendant"),
1796 FocusScopeOnFocus::LastFocused => write!(f, "LastFocused"),
1797 FocusScopeOnFocus::FirstDescendantIgnoreBounds => write!(f, "FirstDescendantIgnoreBounds"),
1798 FocusScopeOnFocus::LastFocusedIgnoreBounds => write!(f, "LastFocusedIgnoreBounds"),
1799 }
1800 }
1801}
1802impl Default for FocusScopeOnFocus {
1803 fn default() -> Self {
1805 FocusScopeOnFocus::FirstDescendant
1806 }
1807}
1808
1809impl FocusInfo {
1810 pub fn is_focusable(self) -> bool {
1812 !matches!(self, FocusInfo::NotFocusable)
1813 }
1814
1815 pub fn is_scope(self) -> bool {
1817 matches!(self, FocusInfo::FocusScope { .. })
1818 }
1819
1820 pub fn is_alt_scope(self) -> bool {
1822 match self {
1823 FocusInfo::FocusScope { alt, .. } => alt,
1824 _ => false,
1825 }
1826 }
1827
1828 pub fn tab_nav(self) -> TabNav {
1836 match self {
1837 FocusInfo::FocusScope { tab_nav, .. } => tab_nav,
1838 FocusInfo::Focusable { .. } => TabNav::Continue,
1839 FocusInfo::NotFocusable => TabNav::None,
1840 }
1841 }
1842
1843 pub fn directional_nav(self) -> DirectionalNav {
1851 match self {
1852 FocusInfo::FocusScope { directional_nav, .. } => directional_nav,
1853 FocusInfo::Focusable { .. } => DirectionalNav::Continue,
1854 FocusInfo::NotFocusable => DirectionalNav::None,
1855 }
1856 }
1857
1858 pub fn tab_index(self) -> TabIndex {
1865 match self {
1866 FocusInfo::Focusable { tab_index, .. } => tab_index,
1867 FocusInfo::FocusScope { tab_index, .. } => tab_index,
1868 FocusInfo::NotFocusable => TabIndex::SKIP,
1869 }
1870 }
1871
1872 pub fn skip_directional(self) -> bool {
1879 match self {
1880 FocusInfo::Focusable { skip_directional, .. } => skip_directional,
1881 FocusInfo::FocusScope { skip_directional, .. } => skip_directional,
1882 FocusInfo::NotFocusable => true,
1883 }
1884 }
1885
1886 pub fn scope_on_focus(self) -> FocusScopeOnFocus {
1893 match self {
1894 FocusInfo::FocusScope { on_focus, .. } => on_focus,
1895 _ => FocusScopeOnFocus::Widget,
1896 }
1897 }
1898}
1899
1900static_id! {
1901 static ref FOCUS_INFO_ID: StateId<FocusInfoData>;
1902 static ref FOCUS_TREE_ID: StateId<FocusTreeData>;
1903}
1904
1905#[derive(Default)]
1906pub(super) struct FocusTreeData {
1907 alt_scopes: Mutex<IdSet<WidgetId>>,
1908}
1909impl FocusTreeData {
1910 pub(super) fn consolidate_alt_scopes(prev_tree: &WeakWidgetInfoTree, new_tree: &WidgetInfoTree) {
1911 let prev = prev_tree
1914 .upgrade()
1915 .and_then(|t| t.build_meta().get(*FOCUS_TREE_ID).map(|d| d.alt_scopes.lock().clone()))
1916 .unwrap_or_default();
1917
1918 let mut alt_scopes = prev;
1919 if let Some(data) = new_tree.build_meta().get(*FOCUS_TREE_ID) {
1920 alt_scopes.extend(data.alt_scopes.lock().iter());
1921 }
1922
1923 alt_scopes.retain(|id| {
1924 if let Some(wgt) = new_tree.get(*id)
1925 && let Some(info) = wgt.meta().get(*FOCUS_INFO_ID)
1926 && info.build().is_alt_scope()
1927 {
1928 for parent in wgt.ancestors() {
1929 if let Some(info) = parent.meta().get(*FOCUS_INFO_ID)
1930 && info.build().is_scope()
1931 {
1932 info.inner_alt.store(Some(*id), Relaxed);
1933 break;
1934 }
1935 }
1936
1937 return true;
1938 }
1939 false
1940 });
1941
1942 if let Some(data) = new_tree.build_meta().get(*FOCUS_TREE_ID) {
1943 *data.alt_scopes.lock() = alt_scopes;
1944 }
1945 }
1946}
1947
1948#[derive(Default, Debug)]
1949struct FocusInfoData {
1950 focusable: Option<bool>,
1951 scope: Option<bool>,
1952 alt_scope: bool,
1953 on_focus: FocusScopeOnFocus,
1954 tab_index: Option<TabIndex>,
1955 tab_nav: Option<TabNav>,
1956 directional_nav: Option<DirectionalNav>,
1957 skip_directional: Option<bool>,
1958
1959 inner_alt: Atomic<Option<WidgetId>>,
1960
1961 access_handler_registered: bool,
1962}
1963impl FocusInfoData {
1964 pub fn build(&self) -> FocusInfo {
1968 match (self.focusable, self.scope, self.tab_index, self.tab_nav, self.directional_nav) {
1969 (Some(false), _, _, _, _) => FocusInfo::NotFocusable,
1971
1972 (_, Some(true), idx, tab, dir) | (_, None, idx, tab @ Some(_), dir) | (_, None, idx, tab, dir @ Some(_)) => {
1976 FocusInfo::FocusScope {
1977 tab_index: idx.unwrap_or(TabIndex::AUTO),
1978 skip_directional: self.skip_directional.unwrap_or_default(),
1979 tab_nav: tab.unwrap_or(TabNav::Continue),
1980 directional_nav: dir.unwrap_or(DirectionalNav::Continue),
1981 alt: self.alt_scope,
1982 on_focus: self.on_focus,
1983 }
1984 }
1985
1986 (Some(true), _, idx, _, _) | (_, _, idx @ Some(_), _, _) => FocusInfo::Focusable {
1989 tab_index: idx.unwrap_or(TabIndex::AUTO),
1990 skip_directional: self.skip_directional.unwrap_or_default(),
1991 },
1992
1993 _ => FocusInfo::NotFocusable,
1994 }
1995 }
1996}
1997
1998pub struct FocusInfoBuilder<'a>(&'a mut WidgetInfoBuilder);
2043impl<'a> FocusInfoBuilder<'a> {
2044 pub fn new(builder: &'a mut WidgetInfoBuilder) -> Self {
2046 let mut r = Self(builder);
2047 r.with_tree_data(|_| {}); r
2049 }
2050
2051 fn with_data<R>(&mut self, visitor: impl FnOnce(&mut FocusInfoData) -> R) -> R {
2052 let mut access = self.0.access().is_some();
2053
2054 let r = self.0.with_meta(|m| {
2055 let data = m.into_entry(*FOCUS_INFO_ID).or_default();
2056
2057 if access {
2058 access = !std::mem::replace(&mut data.access_handler_registered, true);
2059 }
2060
2061 visitor(data)
2062 });
2063
2064 if access {
2065 self.0.access().unwrap().on_access_build(|args| {
2067 if args.widget.info().clone().into_focusable(true, false).is_some() {
2068 args.node.commands.push(zng_view_api::access::AccessCmdName::Focus);
2069 }
2070 });
2071 }
2072
2073 r
2074 }
2075
2076 fn with_tree_data<R>(&mut self, visitor: impl FnOnce(&mut FocusTreeData) -> R) -> R {
2077 self.0.with_build_meta(|m| visitor(m.into_entry(*FOCUS_TREE_ID).or_default()))
2078 }
2079
2080 pub fn focusable(&mut self, is_focusable: bool) -> &mut Self {
2082 self.with_data(|data| {
2083 data.focusable = Some(is_focusable);
2084 });
2085 self
2086 }
2087
2088 pub fn focusable_passive(&mut self, is_focusable: bool) -> &mut Self {
2092 self.with_data(|data| {
2093 if data.focusable.is_none() {
2094 data.focusable = Some(is_focusable);
2095 }
2096 });
2097 self
2098 }
2099
2100 pub fn scope(&mut self, is_focus_scope: bool) -> &mut Self {
2102 self.with_data(|data| {
2103 data.scope = Some(is_focus_scope);
2104 });
2105 self
2106 }
2107
2108 pub fn alt_scope(&mut self, is_alt_focus_scope: bool) -> &mut Self {
2112 self.with_data(|data| {
2113 data.alt_scope = is_alt_focus_scope;
2114 if is_alt_focus_scope {
2115 data.scope = Some(true);
2116
2117 if data.tab_index.is_none() {
2118 data.tab_index = Some(TabIndex::SKIP);
2119 }
2120 if data.tab_nav.is_none() {
2121 data.tab_nav = Some(TabNav::Cycle);
2122 }
2123 if data.directional_nav.is_none() {
2124 data.directional_nav = Some(DirectionalNav::Cycle);
2125 }
2126 if data.skip_directional.is_none() {
2127 data.skip_directional = Some(true);
2128 }
2129 }
2130 });
2131 if is_alt_focus_scope {
2132 let wgt_id = self.0.widget_id();
2133 self.with_tree_data(|d| d.alt_scopes.lock().insert(wgt_id));
2134 }
2135 self
2136 }
2137
2138 pub fn on_focus(&mut self, as_focus_scope_on_focus: FocusScopeOnFocus) -> &mut Self {
2140 self.with_data(|data| {
2141 data.on_focus = as_focus_scope_on_focus;
2142 });
2143 self
2144 }
2145
2146 pub fn tab_index(&mut self, tab_index: TabIndex) -> &mut Self {
2148 self.with_data(|data| {
2149 data.tab_index = Some(tab_index);
2150 });
2151 self
2152 }
2153
2154 pub fn tab_nav(&mut self, scope_tab_nav: TabNav) -> &mut Self {
2156 self.with_data(|data| {
2157 data.tab_nav = Some(scope_tab_nav);
2158 });
2159 self
2160 }
2161
2162 pub fn directional_nav(&mut self, scope_directional_nav: DirectionalNav) -> &mut Self {
2164 self.with_data(|data| {
2165 data.directional_nav = Some(scope_directional_nav);
2166 });
2167 self
2168 }
2169 pub fn skip_directional(&mut self, skip: bool) -> &mut Self {
2171 self.with_data(|data| {
2172 data.skip_directional = Some(skip);
2173 });
2174 self
2175 }
2176}