zng_ext_input/focus/
focus_info.rs

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, 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/// Widget tab navigation position within a focus scope.
25///
26/// The index is zero based, zero first.
27#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
28pub struct TabIndex(pub u32);
29impl TabIndex {
30    /// Widget is skipped during tab navigation.
31    ///
32    /// The integer value is `u32::MAX`.
33    pub const SKIP: TabIndex = TabIndex(u32::MAX);
34
35    /// Default focusable widget index.
36    ///
37    /// Tab navigation uses the widget position in the widget tree when multiple widgets have the same index
38    /// so if no widget index is explicitly set they get auto-sorted by their position.
39    ///
40    /// The integer value is `u32::MAX / 2`.
41    pub const AUTO: TabIndex = TabIndex(u32::MAX / 2);
42
43    /// Last possible widget index.
44    pub const LAST: TabIndex = TabIndex(u32::MAX - 1);
45
46    /// If is [`SKIP`](TabIndex::SKIP).
47    pub fn is_skip(self) -> bool {
48        self == Self::SKIP
49    }
50
51    /// If is [`AUTO`](TabIndex::AUTO).
52    pub fn is_auto(self) -> bool {
53        self == Self::AUTO
54    }
55
56    /// If is a custom index placed [before auto](Self::before_auto).
57    pub fn is_before_auto(self) -> bool {
58        self.0 < Self::AUTO.0
59    }
60
61    /// If is a custom index placed [after auto](Self::after_auto).
62    pub fn is_after_auto(self) -> bool {
63        self.0 > Self::AUTO.0
64    }
65
66    /// Create a new tab index that is guaranteed to not be [`SKIP`](Self::SKIP).
67    ///
68    /// Returns `SKIP - 1` if `index` is `SKIP`.
69    pub fn not_skip(index: u32) -> Self {
70        TabIndex(if index == Self::SKIP.0 { Self::SKIP.0 - 1 } else { index })
71    }
72
73    /// Create a new tab index that is guaranteed to be before [`AUTO`](Self::AUTO).
74    ///
75    /// Returns `AUTO - 1` if `index` is equal to or greater then `AUTO`.
76    pub fn before_auto(index: u32) -> Self {
77        TabIndex(if index >= Self::AUTO.0 { Self::AUTO.0 - 1 } else { index })
78    }
79
80    /// Create a new tab index that is guaranteed to be after [`AUTO`](Self::AUTO) and not [`SKIP`](Self::SKIP).
81    ///
82    /// The `index` argument is zero based here.
83    ///
84    /// Returns `not_skip(AUTO + 1 + index)`.
85    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            //
103            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    /// `AUTO`
117    fn default() -> Self {
118        TabIndex::AUTO
119    }
120}
121impl_from_and_into_var! {
122    /// Calls [`TabIndex::not_skip`].
123    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/// Tab navigation configuration of a focus scope.
172///
173/// See the [module level](../#tab-navigation) for an overview of tab navigation.
174#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
175pub enum TabNav {
176    /// Tab can move into the scope, but does not move the focus inside the scope.
177    None,
178    /// Tab moves the focus through the scope continuing out after the last item.
179    Continue,
180    /// Tab is contained in the scope, does not move after the last item.
181    Contained,
182    /// Tab is contained in the scope, after the last item moves to the first item in the scope.
183    Cycle,
184    /// Tab moves into the scope once but then moves out of the scope.
185    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/// Directional navigation configuration of a focus scope.
203///
204/// See the [module level](../#directional-navigation) for an overview of directional navigation.
205#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
206pub enum DirectionalNav {
207    /// Arrows can move into the scope, but does not move the focus inside the scope.
208    None,
209    /// Arrows move the focus through the scope continuing out of the edges.
210    Continue,
211    /// Arrows move the focus inside the scope only, stops at the edges.
212    Contained,
213    /// Arrows move the focus inside the scope only, cycles back to opposite edges.
214    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/// Focus change request.
231///
232/// See [`FOCUS`] for details.
233///
234/// [`FOCUS`]: crate::focus::FOCUS::focus
235#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
236pub struct FocusRequest {
237    /// Where to move the focus.
238    pub target: FocusTarget,
239    /// If the widget should visually indicate that it has keyboard focus.
240    pub highlight: bool,
241
242    /// If the window should be focused even if another app has focus. By default the window
243    /// is only focused if the app has keyboard focus in any of the open windows, if this is enabled
244    /// a [`WINDOWS.focus`] request is always made, potentially stealing keyboard focus from another app
245    /// and disrupting the user.
246    ///
247    /// [`WINDOWS.focus`]: zng_ext_window::WINDOWS::focus
248    pub force_window_focus: bool,
249
250    /// Focus indicator to set on the target window if the app does not have keyboard focus and
251    /// `force_window_focus` is disabled.
252    ///
253    /// The [`focus_indicator`] of the window is set and the request is processed after the window receives focus,
254    /// or it is canceled if another focus request is made.
255    ///
256    /// [`focus_indicator`]: zng_ext_window::WindowVars::focus_indicator
257    pub window_indicator: Option<FocusIndicator>,
258}
259
260impl FocusRequest {
261    /// New request from target and highlight.
262    pub fn new(target: FocusTarget, highlight: bool) -> Self {
263        Self {
264            target,
265            highlight,
266            force_window_focus: false,
267            window_indicator: None,
268        }
269    }
270
271    /// New [`FocusTarget::Direct`] request.
272    pub fn direct(widget_id: WidgetId, highlight: bool) -> Self {
273        Self::new(FocusTarget::Direct { target: widget_id }, highlight)
274    }
275    /// New [`FocusTarget::DirectOrExit`] request.
276    pub fn direct_or_exit(widget_id: WidgetId, navigation_origin: bool, highlight: bool) -> Self {
277        Self::new(
278            FocusTarget::DirectOrExit {
279                target: widget_id,
280                navigation_origin,
281            },
282            highlight,
283        )
284    }
285    /// New [`FocusTarget::DirectOrEnter`] request.
286    pub fn direct_or_enter(widget_id: WidgetId, navigation_origin: bool, highlight: bool) -> Self {
287        Self::new(
288            FocusTarget::DirectOrEnter {
289                target: widget_id,
290                navigation_origin,
291            },
292            highlight,
293        )
294    }
295    /// New [`FocusTarget::DirectOrRelated`] request.
296    pub fn direct_or_related(widget_id: WidgetId, navigation_origin: bool, highlight: bool) -> Self {
297        Self::new(
298            FocusTarget::DirectOrRelated {
299                target: widget_id,
300                navigation_origin,
301            },
302            highlight,
303        )
304    }
305    /// New [`FocusTarget::Enter`] request.
306    pub fn enter(highlight: bool) -> Self {
307        Self::new(FocusTarget::Enter, highlight)
308    }
309    /// New [`FocusTarget::Exit`] request.
310    pub fn exit(highlight: bool) -> Self {
311        Self::new(FocusTarget::Exit, highlight)
312    }
313    /// New [`FocusTarget::Next`] request.
314    pub fn next(highlight: bool) -> Self {
315        Self::new(FocusTarget::Next, highlight)
316    }
317    /// New [`FocusTarget::Prev`] request.
318    pub fn prev(highlight: bool) -> Self {
319        Self::new(FocusTarget::Prev, highlight)
320    }
321    /// New [`FocusTarget::Up`] request.
322    pub fn up(highlight: bool) -> Self {
323        Self::new(FocusTarget::Up, highlight)
324    }
325    /// New [`FocusTarget::Right`] request.
326    pub fn right(highlight: bool) -> Self {
327        Self::new(FocusTarget::Right, highlight)
328    }
329    /// New [`FocusTarget::Down`] request.
330    pub fn down(highlight: bool) -> Self {
331        Self::new(FocusTarget::Down, highlight)
332    }
333    /// New [`FocusTarget::Left`] request.
334    pub fn left(highlight: bool) -> Self {
335        Self::new(FocusTarget::Left, highlight)
336    }
337    /// New [`FocusTarget::Alt`] request.
338    pub fn alt(highlight: bool) -> Self {
339        Self::new(FocusTarget::Alt, highlight)
340    }
341
342    /// Sets [`FocusRequest::force_window_focus`] to `true`.
343    pub fn with_force_window_focus(mut self) -> Self {
344        self.force_window_focus = true;
345        self
346    }
347
348    /// Sets the [`FocusRequest::window_indicator`].
349    pub fn with_indicator(mut self, indicator: FocusIndicator) -> Self {
350        self.window_indicator = Some(indicator);
351        self
352    }
353}
354
355/// Focus request target.
356#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
357pub enum FocusTarget {
358    /// Move focus to widget.
359    Direct {
360        /// Focusable widget.
361        target: WidgetId,
362    },
363    /// Move focus to the widget if it is focusable or to the first focusable ancestor.
364    DirectOrExit {
365        /// Maybe focusable widget.
366        target: WidgetId,
367        /// If `true` the `target` becomes the [`navigation_origin`] when the first focusable ancestor
368        /// is focused because the `target` is not focusable.
369        ///
370        /// [`navigation_origin`]: crate::focus::FOCUS::navigation_origin
371        navigation_origin: bool,
372    },
373    /// Move focus to the widget if it is focusable or to first focusable descendant.
374    DirectOrEnter {
375        /// Maybe focusable widget.
376        target: WidgetId,
377        /// If `true` the `target` becomes the [`navigation_origin`] when the first focusable descendant
378        /// is focused because the `target` is not focusable.
379        ///
380        /// [`navigation_origin`]: crate::focus::FOCUS::navigation_origin
381        navigation_origin: bool,
382    },
383    /// Move focus to the widget if it is focusable, or to the first focusable descendant or
384    /// to the first focusable ancestor.
385    DirectOrRelated {
386        /// Maybe focusable widget.
387        target: WidgetId,
388        /// If `true` the `target` becomes the [`navigation_origin`] when the first focusable relative
389        /// is focused because the `target` is not focusable.
390        ///
391        /// [`navigation_origin`]: crate::focus::FOCUS::navigation_origin
392        navigation_origin: bool,
393    },
394
395    /// Move focus to the first focusable descendant of the current focus, or to first in screen.
396    Enter,
397    /// Move focus to the first focusable ancestor of the current focus, or to first in screen, or the return focus from ALT scopes.
398    Exit,
399
400    /// Move focus to next from current in screen, or to first in screen.
401    Next,
402    /// Move focus to previous from current in screen, or to last in screen.
403    Prev,
404
405    /// Move focus above current.
406    Up,
407    /// Move focus to the right of current.
408    Right,
409    /// Move focus bellow current.
410    Down,
411    /// Move focus to the left of current.
412    Left,
413
414    /// Move focus to the current widget ALT scope or out of it.
415    Alt,
416}
417
418bitflags! {
419    /// Represents the [`FocusTarget`] actions that move focus from the current focused widget.
420    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
421    pub struct FocusNavAction: u16 {
422        /// [`FocusTarget::Enter`]
423        const ENTER = 0b0000_0000_0001;
424        /// [`FocusTarget::Exit`]
425        const EXIT = 0b0000_0000_0010;
426
427        /// [`FocusTarget::Next`]
428        const NEXT = 0b0000_0000_0100;
429        /// [`FocusTarget::Prev`]
430        const PREV = 0b0000_0000_1000;
431
432        /// [`FocusTarget::Up`]
433        const UP = 0b0000_0001_0000;
434        /// [`FocusTarget::Right`]
435        const RIGHT = 0b0000_0010_0000;
436        /// [`FocusTarget::Down`]
437        const DOWN = 0b0000_0100_0000;
438        /// [`FocusTarget::Left`]
439        const LEFT = 0b0000_1000_0000;
440
441        /// [`FocusTarget::Alt`]
442        const ALT = 0b0001_0000_0000;
443
444        /// Up, right, down, left.
445        const DIRECTIONAL =
446            FocusNavAction::UP.bits() | FocusNavAction::RIGHT.bits() | FocusNavAction::DOWN.bits() | FocusNavAction::LEFT.bits();
447    }
448}
449
450bitflags! {
451    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
452    pub(super) struct FocusMode: u8 {
453        /// Allow focus in disabled widgets.
454        const DISABLED = 1;
455        /// Allow focus in hidden widgets.
456        const HIDDEN = 2;
457    }
458}
459impl FocusMode {
460    pub fn new(focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Self {
461        let mut mode = FocusMode::empty();
462        mode.set(FocusMode::DISABLED, focus_disabled_widgets);
463        mode.set(FocusMode::HIDDEN, focus_hidden_widgets);
464        mode
465    }
466}
467
468/// A [`WidgetInfoTree`] wrapper for querying focus info out of the widget tree.
469///
470/// [`WidgetInfoTree`]: zng_app::widget::info::WidgetInfoTree
471#[derive(Clone, Debug)]
472pub struct FocusInfoTree {
473    tree: WidgetInfoTree,
474    mode: FocusMode,
475}
476impl FocusInfoTree {
477    /// Wrap a `widget_info` reference to enable focus info querying.
478    ///
479    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
480    ///
481    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
482    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
483    pub fn new(tree: WidgetInfoTree, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Self {
484        FocusInfoTree {
485            tree,
486            mode: FocusMode::new(focus_disabled_widgets, focus_hidden_widgets),
487        }
488    }
489
490    /// Full widget info.
491    pub fn tree(&self) -> &WidgetInfoTree {
492        &self.tree
493    }
494
495    /// If [`DISABLED`] widgets are focusable in this tree.
496    ///
497    /// See the [`FOCUS.focus_disabled_widgets`] config for more details.
498    ///
499    /// [`DISABLED`]: zng_app::widget::info::Interactivity::DISABLED
500    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
501    pub fn focus_disabled_widgets(&self) -> bool {
502        self.mode.contains(FocusMode::DISABLED)
503    }
504
505    /// If [`Hidden`] widgets are focusable in this tree.
506    ///
507    /// See the [`FOCUS.focus_hidden_widgets`] config for more details.
508    ///
509    /// [`Hidden`]: Visibility::Hidden
510    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
511    pub fn focus_hidden_widgets(&self) -> bool {
512        self.mode.contains(FocusMode::HIDDEN)
513    }
514
515    /// Reference to the root widget in the tree.
516    ///
517    /// The root is usually a focusable focus scope but it may not be. This
518    /// is the only method that returns a [`WidgetFocusInfo`] that may not be focusable.
519    pub fn root(&self) -> WidgetFocusInfo {
520        WidgetFocusInfo {
521            info: self.tree.root(),
522            mode: self.mode,
523        }
524    }
525
526    /// Reference the focusable widget closest to the window root.
527    ///
528    /// When the window root is not focusable, but a descendant widget is, this method returns
529    /// the focusable closest to the root counting previous siblings then parents.
530    pub fn focusable_root(&self) -> Option<WidgetFocusInfo> {
531        let root = self.root();
532        if root.is_focusable() {
533            return Some(root);
534        }
535
536        let mut candidate = None;
537        let mut candidate_weight = usize::MAX;
538
539        for w in root.descendants().tree_filter(|_| TreeFilter::SkipDescendants) {
540            let weight = w.info.prev_siblings().count() + w.info.ancestors().count();
541            if weight < candidate_weight {
542                candidate = Some(w);
543                candidate_weight = weight;
544            }
545        }
546
547        candidate
548    }
549
550    /// Reference to the widget in the tree, if it is present and is focusable.
551    pub fn get(&self, widget_id: impl Into<WidgetId>) -> Option<WidgetFocusInfo> {
552        self.tree
553            .get(widget_id)
554            .and_then(|i| i.into_focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets()))
555    }
556
557    /// Reference to the first focusable widget or parent in the tree.
558    pub fn get_or_parent(&self, path: &WidgetPath) -> Option<WidgetFocusInfo> {
559        self.get(path.widget_id())
560            .or_else(|| path.ancestors().iter().rev().find_map(|&id| self.get(id)))
561    }
562
563    /// If the tree info contains the widget and it is focusable.
564    pub fn contains(&self, widget_id: impl Into<WidgetId>) -> bool {
565        self.get(widget_id).is_some()
566    }
567}
568
569/// [`WidgetInfo`] extensions that build a [`WidgetFocusInfo`].
570///
571/// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
572pub trait WidgetInfoFocusExt {
573    /// Wraps the [`WidgetInfo`] in a [`WidgetFocusInfo`] even if it is not focusable.
574    ///
575    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
576    ///
577    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
578    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
579    /// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
580    fn into_focus_info(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> WidgetFocusInfo;
581    /// Returns a wrapped [`WidgetFocusInfo`] if the [`WidgetInfo`] is focusable.
582    ///
583    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
584    ///
585    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
586    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
587    /// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
588    fn into_focusable(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Option<WidgetFocusInfo>;
589}
590impl WidgetInfoFocusExt for WidgetInfo {
591    fn into_focus_info(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> WidgetFocusInfo {
592        WidgetFocusInfo::new(self, focus_disabled_widgets, focus_hidden_widgets)
593    }
594    fn into_focusable(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Option<WidgetFocusInfo> {
595        let r = self.into_focus_info(focus_disabled_widgets, focus_hidden_widgets);
596        if r.is_focusable() { Some(r) } else { None }
597    }
598}
599
600/// [`WidgetInfo`] wrapper that adds focus information for each widget.
601///
602/// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
603#[derive(Clone, Eq, PartialEq, Hash, Debug)]
604pub struct WidgetFocusInfo {
605    info: WidgetInfo,
606    mode: FocusMode,
607}
608impl WidgetFocusInfo {
609    /// Wrap a `widget_info` reference to enable focus info querying.
610    ///
611    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
612    ///
613    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
614    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
615    pub fn new(widget_info: WidgetInfo, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> Self {
616        WidgetFocusInfo {
617            info: widget_info,
618            mode: FocusMode::new(focus_disabled_widgets, focus_hidden_widgets),
619        }
620    }
621
622    /// Full widget info.
623    pub fn info(&self) -> &WidgetInfo {
624        &self.info
625    }
626
627    /// If [`DISABLED`] widgets are focusable in this tree.
628    ///
629    /// See the [`FOCUS.focus_disabled_widgets`] config for more details.
630    ///
631    /// [`DISABLED`]: zng_app::widget::info::Interactivity::DISABLED
632    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
633    pub fn focus_disabled_widgets(&self) -> bool {
634        self.mode.contains(FocusMode::DISABLED)
635    }
636
637    /// If [`Hidden`] widgets are focusable in this tree.
638    ///
639    /// See the [`FOCUS.focus_hidden_widgets`] config for more details.
640    ///
641    /// [`Hidden`]: Visibility::Hidden
642    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
643    pub fn focus_hidden_widgets(&self) -> bool {
644        self.mode.contains(FocusMode::HIDDEN)
645    }
646
647    /// Root focusable.
648    pub fn root(&self) -> Self {
649        self.ancestors().last().unwrap_or_else(|| self.clone())
650    }
651
652    /// Clone a reference to the [`FocusInfoTree`] that owns this widget.
653    pub fn focus_tree(&self) -> FocusInfoTree {
654        FocusInfoTree {
655            tree: self.info.tree().clone(),
656            mode: self.mode,
657        }
658    }
659
660    /// If the widget is focusable.
661    ///
662    /// ## Note
663    ///
664    /// This is probably `true`, the only way to get a [`WidgetFocusInfo`] for a non-focusable widget is by
665    /// calling [`into_focus_info`](WidgetInfoFocusExt::into_focus_info) or explicitly constructing one.
666    ///
667    /// Focus scopes are also focusable.
668    pub fn is_focusable(&self) -> bool {
669        self.focus_info().is_focusable()
670    }
671
672    /// Is focus scope.
673    pub fn is_scope(&self) -> bool {
674        self.focus_info().is_scope()
675    }
676
677    /// Is ALT focus scope.
678    pub fn is_alt_scope(&self) -> bool {
679        self.focus_info().is_alt_scope()
680    }
681
682    /// Gets the nested window ID, if this widget hosts a nested window.
683    ///
684    /// Nested window hosts always focus the nested window on focus.
685    pub fn nested_window(&self) -> Option<WindowId> {
686        self.info.nested_window()
687    }
688
689    /// Gets the nested window focus tree, if this widget hosts a nested window.
690    pub fn nested_window_tree(&self) -> Option<FocusInfoTree> {
691        self.info
692            .nested_window_tree()
693            .map(|t| FocusInfoTree::new(t, self.focus_disabled_widgets(), self.focus_hidden_widgets()))
694    }
695
696    fn mode_allows_focus(&self) -> bool {
697        let int = self.info.interactivity();
698        if self.mode.contains(FocusMode::DISABLED) {
699            if int.is_blocked() {
700                return false;
701            }
702        } else if !int.is_enabled() {
703            return false;
704        }
705
706        let vis = self.info.visibility();
707        if self.mode.contains(FocusMode::HIDDEN) {
708            if vis == Visibility::Collapsed {
709                return false;
710            }
711        } else if vis != Visibility::Visible {
712            return false;
713        }
714
715        true
716    }
717
718    fn mode_allows_focus_ignore_blocked(&self) -> bool {
719        let int = self.info.interactivity();
720        if !self.mode.contains(FocusMode::DISABLED) && int.is_vis_disabled() {
721            return false;
722        }
723
724        let vis = self.info.visibility();
725        if self.mode.contains(FocusMode::HIDDEN) {
726            if vis == Visibility::Collapsed {
727                return false;
728            }
729        } else if vis != Visibility::Visible {
730            return false;
731        }
732
733        true
734    }
735
736    /// Widget focus metadata.
737    pub fn focus_info(&self) -> FocusInfo {
738        if self.mode_allows_focus() {
739            if let Some(builder) = self.info.meta().get(*FOCUS_INFO_ID) {
740                return builder.build();
741            } else if self.info.nested_window().is_some() {
742                // service will actually focus nested window
743                return FocusInfo::FocusScope {
744                    tab_index: TabIndex::AUTO,
745                    skip_directional: false,
746                    tab_nav: TabNav::Contained,
747                    directional_nav: DirectionalNav::Contained,
748                    on_focus: FocusScopeOnFocus::FirstDescendant,
749                    alt: false,
750                };
751            }
752        }
753        FocusInfo::NotFocusable
754    }
755
756    /// Widget focus metadata, all things equal except the widget interactivity is blocked.
757    pub fn focus_info_ignore_blocked(&self) -> FocusInfo {
758        if self.mode_allows_focus_ignore_blocked()
759            && let Some(builder) = self.info.meta().get(*FOCUS_INFO_ID)
760        {
761            return builder.build();
762        }
763        FocusInfo::NotFocusable
764    }
765
766    /// Iterator over focusable parent -> grandparent -> .. -> root.
767    pub fn ancestors(&self) -> impl Iterator<Item = WidgetFocusInfo> {
768        let focus_disabled_widgets = self.focus_disabled_widgets();
769        let focus_hidden_widgets = self.focus_hidden_widgets();
770        self.info.ancestors().focusable(focus_disabled_widgets, focus_hidden_widgets)
771    }
772
773    /// Iterator over self -> focusable parent -> grandparent -> .. -> root.
774    pub fn self_and_ancestors(&self) -> impl Iterator<Item = WidgetFocusInfo> {
775        [self.clone()].into_iter().chain(self.ancestors())
776    }
777
778    /// Iterator over focus scopes parent -> grandparent -> .. -> root.
779    pub fn scopes(&self) -> impl Iterator<Item = WidgetFocusInfo> {
780        let focus_disabled_widgets = self.focus_disabled_widgets();
781        let focus_hidden_widgets = self.focus_hidden_widgets();
782        self.info.ancestors().filter_map(move |i| {
783            let i = i.into_focus_info(focus_disabled_widgets, focus_hidden_widgets);
784            if i.is_scope() { Some(i) } else { None }
785        })
786    }
787
788    /// Reference to the focusable parent that contains this widget.
789    pub fn parent(&self) -> Option<WidgetFocusInfo> {
790        self.ancestors().next()
791    }
792
793    /// Reference the focus scope parent that contains the widget.
794    pub fn scope(&self) -> Option<WidgetFocusInfo> {
795        self.scopes().next()
796    }
797
798    /// Reference the ALT focus scope *closest* with the current widget.
799    ///
800    /// # Closest Alt Scope
801    ///
802    /// - If `self` is already an ALT scope or is in one, moves to a sibling ALT scope, nested ALT scopes are ignored.
803    /// - If `self` is a normal scope, moves to the first descendant ALT scope, otherwise..
804    /// - Recursively searches for an ALT scope sibling up the scope tree.
805    pub fn alt_scope(&self) -> Option<WidgetFocusInfo> {
806        if self.in_alt_scope() {
807            // We do not allow nested alt scopes, search for sibling focus scope.
808            let mut alt_scope = self.clone();
809            for scope in self.scopes() {
810                if scope.is_alt_scope() {
811                    alt_scope = scope;
812                } else {
813                    return scope.inner_alt_scope_skip(&alt_scope);
814                }
815            }
816            return None;
817        }
818
819        if self.is_scope() {
820            // if we are a normal scope, try for an inner ALT scope descendant first.
821            let r = self.inner_alt_scope();
822            if r.is_some() {
823                return r;
824            }
825        }
826
827        // try each parent scope up the tree
828        let mut skip = self.clone();
829        for scope in self.scopes() {
830            let r = scope.inner_alt_scope_skip(&skip);
831            if r.is_some() {
832                return r;
833            }
834            skip = scope;
835        }
836
837        None
838    }
839    fn inner_alt_scope(&self) -> Option<WidgetFocusInfo> {
840        let inner_alt = self.info.meta().get(*FOCUS_INFO_ID)?.inner_alt.load(Relaxed);
841        if let Some(id) = inner_alt
842            && let Some(wgt) = self.info.tree().get(id)
843        {
844            let wgt = wgt.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
845            if wgt.is_alt_scope() && wgt.info.is_descendant(&self.info) {
846                return Some(wgt);
847            }
848        }
849        None
850    }
851    fn inner_alt_scope_skip(&self, skip: &WidgetFocusInfo) -> Option<WidgetFocusInfo> {
852        if let Some(alt) = self.inner_alt_scope()
853            && !alt.info.is_descendant(&skip.info)
854            && alt.info != skip.info
855        {
856            return Some(alt);
857        }
858        None
859    }
860
861    /// Widget is in a ALT scope or is an ALT scope.
862    pub fn in_alt_scope(&self) -> bool {
863        self.is_alt_scope() || self.scopes().any(|s| s.is_alt_scope())
864    }
865
866    /// Widget the focus needs to move to when `self` gets focused.
867    ///
868    /// # Input
869    ///
870    /// * `last_focused`: A function that returns the last focused widget within a focus scope identified by `WidgetId`.
871    /// * `is_tab_cycle_reentry`: If the focus returned to `self` immediately after leaving because the parent scope is `TabNav::Cycle`.
872    /// * `reverse`: If the focus *reversed* into `self`.
873    ///
874    /// # Returns
875    ///
876    /// Returns the different widget the focus must move to after focusing in `self` that is a focus scope.
877    ///
878    /// If `self` is not a [`FocusScope`](FocusInfo::FocusScope) always returns `None`.
879    pub fn on_focus_scope_move<'f>(
880        &self,
881        last_focused: impl FnOnce(WidgetId) -> Option<&'f WidgetPath>,
882        is_tab_cycle_reentry: bool,
883        reverse: bool,
884    ) -> Option<WidgetFocusInfo> {
885        match self.focus_info() {
886            FocusInfo::FocusScope { on_focus, .. } => {
887                let candidate = match on_focus {
888                    FocusScopeOnFocus::FirstDescendant | FocusScopeOnFocus::FirstDescendantIgnoreBounds => {
889                        if reverse {
890                            self.last_tab_descendant()
891                        } else {
892                            self.first_tab_descendant()
893                        }
894                    }
895                    FocusScopeOnFocus::LastFocused | FocusScopeOnFocus::LastFocusedIgnoreBounds => {
896                        if is_tab_cycle_reentry { None } else { last_focused(self.info.id()) }
897                            .and_then(|path| self.info.tree().get(path.widget_id()))
898                            .and_then(|w| w.into_focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets()))
899                            .and_then(|f| {
900                                if f.info.is_descendant(&self.info) {
901                                    Some(f) // valid last focused
902                                } else {
903                                    None
904                                }
905                            })
906                            .or_else(|| {
907                                if reverse {
908                                    self.last_tab_descendant()
909                                } else {
910                                    self.first_tab_descendant()
911                                }
912                            })
913                    } // fallback
914                    FocusScopeOnFocus::Widget => None,
915                };
916
917                // if not IgnoreBounds and some candidate
918                if let FocusScopeOnFocus::FirstDescendant | FocusScopeOnFocus::LastFocused = on_focus
919                    && let Some(candidate) = &candidate
920                    && !self.info.inner_bounds().contains_rect(&candidate.info().inner_bounds())
921                {
922                    // not fully in bounds.
923                    return None;
924                }
925
926                candidate
927            }
928            FocusInfo::NotFocusable | FocusInfo::Focusable { .. } => None,
929        }
930    }
931
932    /// Iterator over the focusable widgets contained by this widget.
933    pub fn descendants(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
934        super::iter::FocusTreeIter::new(self.info.descendants(), self.mode)
935    }
936
937    /// Iterator over self and the focusable widgets contained by it.
938    pub fn self_and_descendants(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
939        super::iter::FocusTreeIter::new(self.info.self_and_descendants(), self.mode)
940    }
941
942    /// If the focusable has any focusable descendant that is not [`TabIndex::SKIP`]
943    pub fn has_tab_descendant(&self) -> bool {
944        self.descendants().tree_find(Self::filter_tab_skip).is_some()
945    }
946
947    /// First descendant considering TAB index.
948    pub fn first_tab_descendant(&self) -> Option<WidgetFocusInfo> {
949        let mut best = (TabIndex::SKIP, self.clone());
950
951        for d in self.descendants().tree_filter(Self::filter_tab_skip) {
952            let idx = d.focus_info().tab_index();
953
954            if idx < best.0 {
955                best = (idx, d);
956            }
957        }
958
959        if best.0.is_skip() { None } else { Some(best.1) }
960    }
961
962    /// Last descendant considering TAB index.
963    pub fn last_tab_descendant(&self) -> Option<WidgetFocusInfo> {
964        let mut best = (-1i64, self.clone());
965
966        for d in self.descendants().tree_rev().tree_filter(Self::filter_tab_skip) {
967            let idx = d.focus_info().tab_index().0 as i64;
968
969            if idx > best.0 {
970                best = (idx, d);
971            }
972        }
973
974        if best.0 < 0 { None } else { Some(best.1) }
975    }
976
977    /// Iterator over all focusable widgets in the same scope after this widget.
978    pub fn next_focusables(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
979        if let Some(scope) = self.scope() {
980            super::iter::FocusTreeIter::new(self.info.next_siblings_in(&scope.info), self.mode)
981        } else {
982            // empty
983            super::iter::FocusTreeIter::new(self.info.next_siblings_in(&self.info), self.mode)
984        }
985    }
986
987    /// Next focusable in the same scope after this widget.
988    pub fn next_focusable(&self) -> Option<WidgetFocusInfo> {
989        self.next_focusables().next()
990    }
991
992    fn filter_tab_skip(w: &WidgetFocusInfo) -> TreeFilter {
993        if w.focus_info().tab_index().is_skip() {
994            TreeFilter::SkipAll
995        } else {
996            TreeFilter::Include
997        }
998    }
999
1000    /// Next focusable in the same scope after this widget respecting the TAB index.
1001    ///
1002    /// If `self` is set to [`TabIndex::SKIP`] returns the next non-skip focusable in the same scope after this widget.
1003    ///
1004    /// If `skip_self` is `true`, does not include widgets inside `self`.
1005    pub fn next_tab_focusable(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1006        self.next_tab_focusable_impl(skip_self, false)
1007    }
1008    fn next_tab_focusable_impl(&self, skip_self: bool, any: bool) -> Option<WidgetFocusInfo> {
1009        let self_index = self.focus_info().tab_index();
1010
1011        if self_index == TabIndex::SKIP {
1012            // TAB from skip, goes to next in widget tree.
1013            return self.next_focusables().tree_find(Self::filter_tab_skip);
1014        }
1015
1016        let mut best = (TabIndex::SKIP, self.clone());
1017
1018        if !skip_self {
1019            for d in self.descendants().tree_filter(Self::filter_tab_skip) {
1020                let idx = d.focus_info().tab_index();
1021
1022                if idx == self_index {
1023                    return Some(d);
1024                } else if idx < best.0 && idx > self_index {
1025                    if any {
1026                        return Some(d);
1027                    }
1028                    best = (idx, d);
1029                }
1030            }
1031        }
1032
1033        for s in self.next_focusables().tree_filter(Self::filter_tab_skip) {
1034            let idx = s.focus_info().tab_index();
1035
1036            if idx == self_index {
1037                return Some(s);
1038            } else if idx < best.0 && idx > self_index {
1039                if any {
1040                    return Some(s);
1041                }
1042                best = (idx, s);
1043            }
1044        }
1045
1046        for s in self.prev_focusables().tree_filter(Self::filter_tab_skip) {
1047            let idx = s.focus_info().tab_index();
1048
1049            if idx <= best.0 && idx > self_index {
1050                if any {
1051                    return Some(s);
1052                }
1053                best = (idx, s);
1054            }
1055        }
1056
1057        if best.0.is_skip() { None } else { Some(best.1) }
1058    }
1059
1060    /// Iterator over all focusable widgets in the same scope before this widget in reverse.
1061    pub fn prev_focusables(&self) -> super::iter::FocusTreeIter<w_iter::RevTreeIter> {
1062        if let Some(scope) = self.scope() {
1063            super::iter::FocusTreeIter::new(self.info.prev_siblings_in(&scope.info), self.mode)
1064        } else {
1065            // empty
1066            super::iter::FocusTreeIter::new(self.info.prev_siblings_in(&self.info), self.mode)
1067        }
1068    }
1069
1070    /// Previous focusable in the same scope before this widget.
1071    pub fn prev_focusable(&self) -> Option<WidgetFocusInfo> {
1072        self.prev_focusables().next()
1073    }
1074
1075    /// Previous focusable in the same scope after this widget respecting the TAB index.
1076    ///
1077    /// If `self` is set to [`TabIndex::SKIP`] returns the previous non-skip focusable in the same scope before this widget.
1078    ///
1079    /// If `skip_self` is `true`, does not include widgets inside `self`.
1080    pub fn prev_tab_focusable(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1081        self.prev_tab_focusable_impl(skip_self, false)
1082    }
1083    fn prev_tab_focusable_impl(&self, skip_self: bool, any: bool) -> Option<WidgetFocusInfo> {
1084        let self_index = self.focus_info().tab_index();
1085
1086        if self_index == TabIndex::SKIP {
1087            // TAB from skip, goes to prev in widget tree.
1088            return self.prev_focusables().tree_find(Self::filter_tab_skip);
1089        }
1090
1091        let self_index = self_index.0 as i64;
1092        let mut best = (-1i64, self.clone());
1093
1094        if !skip_self {
1095            for d in self.descendants().tree_rev().tree_filter(Self::filter_tab_skip) {
1096                let idx = d.focus_info().tab_index().0 as i64;
1097
1098                if idx == self_index {
1099                    return Some(d);
1100                } else if idx > best.0 && idx < self_index {
1101                    if any {
1102                        return Some(d);
1103                    }
1104                    best = (idx, d);
1105                }
1106            }
1107        }
1108
1109        for s in self.prev_focusables().tree_filter(Self::filter_tab_skip) {
1110            let idx = s.focus_info().tab_index().0 as i64;
1111
1112            if idx == self_index {
1113                return Some(s);
1114            } else if idx > best.0 && idx < self_index {
1115                if any {
1116                    return Some(s);
1117                }
1118                best = (idx, s);
1119            }
1120        }
1121
1122        for s in self.next_focusables().tree_filter(Self::filter_tab_skip) {
1123            let idx = s.focus_info().tab_index().0 as i64;
1124
1125            if idx >= best.0 && idx < self_index {
1126                if any {
1127                    return Some(s);
1128                }
1129                best = (idx, s);
1130            }
1131        }
1132
1133        if best.0 < 0 { None } else { Some(best.1) }
1134    }
1135
1136    /// Widget to focus when pressing TAB from this widget.
1137    ///
1138    /// Set `skip_self` to not enter `self`, that is, the focus goes to the next sibling or next sibling descendant.
1139    ///
1140    /// Returns `None` if the focus does not move to another widget.
1141    pub fn next_tab(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1142        let _span = tracing::trace_span!("next_tab").entered();
1143
1144        if let Some(scope) = self.scope() {
1145            let scope_info = scope.focus_info();
1146            match scope_info.tab_nav() {
1147                TabNav::None => None,
1148                TabNav::Continue => self.next_tab_focusable(skip_self).or_else(|| scope.next_tab(true)),
1149                TabNav::Contained => self.next_tab_focusable(skip_self),
1150                TabNav::Cycle => self.next_tab_focusable(skip_self).or_else(|| scope.first_tab_descendant()),
1151                TabNav::Once => scope.next_tab(true),
1152            }
1153        } else {
1154            None
1155        }
1156    }
1157
1158    /// Widget to focus when pressing SHIFT+TAB from this widget.
1159    ///
1160    /// Set `skip_self` to not enter `self`, that is, the focus goes to the previous sibling or previous sibling descendant.
1161    ///
1162    /// Returns `None` if the focus does not move to another widget.
1163    pub fn prev_tab(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1164        let _span = tracing::trace_span!("prev_tab").entered();
1165        if let Some(scope) = self.scope() {
1166            let scope_info = scope.focus_info();
1167            match scope_info.tab_nav() {
1168                TabNav::None => None,
1169                TabNav::Continue => self.prev_tab_focusable(skip_self).or_else(|| scope.prev_tab(true)),
1170                TabNav::Contained => self.prev_tab_focusable(skip_self),
1171                TabNav::Cycle => self.prev_tab_focusable(skip_self).or_else(|| scope.last_tab_descendant()),
1172                TabNav::Once => scope.prev_tab(true),
1173            }
1174        } else {
1175            None
1176        }
1177    }
1178
1179    /// Find the focusable descendant with center point nearest of `origin` within the `max_radius`.
1180    pub fn nearest(&self, origin: PxPoint, max_radius: Px) -> Option<WidgetFocusInfo> {
1181        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1182        self.info
1183            .nearest_filtered(origin, max_radius, |w| cast(w.clone()).is_focusable())
1184            .map(cast)
1185    }
1186
1187    /// Find the descendant with center point nearest of `origin` within the `max_radius` and approved by the `filter` closure.
1188    pub fn nearest_filtered(
1189        &self,
1190        origin: PxPoint,
1191        max_radius: Px,
1192        mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1193    ) -> Option<WidgetFocusInfo> {
1194        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1195        self.info
1196            .nearest_filtered(origin, max_radius, |w| {
1197                let w = cast(w.clone());
1198                w.is_focusable() && filter(w)
1199            })
1200            .map(cast)
1201    }
1202
1203    /// Find the descendant with center point nearest of `origin` within the `max_radius` and inside `bounds`; and approved by the `filter` closure.
1204    pub fn nearest_bounded_filtered(
1205        &self,
1206        origin: PxPoint,
1207        max_radius: Px,
1208        bounds: PxRect,
1209        mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1210    ) -> Option<WidgetFocusInfo> {
1211        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1212        self.info
1213            .nearest_bounded_filtered(origin, max_radius, bounds, move |w| {
1214                let w = cast(w.clone());
1215                w.is_focusable() && filter(w)
1216            })
1217            .map(cast)
1218    }
1219
1220    /// Find the focusable descendant with center point nearest of `origin` within the `max_distance` and with `orientation` to origin.
1221    pub fn nearest_oriented(&self, origin: PxPoint, max_distance: Px, orientation: Orientation2D) -> Option<WidgetFocusInfo> {
1222        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1223        self.info
1224            .nearest_oriented_filtered(origin, max_distance, orientation, |w| cast(w.clone()).is_focusable())
1225            .map(cast)
1226    }
1227
1228    /// Find the focusable descendant with center point nearest of `origin` within the `max_distance` and with `orientation`
1229    /// to origin that passes the `filter`.
1230    pub fn nearest_oriented_filtered(
1231        &self,
1232        origin: PxPoint,
1233        max_distance: Px,
1234        orientation: Orientation2D,
1235        mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1236    ) -> Option<WidgetFocusInfo> {
1237        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1238        self.info
1239            .nearest_oriented_filtered(origin, max_distance, orientation, |w| {
1240                let w = cast(w.clone());
1241                w.is_focusable() && filter(w)
1242            })
1243            .map(cast)
1244    }
1245
1246    fn directional_from(
1247        &self,
1248        scope: &WidgetFocusInfo,
1249        origin: PxBox,
1250        orientation: Orientation2D,
1251        skip_self: bool,
1252        any: bool,
1253    ) -> Option<WidgetFocusInfo> {
1254        let self_id = self.info.id();
1255        let scope_id = scope.info.id();
1256
1257        // don't return focus to parent from non-focusable child.
1258        let skip_parent = if self.is_focusable() {
1259            None
1260        } else {
1261            self.ancestors().next().map(|w| w.info.id())
1262        };
1263
1264        let filter = |w: &WidgetFocusInfo| {
1265            let mut up_to_scope = w.self_and_ancestors().take_while(|w| w.info.id() != scope_id);
1266
1267            if skip_self {
1268                up_to_scope.all(|w| w.info.id() != self_id && !w.focus_info().skip_directional())
1269            } else {
1270                up_to_scope.all(|w| !w.focus_info().skip_directional())
1271            }
1272        };
1273
1274        let origin_center = origin.center();
1275
1276        let mut oriented = scope
1277            .info
1278            .oriented(origin_center, Px::MAX, orientation)
1279            .chain(
1280                // nearby boxes (not overlapped)
1281                scope
1282                    .info
1283                    .oriented_box(origin, origin.width().max(origin.height()) * Px(2), orientation)
1284                    .filter(|w| !w.inner_bounds().to_box2d().intersects(&origin)),
1285            )
1286            .focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets())
1287            .filter(|w| w.info.id() != scope_id && Some(w.info.id()) != skip_parent);
1288
1289        if any {
1290            return oriented.find(filter);
1291        }
1292
1293        let parent_range = self.parent().map(|w| w.info.descendants_range()).unwrap_or_default();
1294
1295        let mut ancestor_dist = DistanceKey::NONE_MAX;
1296        let mut ancestor = None;
1297        let mut sibling_dist = DistanceKey::NONE_MAX;
1298        let mut sibling = None;
1299        let mut other_dist = DistanceKey::NONE_MAX;
1300        let mut other = None;
1301
1302        for w in oriented {
1303            if filter(&w) {
1304                let dist = w.info.distance_key(origin_center);
1305
1306                let mut is_ancestor = None;
1307                let mut is_ancestor = || *is_ancestor.get_or_insert_with(|| w.info.is_ancestor(&self.info));
1308
1309                let mut is_sibling = None;
1310                let mut is_sibling = || *is_sibling.get_or_insert_with(|| parent_range.contains(&w.info));
1311
1312                if dist <= ancestor_dist && is_ancestor() {
1313                    ancestor_dist = dist;
1314                    ancestor = Some(w);
1315                } else if dist <= sibling_dist && is_sibling() {
1316                    sibling_dist = dist;
1317                    sibling = Some(w);
1318                } else if dist <= other_dist && !is_ancestor() && !is_sibling() {
1319                    other_dist = dist;
1320                    other = Some(w);
1321                }
1322            }
1323        }
1324
1325        if other_dist <= ancestor_dist && other_dist <= sibling_dist {
1326            other
1327        } else {
1328            sibling.or(ancestor)
1329        }
1330    }
1331
1332    fn directional_next(&self, orientation: Orientation2D) -> Option<WidgetFocusInfo> {
1333        self.directional_next_from(orientation, self.info.inner_bounds().to_box2d())
1334    }
1335
1336    fn directional_next_from(&self, orientation: Orientation2D, from: PxBox) -> Option<WidgetFocusInfo> {
1337        self.scope()
1338            .and_then(|s| self.directional_from(&s, from, orientation, false, false))
1339    }
1340
1341    /// Closest focusable in the same scope above this widget.
1342    pub fn focusable_up(&self) -> Option<WidgetFocusInfo> {
1343        self.directional_next(Orientation2D::Above)
1344    }
1345
1346    /// Closest focusable in the same scope below this widget.
1347    pub fn focusable_down(&self) -> Option<WidgetFocusInfo> {
1348        self.directional_next(Orientation2D::Below)
1349    }
1350
1351    /// Closest focusable in the same scope to the left of this widget.
1352    pub fn focusable_left(&self) -> Option<WidgetFocusInfo> {
1353        self.directional_next(Orientation2D::Left)
1354    }
1355
1356    /// Closest focusable in the same scope to the right of this widget.
1357    pub fn focusable_right(&self) -> Option<WidgetFocusInfo> {
1358        self.directional_next(Orientation2D::Right)
1359    }
1360
1361    /// Widget to focus when pressing the arrow up key from this widget.
1362    pub fn next_up(&self) -> Option<WidgetFocusInfo> {
1363        let _span = tracing::trace_span!("next_up").entered();
1364        self.next_up_from(self.info.inner_bounds().to_box2d())
1365    }
1366    fn next_up_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1367        if let Some(scope) = self.scope() {
1368            let scope_info = scope.focus_info();
1369            match scope_info.directional_nav() {
1370                DirectionalNav::None => None,
1371                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Above, origin).or_else(|| {
1372                    let mut from = scope.info.inner_bounds();
1373                    from.origin.y -= Px(1);
1374                    from.size.height = Px(1);
1375                    scope.next_up_from(from.to_box2d())
1376                }),
1377                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Above, origin),
1378                DirectionalNav::Cycle => {
1379                    self.directional_next_from(Orientation2D::Above, origin).or_else(|| {
1380                        // next up from the same X but from the bottom segment of scope spatial bounds.
1381                        let mut from_pt = origin.center();
1382                        from_pt.y = scope.info.spatial_bounds().max.y;
1383                        self.directional_from(
1384                            &scope,
1385                            PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1386                            Orientation2D::Above,
1387                            false,
1388                            false,
1389                        )
1390                    })
1391                }
1392            }
1393        } else {
1394            None
1395        }
1396    }
1397
1398    /// Widget to focus when pressing the arrow right key from this widget.
1399    pub fn next_right(&self) -> Option<WidgetFocusInfo> {
1400        let _span = tracing::trace_span!("next_right").entered();
1401        self.next_right_from(self.info.inner_bounds().to_box2d())
1402    }
1403    fn next_right_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1404        if let Some(scope) = self.scope() {
1405            let scope_info = scope.focus_info();
1406            match scope_info.directional_nav() {
1407                DirectionalNav::None => None,
1408                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Right, origin).or_else(|| {
1409                    let mut from = scope.info.inner_bounds();
1410                    from.origin.x += from.size.width + Px(1);
1411                    from.size.width = Px(1);
1412                    scope.next_right_from(from.to_box2d())
1413                }),
1414                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Right, origin),
1415                DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Right, origin).or_else(|| {
1416                    // next right from the same Y but from the left segment of scope spatial bounds.
1417                    let mut from_pt = origin.center();
1418                    from_pt.x = scope.info.spatial_bounds().min.x;
1419                    self.directional_from(
1420                        &scope,
1421                        PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1422                        Orientation2D::Right,
1423                        false,
1424                        false,
1425                    )
1426                }),
1427            }
1428        } else {
1429            None
1430        }
1431    }
1432
1433    /// Widget to focus when pressing the arrow down key from this widget.
1434    pub fn next_down(&self) -> Option<WidgetFocusInfo> {
1435        let _span = tracing::trace_span!("next_down").entered();
1436        self.next_down_from(self.info.inner_bounds().to_box2d())
1437    }
1438    fn next_down_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1439        if let Some(scope) = self.scope() {
1440            let scope_info = scope.focus_info();
1441            match scope_info.directional_nav() {
1442                DirectionalNav::None => None,
1443                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Below, origin).or_else(|| {
1444                    let mut from = scope.info.inner_bounds();
1445                    from.origin.y += from.size.height + Px(1);
1446                    from.size.height = Px(1);
1447                    scope.next_down_from(from.to_box2d())
1448                }),
1449                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Below, origin),
1450                DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Below, origin).or_else(|| {
1451                    // next down from the same X but from the top segment of scope spatial bounds.
1452                    let mut from_pt = origin.center();
1453                    from_pt.y = scope.info.spatial_bounds().min.y;
1454                    self.directional_from(
1455                        &scope,
1456                        PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1457                        Orientation2D::Below,
1458                        false,
1459                        false,
1460                    )
1461                }),
1462            }
1463        } else {
1464            None
1465        }
1466    }
1467
1468    /// Widget to focus when pressing the arrow left key from this widget.
1469    pub fn next_left(&self) -> Option<WidgetFocusInfo> {
1470        let _span = tracing::trace_span!("next_left").entered();
1471        self.next_left_from(self.info.inner_bounds().to_box2d())
1472    }
1473    fn next_left_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1474        if let Some(scope) = self.scope() {
1475            let scope_info = scope.focus_info();
1476            match scope_info.directional_nav() {
1477                DirectionalNav::None => None,
1478                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Left, origin).or_else(|| {
1479                    let mut from = scope.info.inner_bounds();
1480                    from.origin.x -= Px(1);
1481                    from.size.width = Px(1);
1482                    scope.next_left_from(from.to_box2d())
1483                }),
1484                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Left, origin),
1485                DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Left, origin).or_else(|| {
1486                    // next left from the same Y but from the right segment of scope spatial bounds.
1487                    let mut from_pt = origin.center();
1488                    from_pt.x = scope.info.spatial_bounds().max.x;
1489                    self.directional_from(
1490                        &scope,
1491                        PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1492                        Orientation2D::Left,
1493                        false,
1494                        false,
1495                    )
1496                }),
1497            }
1498        } else {
1499            None
1500        }
1501    }
1502
1503    fn enabled_tab_nav(
1504        &self,
1505        scope: &WidgetFocusInfo,
1506        scope_info: FocusInfo,
1507        skip_self: bool,
1508        already_found: FocusNavAction,
1509    ) -> FocusNavAction {
1510        match scope_info.tab_nav() {
1511            TabNav::None => FocusNavAction::empty(),
1512            tab_nav @ (TabNav::Continue | TabNav::Contained) => {
1513                let mut nav = already_found;
1514
1515                if !nav.contains(FocusNavAction::PREV) && self.prev_tab_focusable_impl(skip_self, true).is_some() {
1516                    nav |= FocusNavAction::PREV;
1517                }
1518                if !nav.contains(FocusNavAction::NEXT) && self.next_tab_focusable_impl(skip_self, true).is_some() {
1519                    nav |= FocusNavAction::NEXT;
1520                }
1521
1522                if !nav.contains(FocusNavAction::PREV | FocusNavAction::NEXT)
1523                    && tab_nav == TabNav::Continue
1524                    && let Some(p_scope) = scope.scope()
1525                {
1526                    nav |= scope.enabled_tab_nav(&p_scope, p_scope.focus_info(), true, nav)
1527                }
1528                nav
1529            }
1530            TabNav::Cycle => {
1531                if scope.descendants().tree_filter(Self::filter_tab_skip).any(|w| &w != self) {
1532                    FocusNavAction::PREV | FocusNavAction::NEXT
1533                } else {
1534                    FocusNavAction::empty()
1535                }
1536            }
1537            TabNav::Once => {
1538                if let Some(p_scope) = scope.scope() {
1539                    scope.enabled_tab_nav(&p_scope, p_scope.focus_info(), true, already_found)
1540                } else {
1541                    FocusNavAction::empty()
1542                }
1543            }
1544        }
1545    }
1546
1547    fn enabled_directional_nav(
1548        &self,
1549        scope: &WidgetFocusInfo,
1550        scope_info: FocusInfo,
1551        skip_self: bool,
1552        already_found: FocusNavAction,
1553    ) -> FocusNavAction {
1554        let directional_nav = scope_info.directional_nav();
1555
1556        if directional_nav == DirectionalNav::None {
1557            return FocusNavAction::empty();
1558        }
1559
1560        let mut nav = already_found;
1561        let from_pt = self.info.inner_bounds().to_box2d();
1562
1563        if !nav.contains(FocusNavAction::UP)
1564            && self
1565                .directional_from(scope, from_pt, Orientation2D::Above, skip_self, true)
1566                .is_some()
1567        {
1568            nav |= FocusNavAction::UP;
1569        }
1570        if !nav.contains(FocusNavAction::RIGHT)
1571            && self
1572                .directional_from(scope, from_pt, Orientation2D::Right, skip_self, true)
1573                .is_some()
1574        {
1575            nav |= FocusNavAction::RIGHT;
1576        }
1577        if !nav.contains(FocusNavAction::DOWN)
1578            && self
1579                .directional_from(scope, from_pt, Orientation2D::Below, skip_self, true)
1580                .is_some()
1581        {
1582            nav |= FocusNavAction::DOWN;
1583        }
1584        if !nav.contains(FocusNavAction::LEFT)
1585            && self
1586                .directional_from(scope, from_pt, Orientation2D::Left, skip_self, true)
1587                .is_some()
1588        {
1589            nav |= FocusNavAction::LEFT;
1590        }
1591
1592        if !nav.contains(FocusNavAction::DIRECTIONAL) {
1593            match directional_nav {
1594                DirectionalNav::Continue => {
1595                    if let Some(p_scope) = scope.scope() {
1596                        nav |= scope.enabled_directional_nav(&p_scope, p_scope.focus_info(), true, nav);
1597                    }
1598                }
1599                DirectionalNav::Cycle => {
1600                    let scope_bounds = scope.info.inner_bounds();
1601                    if !nav.contains(FocusNavAction::UP) {
1602                        let mut from_pt = from_pt.center();
1603                        from_pt.y = scope_bounds.max().y;
1604                        if self
1605                            .directional_from(
1606                                scope,
1607                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1608                                Orientation2D::Above,
1609                                true,
1610                                true,
1611                            )
1612                            .is_some()
1613                        {
1614                            nav |= FocusNavAction::UP;
1615                        }
1616                    }
1617                    if !nav.contains(FocusNavAction::RIGHT) {
1618                        let mut from_pt = from_pt.center();
1619                        from_pt.x = scope_bounds.min().x;
1620                        if self
1621                            .directional_from(
1622                                scope,
1623                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1624                                Orientation2D::Right,
1625                                true,
1626                                true,
1627                            )
1628                            .is_some()
1629                        {
1630                            nav |= FocusNavAction::RIGHT;
1631                        }
1632                    }
1633                    if !nav.contains(FocusNavAction::DOWN) {
1634                        let mut from_pt = from_pt.center();
1635                        from_pt.y = scope_bounds.min().y;
1636                        if self
1637                            .directional_from(
1638                                scope,
1639                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1640                                Orientation2D::Below,
1641                                true,
1642                                true,
1643                            )
1644                            .is_some()
1645                        {
1646                            nav |= FocusNavAction::DOWN;
1647                        }
1648                    }
1649                    if !nav.contains(FocusNavAction::LEFT) {
1650                        let mut from_pt = from_pt.center();
1651                        from_pt.x = scope_bounds.max().x;
1652                        if self
1653                            .directional_from(
1654                                scope,
1655                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1656                                Orientation2D::Left,
1657                                true,
1658                                true,
1659                            )
1660                            .is_some()
1661                        {
1662                            nav |= FocusNavAction::LEFT;
1663                        }
1664                    }
1665
1666                    if !nav.contains(FocusNavAction::DIRECTIONAL) {
1667                        let info = self.focus_info();
1668
1669                        if info.is_scope() && matches!(info.directional_nav(), DirectionalNav::Continue) {
1670                            // continue scope as single child of cycle scope.
1671                            if nav.contains(FocusNavAction::UP) || nav.contains(FocusNavAction::DOWN) {
1672                                nav |= FocusNavAction::UP | FocusNavAction::DOWN;
1673                            }
1674                            if nav.contains(FocusNavAction::LEFT) || nav.contains(FocusNavAction::RIGHT) {
1675                                nav |= FocusNavAction::LEFT | FocusNavAction::RIGHT;
1676                            }
1677                        }
1678                    }
1679                }
1680                _ => {}
1681            }
1682        }
1683
1684        nav
1685    }
1686
1687    /// Focus navigation actions that can move the focus away from this item.
1688    pub fn enabled_nav(&self) -> FocusNavAction {
1689        let _span = tracing::trace_span!("enabled_nav").entered();
1690
1691        let mut nav = FocusNavAction::empty();
1692
1693        if let Some(scope) = self.scope() {
1694            nav |= FocusNavAction::EXIT;
1695            nav.set(FocusNavAction::ENTER, self.descendants().next().is_some());
1696
1697            let scope_info = scope.focus_info();
1698
1699            nav |= self.enabled_tab_nav(&scope, scope_info, false, FocusNavAction::empty());
1700            nav |= self.enabled_directional_nav(&scope, scope_info, false, FocusNavAction::empty());
1701        }
1702
1703        nav.set(FocusNavAction::ALT, self.in_alt_scope() || self.alt_scope().is_some());
1704
1705        nav
1706    }
1707}
1708impl_from_and_into_var! {
1709    fn from(focus_info: WidgetFocusInfo) -> WidgetInfo {
1710        focus_info.info
1711    }
1712}
1713
1714/// Focus metadata associated with a widget info tree.
1715#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
1716pub enum FocusInfo {
1717    /// The widget is not focusable.
1718    NotFocusable,
1719    /// The widget is focusable as a single item.
1720    Focusable {
1721        /// Tab index of the widget.
1722        tab_index: TabIndex,
1723        /// If the widget is skipped during directional navigation from outside.
1724        skip_directional: bool,
1725    },
1726    /// The widget is a focusable focus scope.
1727    FocusScope {
1728        /// Tab index of the widget.
1729        tab_index: TabIndex,
1730        /// If the widget is skipped during directional navigation from outside.
1731        skip_directional: bool,
1732        /// Tab navigation inside the focus scope.
1733        tab_nav: TabNav,
1734        /// Directional navigation inside the focus scope.
1735        directional_nav: DirectionalNav,
1736        /// Behavior of the widget when receiving direct focus.
1737        on_focus: FocusScopeOnFocus,
1738        /// If this scope is focused when the ALT key is pressed.
1739        alt: bool,
1740    },
1741}
1742
1743/// Behavior of a focus scope when it receives direct focus.
1744#[derive(Clone, Copy, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
1745pub enum FocusScopeOnFocus {
1746    /// Just focus the scope widget.
1747    Widget,
1748    /// Focus the first descendant considering the TAB index, if the scope has no descendants
1749    /// behaves like [`Widget`].
1750    ///
1751    /// Focus the last descendant if the focus is *reversing* in, e.g. in a SHIFT+TAB action.
1752    ///
1753    /// Behaves like [`Widget`] if the first(or last) descendant inner-bounds is not fully contained
1754    /// by the scope inner-bounds.
1755    ///
1756    /// [`Widget`]: Self::Widget
1757    FirstDescendant,
1758    /// Focus the descendant that was last focused before focus moved out of the scope. If the
1759    /// scope cannot return focus, behaves like [`FirstDescendant`].
1760    ///
1761    /// If the scope is the only child of a parent that is `TabNav::Cycle` and the focus just exited and
1762    /// returned in a cycle action, behaves like [`FirstDescendant`].
1763    ///
1764    /// Behaves like [`Widget`] if the first(or last) descendant inner-bounds is not fully contained
1765    /// by the scope inner-bounds.
1766    ///
1767    /// [`Widget`]: Self::Widget
1768    /// [`FirstDescendant`]: Self::FirstDescendant
1769    LastFocused,
1770
1771    /// Like [`FirstDescendant`], but also focus the descendant even if it's inner-bounds
1772    /// is not fully contained by the scope inner-bounds.
1773    ///
1774    /// The expectation is that the descendant is already visible or will be made visible when
1775    /// it receives focus, a scroll scope will scroll to make the descendant visible for example.
1776    ///
1777    /// [`FirstDescendant`]: Self::FirstDescendant
1778    FirstDescendantIgnoreBounds,
1779
1780    /// Like [`LastFocused`], but also focus the descendant even if it's inner-bounds
1781    /// is not fully contained by the scope inner-bounds.
1782    ///
1783    /// The expectation is that the descendant is already visible or will be made visible when
1784    /// it receives focus, a scroll scope will scroll to make the descendant visible for example.
1785    ///
1786    /// [`LastFocused`]: Self::LastFocused
1787    LastFocusedIgnoreBounds,
1788}
1789impl fmt::Debug for FocusScopeOnFocus {
1790    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1791        if f.alternate() {
1792            write!(f, "FocusScopeOnFocus::")?;
1793        }
1794        match self {
1795            FocusScopeOnFocus::Widget => write!(f, "Widget"),
1796            FocusScopeOnFocus::FirstDescendant => write!(f, "FirstDescendant"),
1797            FocusScopeOnFocus::LastFocused => write!(f, "LastFocused"),
1798            FocusScopeOnFocus::FirstDescendantIgnoreBounds => write!(f, "FirstDescendantIgnoreBounds"),
1799            FocusScopeOnFocus::LastFocusedIgnoreBounds => write!(f, "LastFocusedIgnoreBounds"),
1800        }
1801    }
1802}
1803impl Default for FocusScopeOnFocus {
1804    /// [`FirstDescendant`](Self::FirstDescendant)
1805    fn default() -> Self {
1806        FocusScopeOnFocus::FirstDescendant
1807    }
1808}
1809
1810impl FocusInfo {
1811    /// If is focusable or a focus scope.
1812    pub fn is_focusable(self) -> bool {
1813        !matches!(self, FocusInfo::NotFocusable)
1814    }
1815
1816    /// If is a focus scope.
1817    pub fn is_scope(self) -> bool {
1818        matches!(self, FocusInfo::FocusScope { .. })
1819    }
1820
1821    /// If is an ALT focus scope.
1822    pub fn is_alt_scope(self) -> bool {
1823        match self {
1824            FocusInfo::FocusScope { alt, .. } => alt,
1825            _ => false,
1826        }
1827    }
1828
1829    /// Tab navigation mode.
1830    ///
1831    /// | Variant                   | Returns                                 |
1832    /// |---------------------------|-----------------------------------------|
1833    /// | Focus scope               | Associated value, default is `Continue` |
1834    /// | Focusable                 | `TabNav::Continue`                      |
1835    /// | Not-Focusable             | `TabNav::None`                          |
1836    pub fn tab_nav(self) -> TabNav {
1837        match self {
1838            FocusInfo::FocusScope { tab_nav, .. } => tab_nav,
1839            FocusInfo::Focusable { .. } => TabNav::Continue,
1840            FocusInfo::NotFocusable => TabNav::None,
1841        }
1842    }
1843
1844    /// Directional navigation mode.
1845    ///
1846    /// | Variant                   | Returns                             |
1847    /// |---------------------------|-------------------------------------|
1848    /// | Focus scope               | Associated value, default is `None` |
1849    /// | Focusable                 | `DirectionalNav::Continue`          |
1850    /// | Not-Focusable             | `DirectionalNav::None`              |
1851    pub fn directional_nav(self) -> DirectionalNav {
1852        match self {
1853            FocusInfo::FocusScope { directional_nav, .. } => directional_nav,
1854            FocusInfo::Focusable { .. } => DirectionalNav::Continue,
1855            FocusInfo::NotFocusable => DirectionalNav::None,
1856        }
1857    }
1858
1859    /// Tab navigation index.
1860    ///
1861    /// | Variant           | Returns                                       |
1862    /// |-------------------|-----------------------------------------------|
1863    /// | Focusable & Scope | Associated value, default is `TabIndex::AUTO` |
1864    /// | Not-Focusable     | `TabIndex::SKIP`                              |
1865    pub fn tab_index(self) -> TabIndex {
1866        match self {
1867            FocusInfo::Focusable { tab_index, .. } => tab_index,
1868            FocusInfo::FocusScope { tab_index, .. } => tab_index,
1869            FocusInfo::NotFocusable => TabIndex::SKIP,
1870        }
1871    }
1872
1873    /// If directional navigation skips over this widget.
1874    ///
1875    /// | Variant           | Returns                                       |
1876    /// |-------------------|-----------------------------------------------|
1877    /// | Focusable & Scope | Associated value, default is `false`          |
1878    /// | Not-Focusable     | `true`                                        |
1879    pub fn skip_directional(self) -> bool {
1880        match self {
1881            FocusInfo::Focusable { skip_directional, .. } => skip_directional,
1882            FocusInfo::FocusScope { skip_directional, .. } => skip_directional,
1883            FocusInfo::NotFocusable => true,
1884        }
1885    }
1886
1887    /// Focus scope behavior when it receives direct focus.
1888    ///
1889    /// | Variant                   | Returns                                                           |
1890    /// |---------------------------|-------------------------------------------------------------------|
1891    /// | Scope                     | Associated value, default is `FocusScopeOnFocus::FirstDescendant` |
1892    /// | Focusable & Not-Focusable | `FocusScopeOnFocus::Self_`                                        |
1893    pub fn scope_on_focus(self) -> FocusScopeOnFocus {
1894        match self {
1895            FocusInfo::FocusScope { on_focus, .. } => on_focus,
1896            _ => FocusScopeOnFocus::Widget,
1897        }
1898    }
1899}
1900
1901static_id! {
1902    static ref FOCUS_INFO_ID: StateId<FocusInfoData>;
1903    static ref FOCUS_TREE_ID: StateId<FocusTreeData>;
1904}
1905
1906#[derive(Default)]
1907pub(super) struct FocusTreeData {
1908    alt_scopes: Mutex<IdSet<WidgetId>>,
1909}
1910impl FocusTreeData {
1911    pub(super) fn consolidate_alt_scopes(prev_tree: &WidgetInfoTree, new_tree: &WidgetInfoTree) {
1912        // reused widgets don't insert build-meta, so we add the previous ALT scopes and validate everything.
1913
1914        let prev = prev_tree
1915            .build_meta()
1916            .get(*FOCUS_TREE_ID)
1917            .map(|d| d.alt_scopes.lock().clone())
1918            .unwrap_or_default();
1919
1920        let mut alt_scopes = prev;
1921        if let Some(data) = new_tree.build_meta().get(*FOCUS_TREE_ID) {
1922            alt_scopes.extend(data.alt_scopes.lock().iter());
1923        }
1924
1925        alt_scopes.retain(|id| {
1926            if let Some(wgt) = new_tree.get(*id)
1927                && let Some(info) = wgt.meta().get(*FOCUS_INFO_ID)
1928                && info.build().is_alt_scope()
1929            {
1930                for parent in wgt.ancestors() {
1931                    if let Some(info) = parent.meta().get(*FOCUS_INFO_ID)
1932                        && info.build().is_scope()
1933                    {
1934                        info.inner_alt.store(Some(*id), Relaxed);
1935                        break;
1936                    }
1937                }
1938
1939                return true;
1940            }
1941            false
1942        });
1943
1944        if let Some(data) = new_tree.build_meta().get(*FOCUS_TREE_ID) {
1945            *data.alt_scopes.lock() = alt_scopes;
1946        }
1947    }
1948}
1949
1950#[derive(Default, Debug)]
1951struct FocusInfoData {
1952    focusable: Option<bool>,
1953    scope: Option<bool>,
1954    alt_scope: bool,
1955    on_focus: FocusScopeOnFocus,
1956    tab_index: Option<TabIndex>,
1957    tab_nav: Option<TabNav>,
1958    directional_nav: Option<DirectionalNav>,
1959    skip_directional: Option<bool>,
1960
1961    inner_alt: Atomic<Option<WidgetId>>,
1962
1963    access_handler_registered: bool,
1964}
1965impl FocusInfoData {
1966    /// Build a [`FocusInfo`] from the collected configuration in `self`.
1967    ///
1968    /// See [`FocusInfoBuilder`] for a review of the algorithm.
1969    pub fn build(&self) -> FocusInfo {
1970        match (self.focusable, self.scope, self.tab_index, self.tab_nav, self.directional_nav) {
1971            // Set as not focusable.
1972            (Some(false), _, _, _, _) => FocusInfo::NotFocusable,
1973
1974            // Set as focus scope and not set as not focusable
1975            // or set tab navigation and did not set as not focus scope
1976            // or set directional navigation and did not set as not focus scope.
1977            (_, Some(true), idx, tab, dir) | (_, None, idx, tab @ Some(_), dir) | (_, None, idx, tab, dir @ Some(_)) => {
1978                FocusInfo::FocusScope {
1979                    tab_index: idx.unwrap_or(TabIndex::AUTO),
1980                    skip_directional: self.skip_directional.unwrap_or_default(),
1981                    tab_nav: tab.unwrap_or(TabNav::Continue),
1982                    directional_nav: dir.unwrap_or(DirectionalNav::Continue),
1983                    alt: self.alt_scope,
1984                    on_focus: self.on_focus,
1985                }
1986            }
1987
1988            // Set as focusable and was not focus scope
1989            // or set tab index and was not focus scope and did not set as not focusable.
1990            (Some(true), _, idx, _, _) | (_, _, idx @ Some(_), _, _) => FocusInfo::Focusable {
1991                tab_index: idx.unwrap_or(TabIndex::AUTO),
1992                skip_directional: self.skip_directional.unwrap_or_default(),
1993            },
1994
1995            _ => FocusInfo::NotFocusable,
1996        }
1997    }
1998}
1999
2000/// Builder for [`FocusInfo`] accessible in a [`WidgetInfoBuilder`].
2001///
2002/// There are multiple focusable metadata that can be set on a widget. These rules define how the focusable
2003/// state of a widget is derived from the focusable metadata.
2004///
2005/// ### Rules
2006///
2007/// The widget is not focusable nor a focus scope if it set [`focusable`](Self::focusable) to `false`.
2008///
2009/// The widget is a *focus scope* if it set [`scope`](Self::scope) to `true` **or** if it set [`tab_nav`](Self::tab_nav) or
2010/// [`directional_nav`](Self::directional_nav) and did not set [`scope`](Self::scope) to `false`.
2011///
2012/// The widget is *focusable* if it set [`focusable`](Self::focusable) to `true` **or** if it set the [`tab_index`](Self::tab_index).
2013///
2014/// The widget is a *focus scope* if it sets [`nested_window`](NestedWindowWidgetInfoExt::nested_window), but the focus will always move inside
2015/// the nested window.
2016///
2017/// The widget is not focusable if it did not set any of the members mentioned.
2018///
2019/// ##### Tab Index
2020///
2021/// If the [`tab_index`](Self::tab_index) was not set but the widget is focusable or a focus scope, the [`TabIndex::AUTO`]
2022/// is used for the widget.
2023///
2024/// ##### Skip Directional
2025///
2026/// If the [`skip_directional`](Self::skip_directional) was not set but the widget is focusable or a focus scope, it is
2027/// set to `false` for the widget.
2028///
2029/// ##### Focus Scope
2030///
2031/// If the widget is a focus scope, it is configured using [`alt_scope`](Self::alt_scope) and [`on_focus`](Self::on_focus).
2032/// If the widget is not a scope these members are ignored.
2033///
2034/// ##### Tab Navigation
2035///
2036/// If [`tab_nav`](Self::tab_nav) is not set but the widget is a focus scope, [`TabNav::Continue`] is used.
2037///
2038/// ##### Directional Navigation
2039///
2040/// If [`directional_nav`](Self::directional_nav) is not set but the widget is a focus scope, [`DirectionalNav::Continue`] is used.
2041///
2042/// [`WidgetInfoBuilder`]: zng_app::widget::info::WidgetInfoBuilder
2043/// [`new`]: Self::new
2044pub struct FocusInfoBuilder<'a>(&'a mut WidgetInfoBuilder);
2045impl<'a> FocusInfoBuilder<'a> {
2046    /// New the builder.
2047    pub fn new(builder: &'a mut WidgetInfoBuilder) -> Self {
2048        let mut r = Self(builder);
2049        r.with_tree_data(|_| {}); // ensure that build meta is allocated.
2050        r
2051    }
2052
2053    fn with_data<R>(&mut self, visitor: impl FnOnce(&mut FocusInfoData) -> R) -> R {
2054        let mut access = self.0.access().is_some();
2055
2056        let r = self.0.with_meta(|m| {
2057            let data = m.into_entry(*FOCUS_INFO_ID).or_default();
2058
2059            if access {
2060                access = !std::mem::replace(&mut data.access_handler_registered, true);
2061            }
2062
2063            visitor(data)
2064        });
2065
2066        if access {
2067            // access info required and not registered
2068            self.0.access().unwrap().on_access_build(|args| {
2069                if args.widget.info().clone().into_focusable(true, false).is_some() {
2070                    args.node.commands.push(zng_view_api::access::AccessCmdName::Focus);
2071                }
2072            });
2073        }
2074
2075        r
2076    }
2077
2078    fn with_tree_data<R>(&mut self, visitor: impl FnOnce(&mut FocusTreeData) -> R) -> R {
2079        self.0.with_build_meta(|m| visitor(m.into_entry(*FOCUS_TREE_ID).or_default()))
2080    }
2081
2082    /// If the widget is definitely focusable or not.
2083    pub fn focusable(&mut self, is_focusable: bool) -> &mut Self {
2084        self.with_data(|data| {
2085            data.focusable = Some(is_focusable);
2086        });
2087        self
2088    }
2089
2090    /// Sets [`focusable`], only if it was not already set.
2091    ///
2092    /// [`focusable`]: Self::focusable
2093    pub fn focusable_passive(&mut self, is_focusable: bool) -> &mut Self {
2094        self.with_data(|data| {
2095            if data.focusable.is_none() {
2096                data.focusable = Some(is_focusable);
2097            }
2098        });
2099        self
2100    }
2101
2102    /// If the widget is definitely a focus scope or not.
2103    pub fn scope(&mut self, is_focus_scope: bool) -> &mut Self {
2104        self.with_data(|data| {
2105            data.scope = Some(is_focus_scope);
2106        });
2107        self
2108    }
2109
2110    /// If the widget is definitely an ALT focus scope or not.
2111    ///
2112    /// If `true` this also sets `TabIndex::SKIP`, `skip_directional_nav`, `TabNav::Cycle` and `DirectionalNav::Cycle` as default.
2113    pub fn alt_scope(&mut self, is_alt_focus_scope: bool) -> &mut Self {
2114        self.with_data(|data| {
2115            data.alt_scope = is_alt_focus_scope;
2116            if is_alt_focus_scope {
2117                data.scope = Some(true);
2118
2119                if data.tab_index.is_none() {
2120                    data.tab_index = Some(TabIndex::SKIP);
2121                }
2122                if data.tab_nav.is_none() {
2123                    data.tab_nav = Some(TabNav::Cycle);
2124                }
2125                if data.directional_nav.is_none() {
2126                    data.directional_nav = Some(DirectionalNav::Cycle);
2127                }
2128                if data.skip_directional.is_none() {
2129                    data.skip_directional = Some(true);
2130                }
2131            }
2132        });
2133        if is_alt_focus_scope {
2134            let wgt_id = self.0.widget_id();
2135            self.with_tree_data(|d| d.alt_scopes.lock().insert(wgt_id));
2136        }
2137        self
2138    }
2139
2140    /// When the widget is a focus scope, its behavior on receiving direct focus.
2141    pub fn on_focus(&mut self, as_focus_scope_on_focus: FocusScopeOnFocus) -> &mut Self {
2142        self.with_data(|data| {
2143            data.on_focus = as_focus_scope_on_focus;
2144        });
2145        self
2146    }
2147
2148    /// Widget TAB index.
2149    pub fn tab_index(&mut self, tab_index: TabIndex) -> &mut Self {
2150        self.with_data(|data| {
2151            data.tab_index = Some(tab_index);
2152        });
2153        self
2154    }
2155
2156    /// TAB navigation within this widget, if set turns the widget into a focus scope.
2157    pub fn tab_nav(&mut self, scope_tab_nav: TabNav) -> &mut Self {
2158        self.with_data(|data| {
2159            data.tab_nav = Some(scope_tab_nav);
2160        });
2161        self
2162    }
2163
2164    /// Directional navigation within this widget, if set turns the widget into a focus scope.
2165    pub fn directional_nav(&mut self, scope_directional_nav: DirectionalNav) -> &mut Self {
2166        self.with_data(|data| {
2167            data.directional_nav = Some(scope_directional_nav);
2168        });
2169        self
2170    }
2171    /// If directional navigation skips over this widget.
2172    pub fn skip_directional(&mut self, skip: bool) -> &mut Self {
2173        self.with_data(|data| {
2174            data.skip_directional = Some(skip);
2175        });
2176        self
2177    }
2178}