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](crate::focus#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](crate::focus#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 = 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        /// Allow focus in disabled widgets.
453        const DISABLED = 1;
454        /// Allow focus in hidden widgets.
455        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/// A [`WidgetInfoTree`] wrapper for querying focus info out of the widget tree.
468///
469/// [`WidgetInfoTree`]: zng_app::widget::info::WidgetInfoTree
470#[derive(Clone, Debug)]
471pub struct FocusInfoTree {
472    tree: WidgetInfoTree,
473    mode: FocusMode,
474}
475impl FocusInfoTree {
476    /// Wrap a `widget_info` reference to enable focus info querying.
477    ///
478    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
479    ///
480    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
481    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
482    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    /// Full widget info.
490    pub fn tree(&self) -> &WidgetInfoTree {
491        &self.tree
492    }
493
494    /// If [`DISABLED`] widgets are focusable in this tree.
495    ///
496    /// See the [`FOCUS.focus_disabled_widgets`] config for more details.
497    ///
498    /// [`DISABLED`]: zng_app::widget::info::Interactivity::DISABLED
499    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
500    pub fn focus_disabled_widgets(&self) -> bool {
501        self.mode.contains(FocusMode::DISABLED)
502    }
503
504    /// If [`Hidden`] widgets are focusable in this tree.
505    ///
506    /// See the [`FOCUS.focus_hidden_widgets`] config for more details.
507    ///
508    /// [`Hidden`]: Visibility::Hidden
509    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
510    pub fn focus_hidden_widgets(&self) -> bool {
511        self.mode.contains(FocusMode::HIDDEN)
512    }
513
514    /// Reference to the root widget in the tree.
515    ///
516    /// The root is usually a focusable focus scope but it may not be. This
517    /// is the only method that returns a [`WidgetFocusInfo`] that may not be focusable.
518    pub fn root(&self) -> WidgetFocusInfo {
519        WidgetFocusInfo {
520            info: self.tree.root(),
521            mode: self.mode,
522        }
523    }
524
525    /// Reference the focusable widget closest to the window root.
526    ///
527    /// When the window root is not focusable, but a descendant widget is, this method returns
528    /// the focusable closest to the root counting previous siblings then parents.
529    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    /// Reference to the widget in the tree, if it is present and is focusable.
550    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    /// Reference to the first focusable widget or parent in the tree.
557    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    /// If the tree info contains the widget and it is focusable.
563    pub fn contains(&self, widget_id: impl Into<WidgetId>) -> bool {
564        self.get(widget_id).is_some()
565    }
566}
567
568/// [`WidgetInfo`] extensions that build a [`WidgetFocusInfo`].
569///
570/// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
571pub trait WidgetInfoFocusExt {
572    /// Wraps the [`WidgetInfo`] in a [`WidgetFocusInfo`] even if it is not focusable.
573    ///
574    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
575    ///
576    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
577    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
578    /// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
579    fn into_focus_info(self, focus_disabled_widgets: bool, focus_hidden_widgets: bool) -> WidgetFocusInfo;
580    /// Returns a wrapped [`WidgetFocusInfo`] if the [`WidgetInfo`] is focusable.
581    ///
582    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
583    ///
584    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
585    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
586    /// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
587    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/// [`WidgetInfo`] wrapper that adds focus information for each widget.
600///
601/// [`WidgetInfo`]: zng_app::widget::info::WidgetInfo
602#[derive(Clone, Eq, PartialEq, Hash, Debug)]
603pub struct WidgetFocusInfo {
604    info: WidgetInfo,
605    mode: FocusMode,
606}
607impl WidgetFocusInfo {
608    /// Wrap a `widget_info` reference to enable focus info querying.
609    ///
610    /// See the [`FOCUS.focus_disabled_widgets`] and [`FOCUS.focus_hidden_widgets`] config for more details on the parameters.
611    ///
612    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
613    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
614    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    /// Full widget info.
622    pub fn info(&self) -> &WidgetInfo {
623        &self.info
624    }
625
626    /// If [`DISABLED`] widgets are focusable in this tree.
627    ///
628    /// See the [`FOCUS.focus_disabled_widgets`] config for more details.
629    ///
630    /// [`DISABLED`]: zng_app::widget::info::Interactivity::DISABLED
631    /// [`FOCUS.focus_disabled_widgets`]: crate::focus::FOCUS::focus_disabled_widgets
632    pub fn focus_disabled_widgets(&self) -> bool {
633        self.mode.contains(FocusMode::DISABLED)
634    }
635
636    /// If [`Hidden`] widgets are focusable in this tree.
637    ///
638    /// See the [`FOCUS.focus_hidden_widgets`] config for more details.
639    ///
640    /// [`Hidden`]: Visibility::Hidden
641    /// [`FOCUS.focus_hidden_widgets`]: crate::focus::FOCUS::focus_hidden_widgets
642    pub fn focus_hidden_widgets(&self) -> bool {
643        self.mode.contains(FocusMode::HIDDEN)
644    }
645
646    /// Root focusable.
647    pub fn root(&self) -> Self {
648        self.ancestors().last().unwrap_or_else(|| self.clone())
649    }
650
651    /// Clone a reference to the [`FocusInfoTree`] that owns this widget.
652    pub fn focus_tree(&self) -> FocusInfoTree {
653        FocusInfoTree {
654            tree: self.info.tree().clone(),
655            mode: self.mode,
656        }
657    }
658
659    /// If the widget is focusable.
660    ///
661    /// ## Note
662    ///
663    /// This is probably `true`, the only way to get a [`WidgetFocusInfo`] for a non-focusable widget is by
664    /// calling [`into_focus_info`](WidgetInfoFocusExt::into_focus_info) or explicitly constructing one.
665    ///
666    /// Focus scopes are also focusable.
667    pub fn is_focusable(&self) -> bool {
668        self.focus_info().is_focusable()
669    }
670
671    /// Is focus scope.
672    pub fn is_scope(&self) -> bool {
673        self.focus_info().is_scope()
674    }
675
676    /// Is ALT focus scope.
677    pub fn is_alt_scope(&self) -> bool {
678        self.focus_info().is_alt_scope()
679    }
680
681    /// Gets the nested window ID, if this widget hosts a nested window.
682    ///
683    /// Nested window hosts always focus the nested window on focus.
684    pub fn nested_window(&self) -> Option<WindowId> {
685        self.info.nested_window()
686    }
687
688    /// Gets the nested window focus tree, if this widget hosts a nested window.
689    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    /// Widget focus metadata.
736    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                // service will actually focus nested window
742                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    /// Widget focus metadata, all things equal except the widget interactivity is blocked.
756    pub fn focus_info_ignore_blocked(&self) -> FocusInfo {
757        if self.mode_allows_focus_ignore_blocked() {
758            if let Some(builder) = self.info.meta().get(*FOCUS_INFO_ID) {
759                return builder.build();
760            }
761        }
762        FocusInfo::NotFocusable
763    }
764
765    /// Iterator over focusable parent -> grandparent -> .. -> root.
766    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    /// Iterator over self -> focusable parent -> grandparent -> .. -> root.
773    pub fn self_and_ancestors(&self) -> impl Iterator<Item = WidgetFocusInfo> {
774        [self.clone()].into_iter().chain(self.ancestors())
775    }
776
777    /// Iterator over focus scopes parent -> grandparent -> .. -> root.
778    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    /// Reference to the focusable parent that contains this widget.
788    pub fn parent(&self) -> Option<WidgetFocusInfo> {
789        self.ancestors().next()
790    }
791
792    /// Reference the focus scope parent that contains the widget.
793    pub fn scope(&self) -> Option<WidgetFocusInfo> {
794        self.scopes().next()
795    }
796
797    /// Reference the ALT focus scope *closest* with the current widget.
798    ///
799    /// # Closest Alt Scope
800    ///
801    /// - If `self` is already an ALT scope or is in one, moves to a sibling ALT scope, nested ALT scopes are ignored.
802    /// - If `self` is a normal scope, moves to the first descendant ALT scope, otherwise..
803    /// - Recursively searches for an ALT scope sibling up the scope tree.
804    pub fn alt_scope(&self) -> Option<WidgetFocusInfo> {
805        if self.in_alt_scope() {
806            // We do not allow nested alt scopes, search for sibling focus scope.
807            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            None
816        } else if self.is_scope() {
817            // if we are a normal scope, try for an inner ALT scope descendant first.
818            let r = self.inner_alt_scope();
819            if r.is_some() {
820                return r;
821            }
822            if let Some(scope) = self.scope() {
823                // search sibling ALT scope.
824                return scope.inner_alt_scope_skip(self);
825            }
826            None
827        } else if let Some(scope) = self.scope() {
828            // search sibling ALT scope.
829            if self.is_focusable() {
830                scope.inner_alt_scope_skip(self)
831            } else {
832                scope.inner_alt_scope()
833            }
834        } else {
835            // we reached root, no ALT found.
836            None
837        }
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            if let Some(wgt) = self.info.tree().get(id) {
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        }
849        None
850    }
851    fn inner_alt_scope_skip(self, skip: &WidgetFocusInfo) -> Option<WidgetFocusInfo> {
852        if let Some(alt) = self.inner_alt_scope() {
853            if !alt.info.is_descendant(&skip.info) && alt.info != skip.info {
854                return Some(alt);
855            }
856        }
857        None
858    }
859
860    /// Widget is in a ALT scope or is an ALT scope.
861    pub fn in_alt_scope(&self) -> bool {
862        self.is_alt_scope() || self.scopes().any(|s| s.is_alt_scope())
863    }
864
865    /// Widget the focus needs to move to when `self` gets focused.
866    ///
867    /// # Input
868    ///
869    /// * `last_focused`: A function that returns the last focused widget within a focus scope identified by `WidgetId`.
870    /// * `is_tab_cycle_reentry`: If the focus returned to `self` immediately after leaving because the parent scope is `TabNav::Cycle`.
871    /// * `reverse`: If the focus *reversed* into `self`.
872    ///
873    /// # Returns
874    ///
875    /// Returns the different widget the focus must move to after focusing in `self` that is a focus scope.
876    ///
877    /// If `self` is not a [`FocusScope`](FocusInfo::FocusScope) always returns `None`.
878    pub fn on_focus_scope_move<'f>(
879        &self,
880        last_focused: impl FnOnce(WidgetId) -> Option<&'f WidgetPath>,
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(|path| self.info.tree().get(path.widget_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) // valid last focused
901                                } 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                    } // fallback
913                    FocusScopeOnFocus::Widget => None,
914                };
915
916                // if not IgnoreBounds and some candidate
917                if let (FocusScopeOnFocus::FirstDescendant | FocusScopeOnFocus::LastFocused, Some(candidate)) = (on_focus, &candidate) {
918                    if !self.info.inner_bounds().contains_rect(&candidate.info().inner_bounds()) {
919                        // not fully in bounds.
920                        return None;
921                    }
922                }
923
924                candidate
925            }
926            FocusInfo::NotFocusable | FocusInfo::Focusable { .. } => None,
927        }
928    }
929
930    /// Iterator over the focusable widgets contained by this widget.
931    pub fn descendants(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
932        super::iter::FocusTreeIter::new(self.info.descendants(), self.mode)
933    }
934
935    /// Iterator over self and the focusable widgets contained by it.
936    pub fn self_and_descendants(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
937        super::iter::FocusTreeIter::new(self.info.self_and_descendants(), self.mode)
938    }
939
940    /// If the focusable has any focusable descendant that is not [`TabIndex::SKIP`]
941    pub fn has_tab_descendant(&self) -> bool {
942        self.descendants().tree_find(Self::filter_tab_skip).is_some()
943    }
944
945    /// First descendant considering TAB index.
946    pub fn first_tab_descendant(&self) -> Option<WidgetFocusInfo> {
947        let mut best = (TabIndex::SKIP, self.clone());
948
949        for d in self.descendants().tree_filter(Self::filter_tab_skip) {
950            let idx = d.focus_info().tab_index();
951
952            if idx < best.0 {
953                best = (idx, d);
954            }
955        }
956
957        if best.0.is_skip() { None } else { Some(best.1) }
958    }
959
960    /// Last descendant considering TAB index.
961    pub fn last_tab_descendant(&self) -> Option<WidgetFocusInfo> {
962        let mut best = (-1i64, self.clone());
963
964        for d in self.descendants().tree_rev().tree_filter(Self::filter_tab_skip) {
965            let idx = d.focus_info().tab_index().0 as i64;
966
967            if idx > best.0 {
968                best = (idx, d);
969            }
970        }
971
972        if best.0 < 0 { None } else { Some(best.1) }
973    }
974
975    /// Iterator over all focusable widgets in the same scope after this widget.
976    pub fn next_focusables(&self) -> super::iter::FocusTreeIter<w_iter::TreeIter> {
977        if let Some(scope) = self.scope() {
978            super::iter::FocusTreeIter::new(self.info.next_siblings_in(&scope.info), self.mode)
979        } else {
980            // empty
981            super::iter::FocusTreeIter::new(self.info.next_siblings_in(&self.info), self.mode)
982        }
983    }
984
985    /// Next focusable in the same scope after this widget.
986    pub fn next_focusable(&self) -> Option<WidgetFocusInfo> {
987        self.next_focusables().next()
988    }
989
990    fn filter_tab_skip(w: &WidgetFocusInfo) -> TreeFilter {
991        if w.focus_info().tab_index().is_skip() {
992            TreeFilter::SkipAll
993        } else {
994            TreeFilter::Include
995        }
996    }
997
998    /// Next focusable in the same scope after this widget respecting the TAB index.
999    ///
1000    /// If `self` is set to [`TabIndex::SKIP`] returns the next non-skip focusable in the same scope after this widget.
1001    ///
1002    /// If `skip_self` is `true`, does not include widgets inside `self`.
1003    pub fn next_tab_focusable(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1004        self.next_tab_focusable_impl(skip_self, false)
1005    }
1006    fn next_tab_focusable_impl(&self, skip_self: bool, any: bool) -> Option<WidgetFocusInfo> {
1007        let self_index = self.focus_info().tab_index();
1008
1009        if self_index == TabIndex::SKIP {
1010            // TAB from skip, goes to next in widget tree.
1011            return self.next_focusables().tree_find(Self::filter_tab_skip);
1012        }
1013
1014        let mut best = (TabIndex::SKIP, self.clone());
1015
1016        if !skip_self {
1017            for d in self.descendants().tree_filter(Self::filter_tab_skip) {
1018                let idx = d.focus_info().tab_index();
1019
1020                if idx == self_index {
1021                    return Some(d);
1022                } else if idx < best.0 && idx > self_index {
1023                    if any {
1024                        return Some(d);
1025                    }
1026                    best = (idx, d);
1027                }
1028            }
1029        }
1030
1031        for s in self.next_focusables().tree_filter(Self::filter_tab_skip) {
1032            let idx = s.focus_info().tab_index();
1033
1034            if idx == self_index {
1035                return Some(s);
1036            } else if idx < best.0 && idx > self_index {
1037                if any {
1038                    return Some(s);
1039                }
1040                best = (idx, s);
1041            }
1042        }
1043
1044        for s in self.prev_focusables().tree_filter(Self::filter_tab_skip) {
1045            let idx = s.focus_info().tab_index();
1046
1047            if idx <= best.0 && idx > self_index {
1048                if any {
1049                    return Some(s);
1050                }
1051                best = (idx, s);
1052            }
1053        }
1054
1055        if best.0.is_skip() { None } else { Some(best.1) }
1056    }
1057
1058    /// Iterator over all focusable widgets in the same scope before this widget in reverse.
1059    pub fn prev_focusables(&self) -> super::iter::FocusTreeIter<w_iter::RevTreeIter> {
1060        if let Some(scope) = self.scope() {
1061            super::iter::FocusTreeIter::new(self.info.prev_siblings_in(&scope.info), self.mode)
1062        } else {
1063            // empty
1064            super::iter::FocusTreeIter::new(self.info.prev_siblings_in(&self.info), self.mode)
1065        }
1066    }
1067
1068    /// Previous focusable in the same scope before this widget.
1069    pub fn prev_focusable(&self) -> Option<WidgetFocusInfo> {
1070        self.prev_focusables().next()
1071    }
1072
1073    /// Previous focusable in the same scope after this widget respecting the TAB index.
1074    ///
1075    /// If `self` is set to [`TabIndex::SKIP`] returns the previous non-skip focusable in the same scope before this widget.
1076    ///
1077    /// If `skip_self` is `true`, does not include widgets inside `self`.
1078    pub fn prev_tab_focusable(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1079        self.prev_tab_focusable_impl(skip_self, false)
1080    }
1081    fn prev_tab_focusable_impl(&self, skip_self: bool, any: bool) -> Option<WidgetFocusInfo> {
1082        let self_index = self.focus_info().tab_index();
1083
1084        if self_index == TabIndex::SKIP {
1085            // TAB from skip, goes to prev in widget tree.
1086            return self.prev_focusables().tree_find(Self::filter_tab_skip);
1087        }
1088
1089        let self_index = self_index.0 as i64;
1090        let mut best = (-1i64, self.clone());
1091
1092        if !skip_self {
1093            for d in self.descendants().tree_rev().tree_filter(Self::filter_tab_skip) {
1094                let idx = d.focus_info().tab_index().0 as i64;
1095
1096                if idx == self_index {
1097                    return Some(d);
1098                } else if idx > best.0 && idx < self_index {
1099                    if any {
1100                        return Some(d);
1101                    }
1102                    best = (idx, d);
1103                }
1104            }
1105        }
1106
1107        for s in self.prev_focusables().tree_filter(Self::filter_tab_skip) {
1108            let idx = s.focus_info().tab_index().0 as i64;
1109
1110            if idx == self_index {
1111                return Some(s);
1112            } else if idx > best.0 && idx < self_index {
1113                if any {
1114                    return Some(s);
1115                }
1116                best = (idx, s);
1117            }
1118        }
1119
1120        for s in self.next_focusables().tree_filter(Self::filter_tab_skip) {
1121            let idx = s.focus_info().tab_index().0 as i64;
1122
1123            if idx >= best.0 && idx < self_index {
1124                if any {
1125                    return Some(s);
1126                }
1127                best = (idx, s);
1128            }
1129        }
1130
1131        if best.0 < 0 { None } else { Some(best.1) }
1132    }
1133
1134    /// Widget to focus when pressing TAB from this widget.
1135    ///
1136    /// Set `skip_self` to not enter `self`, that is, the focus goes to the next sibling or next sibling descendant.
1137    ///
1138    /// Returns `None` if the focus does not move to another widget.
1139    pub fn next_tab(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1140        let _span = tracing::trace_span!("next_tab").entered();
1141
1142        if let Some(scope) = self.scope() {
1143            let scope_info = scope.focus_info();
1144            match scope_info.tab_nav() {
1145                TabNav::None => None,
1146                TabNav::Continue => self.next_tab_focusable(skip_self).or_else(|| scope.next_tab(true)),
1147                TabNav::Contained => self.next_tab_focusable(skip_self),
1148                TabNav::Cycle => self.next_tab_focusable(skip_self).or_else(|| scope.first_tab_descendant()),
1149                TabNav::Once => scope.next_tab(true),
1150            }
1151        } else {
1152            None
1153        }
1154    }
1155
1156    /// Widget to focus when pressing SHIFT+TAB from this widget.
1157    ///
1158    /// Set `skip_self` to not enter `self`, that is, the focus goes to the previous sibling or previous sibling descendant.
1159    ///
1160    /// Returns `None` if the focus does not move to another widget.
1161    pub fn prev_tab(&self, skip_self: bool) -> Option<WidgetFocusInfo> {
1162        let _span = tracing::trace_span!("prev_tab").entered();
1163        if let Some(scope) = self.scope() {
1164            let scope_info = scope.focus_info();
1165            match scope_info.tab_nav() {
1166                TabNav::None => None,
1167                TabNav::Continue => self.prev_tab_focusable(skip_self).or_else(|| scope.prev_tab(true)),
1168                TabNav::Contained => self.prev_tab_focusable(skip_self),
1169                TabNav::Cycle => self.prev_tab_focusable(skip_self).or_else(|| scope.last_tab_descendant()),
1170                TabNav::Once => scope.prev_tab(true),
1171            }
1172        } else {
1173            None
1174        }
1175    }
1176
1177    /// Find the focusable descendant with center point nearest of `origin` within the `max_radius`.
1178    pub fn nearest(&self, origin: PxPoint, max_radius: Px) -> Option<WidgetFocusInfo> {
1179        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1180        self.info
1181            .nearest_filtered(origin, max_radius, |w| cast(w.clone()).is_focusable())
1182            .map(cast)
1183    }
1184
1185    /// Find the descendant with center point nearest of `origin` within the `max_radius` and approved by the `filter` closure.
1186    pub fn nearest_filtered(
1187        &self,
1188        origin: PxPoint,
1189        max_radius: Px,
1190        mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1191    ) -> Option<WidgetFocusInfo> {
1192        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1193        self.info
1194            .nearest_filtered(origin, max_radius, |w| {
1195                let w = cast(w.clone());
1196                w.is_focusable() && filter(w)
1197            })
1198            .map(cast)
1199    }
1200
1201    /// Find the descendant with center point nearest of `origin` within the `max_radius` and inside `bounds`; and approved by the `filter` closure.
1202    pub fn nearest_bounded_filtered(
1203        &self,
1204        origin: PxPoint,
1205        max_radius: Px,
1206        bounds: PxRect,
1207        mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1208    ) -> Option<WidgetFocusInfo> {
1209        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1210        self.info
1211            .nearest_bounded_filtered(origin, max_radius, bounds, move |w| {
1212                let w = cast(w.clone());
1213                w.is_focusable() && filter(w)
1214            })
1215            .map(cast)
1216    }
1217
1218    /// Find the focusable descendant with center point nearest of `origin` within the `max_distance` and with `orientation` to origin.
1219    pub fn nearest_oriented(&self, origin: PxPoint, max_distance: Px, orientation: Orientation2D) -> Option<WidgetFocusInfo> {
1220        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1221        self.info
1222            .nearest_oriented_filtered(origin, max_distance, orientation, |w| cast(w.clone()).is_focusable())
1223            .map(cast)
1224    }
1225
1226    /// Find the focusable descendant with center point nearest of `origin` within the `max_distance` and with `orientation`
1227    /// to origin that passes the `filter`.
1228    pub fn nearest_oriented_filtered(
1229        &self,
1230        origin: PxPoint,
1231        max_distance: Px,
1232        orientation: Orientation2D,
1233        mut filter: impl FnMut(WidgetFocusInfo) -> bool,
1234    ) -> Option<WidgetFocusInfo> {
1235        let cast = |w: WidgetInfo| w.into_focus_info(self.focus_disabled_widgets(), self.focus_hidden_widgets());
1236        self.info
1237            .nearest_oriented_filtered(origin, max_distance, orientation, |w| {
1238                let w = cast(w.clone());
1239                w.is_focusable() && filter(w)
1240            })
1241            .map(cast)
1242    }
1243
1244    fn directional_from(
1245        &self,
1246        scope: &WidgetFocusInfo,
1247        origin: PxBox,
1248        orientation: Orientation2D,
1249        skip_self: bool,
1250        any: bool,
1251    ) -> Option<WidgetFocusInfo> {
1252        let self_id = self.info.id();
1253        let scope_id = scope.info.id();
1254
1255        // don't return focus to parent from non-focusable child.
1256        let skip_parent = if self.is_focusable() {
1257            None
1258        } else {
1259            self.ancestors().next().map(|w| w.info.id())
1260        };
1261
1262        let filter = |w: &WidgetFocusInfo| {
1263            let mut up_to_scope = w.self_and_ancestors().take_while(|w| w.info.id() != scope_id);
1264
1265            if skip_self {
1266                up_to_scope.all(|w| w.info.id() != self_id && !w.focus_info().skip_directional())
1267            } else {
1268                up_to_scope.all(|w| !w.focus_info().skip_directional())
1269            }
1270        };
1271
1272        let origin_center = origin.center();
1273
1274        let mut oriented = scope
1275            .info
1276            .oriented(origin_center, Px::MAX, orientation)
1277            .chain(
1278                // nearby boxes (not overlapped)
1279                scope
1280                    .info
1281                    .oriented_box(origin, origin.width().max(origin.height()) * Px(2), orientation)
1282                    .filter(|w| !w.inner_bounds().to_box2d().intersects(&origin)),
1283            )
1284            .focusable(self.focus_disabled_widgets(), self.focus_hidden_widgets())
1285            .filter(|w| w.info.id() != scope_id && Some(w.info.id()) != skip_parent);
1286
1287        if any {
1288            return oriented.find(filter);
1289        }
1290
1291        let parent_range = self.parent().map(|w| w.info.descendants_range()).unwrap_or_default();
1292
1293        let mut ancestor_dist = DistanceKey::NONE_MAX;
1294        let mut ancestor = None;
1295        let mut sibling_dist = DistanceKey::NONE_MAX;
1296        let mut sibling = None;
1297        let mut other_dist = DistanceKey::NONE_MAX;
1298        let mut other = None;
1299
1300        for w in oriented {
1301            if filter(&w) {
1302                let dist = w.info.distance_key(origin_center);
1303
1304                let mut is_ancestor = None;
1305                let mut is_ancestor = || *is_ancestor.get_or_insert_with(|| w.info.is_ancestor(&self.info));
1306
1307                let mut is_sibling = None;
1308                let mut is_sibling = || *is_sibling.get_or_insert_with(|| parent_range.contains(&w.info));
1309
1310                if dist <= ancestor_dist && is_ancestor() {
1311                    ancestor_dist = dist;
1312                    ancestor = Some(w);
1313                } else if dist <= sibling_dist && is_sibling() {
1314                    sibling_dist = dist;
1315                    sibling = Some(w);
1316                } else if dist <= other_dist && !is_ancestor() && !is_sibling() {
1317                    other_dist = dist;
1318                    other = Some(w);
1319                }
1320            }
1321        }
1322
1323        if other_dist <= ancestor_dist && other_dist <= sibling_dist {
1324            other
1325        } else {
1326            sibling.or(ancestor)
1327        }
1328    }
1329
1330    fn directional_next(&self, orientation: Orientation2D) -> Option<WidgetFocusInfo> {
1331        self.directional_next_from(orientation, self.info.inner_bounds().to_box2d())
1332    }
1333
1334    fn directional_next_from(&self, orientation: Orientation2D, from: PxBox) -> Option<WidgetFocusInfo> {
1335        self.scope()
1336            .and_then(|s| self.directional_from(&s, from, orientation, false, false))
1337    }
1338
1339    /// Closest focusable in the same scope above this widget.
1340    pub fn focusable_up(&self) -> Option<WidgetFocusInfo> {
1341        self.directional_next(Orientation2D::Above)
1342    }
1343
1344    /// Closest focusable in the same scope below this widget.
1345    pub fn focusable_down(&self) -> Option<WidgetFocusInfo> {
1346        self.directional_next(Orientation2D::Below)
1347    }
1348
1349    /// Closest focusable in the same scope to the left of this widget.
1350    pub fn focusable_left(&self) -> Option<WidgetFocusInfo> {
1351        self.directional_next(Orientation2D::Left)
1352    }
1353
1354    /// Closest focusable in the same scope to the right of this widget.
1355    pub fn focusable_right(&self) -> Option<WidgetFocusInfo> {
1356        self.directional_next(Orientation2D::Right)
1357    }
1358
1359    /// Widget to focus when pressing the arrow up key from this widget.
1360    pub fn next_up(&self) -> Option<WidgetFocusInfo> {
1361        let _span = tracing::trace_span!("next_up").entered();
1362        self.next_up_from(self.info.inner_bounds().to_box2d())
1363    }
1364    fn next_up_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1365        if let Some(scope) = self.scope() {
1366            let scope_info = scope.focus_info();
1367            match scope_info.directional_nav() {
1368                DirectionalNav::None => None,
1369                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Above, origin).or_else(|| {
1370                    let mut from = scope.info.inner_bounds();
1371                    from.origin.y -= Px(1);
1372                    from.size.height = Px(1);
1373                    scope.next_up_from(from.to_box2d())
1374                }),
1375                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Above, origin),
1376                DirectionalNav::Cycle => {
1377                    self.directional_next_from(Orientation2D::Above, origin).or_else(|| {
1378                        // next up from the same X but from the bottom segment of scope spatial bounds.
1379                        let mut from_pt = origin.center();
1380                        from_pt.y = scope.info.spatial_bounds().max.y;
1381                        self.directional_from(
1382                            &scope,
1383                            PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1384                            Orientation2D::Above,
1385                            false,
1386                            false,
1387                        )
1388                    })
1389                }
1390            }
1391        } else {
1392            None
1393        }
1394    }
1395
1396    /// Widget to focus when pressing the arrow right key from this widget.
1397    pub fn next_right(&self) -> Option<WidgetFocusInfo> {
1398        let _span = tracing::trace_span!("next_right").entered();
1399        self.next_right_from(self.info.inner_bounds().to_box2d())
1400    }
1401    fn next_right_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1402        if let Some(scope) = self.scope() {
1403            let scope_info = scope.focus_info();
1404            match scope_info.directional_nav() {
1405                DirectionalNav::None => None,
1406                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Right, origin).or_else(|| {
1407                    let mut from = scope.info.inner_bounds();
1408                    from.origin.x += from.size.width + Px(1);
1409                    from.size.width = Px(1);
1410                    scope.next_right_from(from.to_box2d())
1411                }),
1412                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Right, origin),
1413                DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Right, origin).or_else(|| {
1414                    // next right from the same Y but from the left segment of scope spatial bounds.
1415                    let mut from_pt = origin.center();
1416                    from_pt.x = scope.info.spatial_bounds().min.x;
1417                    self.directional_from(
1418                        &scope,
1419                        PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1420                        Orientation2D::Right,
1421                        false,
1422                        false,
1423                    )
1424                }),
1425            }
1426        } else {
1427            None
1428        }
1429    }
1430
1431    /// Widget to focus when pressing the arrow down key from this widget.
1432    pub fn next_down(&self) -> Option<WidgetFocusInfo> {
1433        let _span = tracing::trace_span!("next_down").entered();
1434        self.next_down_from(self.info.inner_bounds().to_box2d())
1435    }
1436    fn next_down_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1437        if let Some(scope) = self.scope() {
1438            let scope_info = scope.focus_info();
1439            match scope_info.directional_nav() {
1440                DirectionalNav::None => None,
1441                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Below, origin).or_else(|| {
1442                    let mut from = scope.info.inner_bounds();
1443                    from.origin.y += from.size.height + Px(1);
1444                    from.size.height = Px(1);
1445                    scope.next_down_from(from.to_box2d())
1446                }),
1447                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Below, origin),
1448                DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Below, origin).or_else(|| {
1449                    // next down from the same X but from the top segment of scope spatial bounds.
1450                    let mut from_pt = origin.center();
1451                    from_pt.y = scope.info.spatial_bounds().min.y;
1452                    self.directional_from(
1453                        &scope,
1454                        PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1455                        Orientation2D::Below,
1456                        false,
1457                        false,
1458                    )
1459                }),
1460            }
1461        } else {
1462            None
1463        }
1464    }
1465
1466    /// Widget to focus when pressing the arrow left key from this widget.
1467    pub fn next_left(&self) -> Option<WidgetFocusInfo> {
1468        let _span = tracing::trace_span!("next_left").entered();
1469        self.next_left_from(self.info.inner_bounds().to_box2d())
1470    }
1471    fn next_left_from(&self, origin: PxBox) -> Option<WidgetFocusInfo> {
1472        if let Some(scope) = self.scope() {
1473            let scope_info = scope.focus_info();
1474            match scope_info.directional_nav() {
1475                DirectionalNav::None => None,
1476                DirectionalNav::Continue => self.directional_next_from(Orientation2D::Left, origin).or_else(|| {
1477                    let mut from = scope.info.inner_bounds();
1478                    from.origin.x -= Px(1);
1479                    from.size.width = Px(1);
1480                    scope.next_left_from(from.to_box2d())
1481                }),
1482                DirectionalNav::Contained => self.directional_next_from(Orientation2D::Left, origin),
1483                DirectionalNav::Cycle => self.directional_next_from(Orientation2D::Left, origin).or_else(|| {
1484                    // next left from the same Y but from the right segment of scope spatial bounds.
1485                    let mut from_pt = origin.center();
1486                    from_pt.x = scope.info.spatial_bounds().max.x;
1487                    self.directional_from(
1488                        &scope,
1489                        PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1490                        Orientation2D::Left,
1491                        false,
1492                        false,
1493                    )
1494                }),
1495            }
1496        } else {
1497            None
1498        }
1499    }
1500
1501    fn enabled_tab_nav(
1502        &self,
1503        scope: &WidgetFocusInfo,
1504        scope_info: FocusInfo,
1505        skip_self: bool,
1506        already_found: FocusNavAction,
1507    ) -> FocusNavAction {
1508        match scope_info.tab_nav() {
1509            TabNav::None => FocusNavAction::empty(),
1510            tab_nav @ (TabNav::Continue | TabNav::Contained) => {
1511                let mut nav = already_found;
1512
1513                if !nav.contains(FocusNavAction::PREV) && self.prev_tab_focusable_impl(skip_self, true).is_some() {
1514                    nav |= FocusNavAction::PREV;
1515                }
1516                if !nav.contains(FocusNavAction::NEXT) && self.next_tab_focusable_impl(skip_self, true).is_some() {
1517                    nav |= FocusNavAction::NEXT;
1518                }
1519
1520                if !nav.contains(FocusNavAction::PREV | FocusNavAction::NEXT) && tab_nav == TabNav::Continue {
1521                    if let Some(p_scope) = scope.scope() {
1522                        nav |= scope.enabled_tab_nav(&p_scope, p_scope.focus_info(), true, nav)
1523                    }
1524                }
1525                nav
1526            }
1527            TabNav::Cycle => {
1528                if scope.descendants().tree_filter(Self::filter_tab_skip).any(|w| &w != self) {
1529                    FocusNavAction::PREV | FocusNavAction::NEXT
1530                } else {
1531                    FocusNavAction::empty()
1532                }
1533            }
1534            TabNav::Once => {
1535                if let Some(p_scope) = scope.scope() {
1536                    scope.enabled_tab_nav(&p_scope, p_scope.focus_info(), true, already_found)
1537                } else {
1538                    FocusNavAction::empty()
1539                }
1540            }
1541        }
1542    }
1543
1544    fn enabled_directional_nav(
1545        &self,
1546        scope: &WidgetFocusInfo,
1547        scope_info: FocusInfo,
1548        skip_self: bool,
1549        already_found: FocusNavAction,
1550    ) -> FocusNavAction {
1551        let directional_nav = scope_info.directional_nav();
1552
1553        if directional_nav == DirectionalNav::None {
1554            return FocusNavAction::empty();
1555        }
1556
1557        let mut nav = already_found;
1558        let from_pt = self.info.inner_bounds().to_box2d();
1559
1560        if !nav.contains(FocusNavAction::UP)
1561            && self
1562                .directional_from(scope, from_pt, Orientation2D::Above, skip_self, true)
1563                .is_some()
1564        {
1565            nav |= FocusNavAction::UP;
1566        }
1567        if !nav.contains(FocusNavAction::RIGHT)
1568            && self
1569                .directional_from(scope, from_pt, Orientation2D::Right, skip_self, true)
1570                .is_some()
1571        {
1572            nav |= FocusNavAction::RIGHT;
1573        }
1574        if !nav.contains(FocusNavAction::DOWN)
1575            && self
1576                .directional_from(scope, from_pt, Orientation2D::Below, skip_self, true)
1577                .is_some()
1578        {
1579            nav |= FocusNavAction::DOWN;
1580        }
1581        if !nav.contains(FocusNavAction::LEFT)
1582            && self
1583                .directional_from(scope, from_pt, Orientation2D::Left, skip_self, true)
1584                .is_some()
1585        {
1586            nav |= FocusNavAction::LEFT;
1587        }
1588
1589        if !nav.contains(FocusNavAction::DIRECTIONAL) {
1590            match directional_nav {
1591                DirectionalNav::Continue => {
1592                    if let Some(p_scope) = scope.scope() {
1593                        nav |= scope.enabled_directional_nav(&p_scope, p_scope.focus_info(), true, nav);
1594                    }
1595                }
1596                DirectionalNav::Cycle => {
1597                    let scope_bounds = scope.info.inner_bounds();
1598                    if !nav.contains(FocusNavAction::UP) {
1599                        let mut from_pt = from_pt.center();
1600                        from_pt.y = scope_bounds.max().y;
1601                        if self
1602                            .directional_from(
1603                                scope,
1604                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1605                                Orientation2D::Above,
1606                                true,
1607                                true,
1608                            )
1609                            .is_some()
1610                        {
1611                            nav |= FocusNavAction::UP;
1612                        }
1613                    }
1614                    if !nav.contains(FocusNavAction::RIGHT) {
1615                        let mut from_pt = from_pt.center();
1616                        from_pt.x = scope_bounds.min().x;
1617                        if self
1618                            .directional_from(
1619                                scope,
1620                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1621                                Orientation2D::Right,
1622                                true,
1623                                true,
1624                            )
1625                            .is_some()
1626                        {
1627                            nav |= FocusNavAction::RIGHT;
1628                        }
1629                    }
1630                    if !nav.contains(FocusNavAction::DOWN) {
1631                        let mut from_pt = from_pt.center();
1632                        from_pt.y = scope_bounds.min().y;
1633                        if self
1634                            .directional_from(
1635                                scope,
1636                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1637                                Orientation2D::Below,
1638                                true,
1639                                true,
1640                            )
1641                            .is_some()
1642                        {
1643                            nav |= FocusNavAction::DOWN;
1644                        }
1645                    }
1646                    if !nav.contains(FocusNavAction::LEFT) {
1647                        let mut from_pt = from_pt.center();
1648                        from_pt.x = scope_bounds.max().x;
1649                        if self
1650                            .directional_from(
1651                                scope,
1652                                PxRect::new(from_pt, PxSize::splat(Px(1))).to_box2d(),
1653                                Orientation2D::Left,
1654                                true,
1655                                true,
1656                            )
1657                            .is_some()
1658                        {
1659                            nav |= FocusNavAction::LEFT;
1660                        }
1661                    }
1662
1663                    if !nav.contains(FocusNavAction::DIRECTIONAL) {
1664                        let info = self.focus_info();
1665
1666                        if info.is_scope() && matches!(info.directional_nav(), DirectionalNav::Continue) {
1667                            // continue scope as single child of cycle scope.
1668                            if nav.contains(FocusNavAction::UP) || nav.contains(FocusNavAction::DOWN) {
1669                                nav |= FocusNavAction::UP | FocusNavAction::DOWN;
1670                            }
1671                            if nav.contains(FocusNavAction::LEFT) || nav.contains(FocusNavAction::RIGHT) {
1672                                nav |= FocusNavAction::LEFT | FocusNavAction::RIGHT;
1673                            }
1674                        }
1675                    }
1676                }
1677                _ => {}
1678            }
1679        }
1680
1681        nav
1682    }
1683
1684    /// Focus navigation actions that can move the focus away from this item.
1685    pub fn enabled_nav(&self) -> FocusNavAction {
1686        let _span = tracing::trace_span!("enabled_nav").entered();
1687
1688        let mut nav = FocusNavAction::empty();
1689
1690        if let Some(scope) = self.scope() {
1691            nav |= FocusNavAction::EXIT;
1692            nav.set(FocusNavAction::ENTER, self.descendants().next().is_some());
1693
1694            let scope_info = scope.focus_info();
1695
1696            nav |= self.enabled_tab_nav(&scope, scope_info, false, FocusNavAction::empty());
1697            nav |= self.enabled_directional_nav(&scope, scope_info, false, FocusNavAction::empty());
1698        }
1699
1700        nav.set(FocusNavAction::ALT, self.in_alt_scope() || self.alt_scope().is_some());
1701
1702        nav
1703    }
1704}
1705
1706/// Focus metadata associated with a widget info tree.
1707#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
1708pub enum FocusInfo {
1709    /// The widget is not focusable.
1710    NotFocusable,
1711    /// The widget is focusable as a single item.
1712    Focusable {
1713        /// Tab index of the widget.
1714        tab_index: TabIndex,
1715        /// If the widget is skipped during directional navigation from outside.
1716        skip_directional: bool,
1717    },
1718    /// The widget is a focusable focus scope.
1719    FocusScope {
1720        /// Tab index of the widget.
1721        tab_index: TabIndex,
1722        /// If the widget is skipped during directional navigation from outside.
1723        skip_directional: bool,
1724        /// Tab navigation inside the focus scope.
1725        tab_nav: TabNav,
1726        /// Directional navigation inside the focus scope.
1727        directional_nav: DirectionalNav,
1728        /// Behavior of the widget when receiving direct focus.
1729        on_focus: FocusScopeOnFocus,
1730        /// If this scope is focused when the ALT key is pressed.
1731        alt: bool,
1732    },
1733}
1734
1735/// Behavior of a focus scope when it receives direct focus.
1736#[derive(Clone, Copy, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
1737pub enum FocusScopeOnFocus {
1738    /// Just focus the scope widget.
1739    Widget,
1740    /// Focus the first descendant considering the TAB index, if the scope has no descendants
1741    /// behaves like [`Widget`].
1742    ///
1743    /// Focus the last descendant if the focus is *reversing* in, e.g. in a SHIFT+TAB action.
1744    ///
1745    /// Behaves like [`Widget`] if the first(or last) descendant inner-bounds is not fully contained
1746    /// by the scope inner-bounds.
1747    ///
1748    /// [`Widget`]: Self::Widget
1749    FirstDescendant,
1750    /// Focus the descendant that was last focused before focus moved out of the scope. If the
1751    /// scope cannot return focus, behaves like [`FirstDescendant`].
1752    ///
1753    /// If the scope is the only child of a parent that is `TabNav::Cycle` and the focus just exited and
1754    /// returned in a cycle action, behaves like [`FirstDescendant`].
1755    ///
1756    /// Behaves like [`Widget`] if the first(or last) descendant inner-bounds is not fully contained
1757    /// by the scope inner-bounds.
1758    ///
1759    /// [`Widget`]: Self::Widget
1760    /// [`FirstDescendant`]: Self::FirstDescendant
1761    LastFocused,
1762
1763    /// Like [`FirstDescendant`], but also focus the descendant even if it's inner-bounds
1764    /// is not fully contained by the scope inner-bounds.
1765    ///
1766    /// The expectation is that the descendant is already visible or will be made visible when
1767    /// it receives focus, a scroll scope will scroll to make the descendant visible for example.
1768    ///
1769    /// [`FirstDescendant`]: Self::FirstDescendant
1770    FirstDescendantIgnoreBounds,
1771
1772    /// Like [`LastFocused`], but also focus the descendant even if it's inner-bounds
1773    /// is not fully contained by the scope inner-bounds.
1774    ///
1775    /// The expectation is that the descendant is already visible or will be made visible when
1776    /// it receives focus, a scroll scope will scroll to make the descendant visible for example.
1777    ///
1778    /// [`LastFocused`]: Self::LastFocused
1779    LastFocusedIgnoreBounds,
1780}
1781impl fmt::Debug for FocusScopeOnFocus {
1782    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1783        if f.alternate() {
1784            write!(f, "FocusScopeOnFocus::")?;
1785        }
1786        match self {
1787            FocusScopeOnFocus::Widget => write!(f, "Widget"),
1788            FocusScopeOnFocus::FirstDescendant => write!(f, "FirstDescendant"),
1789            FocusScopeOnFocus::LastFocused => write!(f, "LastFocused"),
1790            FocusScopeOnFocus::FirstDescendantIgnoreBounds => write!(f, "FirstDescendantIgnoreBounds"),
1791            FocusScopeOnFocus::LastFocusedIgnoreBounds => write!(f, "LastFocusedIgnoreBounds"),
1792        }
1793    }
1794}
1795impl Default for FocusScopeOnFocus {
1796    /// [`FirstDescendant`](Self::FirstDescendant)
1797    fn default() -> Self {
1798        FocusScopeOnFocus::FirstDescendant
1799    }
1800}
1801
1802impl FocusInfo {
1803    /// If is focusable or a focus scope.
1804    pub fn is_focusable(self) -> bool {
1805        !matches!(self, FocusInfo::NotFocusable)
1806    }
1807
1808    /// If is a focus scope.
1809    pub fn is_scope(self) -> bool {
1810        matches!(self, FocusInfo::FocusScope { .. })
1811    }
1812
1813    /// If is an ALT focus scope.
1814    pub fn is_alt_scope(self) -> bool {
1815        match self {
1816            FocusInfo::FocusScope { alt, .. } => alt,
1817            _ => false,
1818        }
1819    }
1820
1821    /// Tab navigation mode.
1822    ///
1823    /// | Variant                   | Returns                                 |
1824    /// |---------------------------|-----------------------------------------|
1825    /// | Focus scope               | Associated value, default is `Continue` |
1826    /// | Focusable                 | `TabNav::Continue`                      |
1827    /// | Not-Focusable             | `TabNav::None`                          |
1828    pub fn tab_nav(self) -> TabNav {
1829        match self {
1830            FocusInfo::FocusScope { tab_nav, .. } => tab_nav,
1831            FocusInfo::Focusable { .. } => TabNav::Continue,
1832            FocusInfo::NotFocusable => TabNav::None,
1833        }
1834    }
1835
1836    /// Directional navigation mode.
1837    ///
1838    /// | Variant                   | Returns                             |
1839    /// |---------------------------|-------------------------------------|
1840    /// | Focus scope               | Associated value, default is `None` |
1841    /// | Focusable                 | `DirectionalNav::Continue`          |
1842    /// | Not-Focusable             | `DirectionalNav::None`              |
1843    pub fn directional_nav(self) -> DirectionalNav {
1844        match self {
1845            FocusInfo::FocusScope { directional_nav, .. } => directional_nav,
1846            FocusInfo::Focusable { .. } => DirectionalNav::Continue,
1847            FocusInfo::NotFocusable => DirectionalNav::None,
1848        }
1849    }
1850
1851    /// Tab navigation index.
1852    ///
1853    /// | Variant           | Returns                                       |
1854    /// |-------------------|-----------------------------------------------|
1855    /// | Focusable & Scope | Associated value, default is `TabIndex::AUTO` |
1856    /// | Not-Focusable     | `TabIndex::SKIP`                              |
1857    pub fn tab_index(self) -> TabIndex {
1858        match self {
1859            FocusInfo::Focusable { tab_index, .. } => tab_index,
1860            FocusInfo::FocusScope { tab_index, .. } => tab_index,
1861            FocusInfo::NotFocusable => TabIndex::SKIP,
1862        }
1863    }
1864
1865    /// If directional navigation skips over this widget.
1866    ///
1867    /// | Variant           | Returns                                       |
1868    /// |-------------------|-----------------------------------------------|
1869    /// | Focusable & Scope | Associated value, default is `false`          |
1870    /// | Not-Focusable     | `true`                                        |
1871    pub fn skip_directional(self) -> bool {
1872        match self {
1873            FocusInfo::Focusable { skip_directional, .. } => skip_directional,
1874            FocusInfo::FocusScope { skip_directional, .. } => skip_directional,
1875            FocusInfo::NotFocusable => true,
1876        }
1877    }
1878
1879    /// Focus scope behavior when it receives direct focus.
1880    ///
1881    /// | Variant                   | Returns                                                           |
1882    /// |---------------------------|-------------------------------------------------------------------|
1883    /// | Scope                     | Associated value, default is `FocusScopeOnFocus::FirstDescendant` |
1884    /// | Focusable & Not-Focusable | `FocusScopeOnFocus::Self_`                                        |
1885    pub fn scope_on_focus(self) -> FocusScopeOnFocus {
1886        match self {
1887            FocusInfo::FocusScope { on_focus, .. } => on_focus,
1888            _ => FocusScopeOnFocus::Widget,
1889        }
1890    }
1891}
1892
1893static_id! {
1894    static ref FOCUS_INFO_ID: StateId<FocusInfoData>;
1895    static ref FOCUS_TREE_ID: StateId<FocusTreeData>;
1896}
1897
1898#[derive(Default)]
1899pub(super) struct FocusTreeData {
1900    alt_scopes: Mutex<IdSet<WidgetId>>,
1901}
1902impl FocusTreeData {
1903    pub(super) fn consolidate_alt_scopes(prev_tree: &WidgetInfoTree, new_tree: &WidgetInfoTree) {
1904        // reused widgets don't insert build-meta, so we add the previous ALT scopes and validate everything.
1905
1906        let prev = prev_tree
1907            .build_meta()
1908            .get(*FOCUS_TREE_ID)
1909            .map(|d| d.alt_scopes.lock().clone())
1910            .unwrap_or_default();
1911
1912        let mut alt_scopes = prev;
1913        if let Some(data) = new_tree.build_meta().get(*FOCUS_TREE_ID) {
1914            alt_scopes.extend(data.alt_scopes.lock().iter());
1915        }
1916
1917        alt_scopes.retain(|id| {
1918            if let Some(wgt) = new_tree.get(*id) {
1919                if let Some(info) = wgt.meta().get(*FOCUS_INFO_ID) {
1920                    if info.build().is_alt_scope() {
1921                        for parent in wgt.ancestors() {
1922                            if let Some(info) = parent.meta().get(*FOCUS_INFO_ID) {
1923                                if info.build().is_scope() {
1924                                    info.inner_alt.store(Some(*id), Relaxed);
1925                                    break;
1926                                }
1927                            }
1928                        }
1929
1930                        return true;
1931                    }
1932                }
1933            }
1934            false
1935        });
1936
1937        if let Some(data) = new_tree.build_meta().get(*FOCUS_TREE_ID) {
1938            *data.alt_scopes.lock() = alt_scopes;
1939        }
1940    }
1941}
1942
1943#[derive(Default, Debug)]
1944struct FocusInfoData {
1945    focusable: Option<bool>,
1946    scope: Option<bool>,
1947    alt_scope: bool,
1948    on_focus: FocusScopeOnFocus,
1949    tab_index: Option<TabIndex>,
1950    tab_nav: Option<TabNav>,
1951    directional_nav: Option<DirectionalNav>,
1952    skip_directional: Option<bool>,
1953
1954    inner_alt: Atomic<Option<WidgetId>>,
1955
1956    access_handler_registered: bool,
1957}
1958impl FocusInfoData {
1959    /// Build a [`FocusInfo`] from the collected configuration in `self`.
1960    ///
1961    /// See [`FocusInfoBuilder`] for a review of the algorithm.
1962    pub fn build(&self) -> FocusInfo {
1963        match (self.focusable, self.scope, self.tab_index, self.tab_nav, self.directional_nav) {
1964            // Set as not focusable.
1965            (Some(false), _, _, _, _) => FocusInfo::NotFocusable,
1966
1967            // Set as focus scope and not set as not focusable
1968            // or set tab navigation and did not set as not focus scope
1969            // or set directional navigation and did not set as not focus scope.
1970            (_, Some(true), idx, tab, dir) | (_, None, idx, tab @ Some(_), dir) | (_, None, idx, tab, dir @ Some(_)) => {
1971                FocusInfo::FocusScope {
1972                    tab_index: idx.unwrap_or(TabIndex::AUTO),
1973                    skip_directional: self.skip_directional.unwrap_or_default(),
1974                    tab_nav: tab.unwrap_or(TabNav::Continue),
1975                    directional_nav: dir.unwrap_or(DirectionalNav::Continue),
1976                    alt: self.alt_scope,
1977                    on_focus: self.on_focus,
1978                }
1979            }
1980
1981            // Set as focusable and was not focus scope
1982            // or set tab index and was not focus scope and did not set as not focusable.
1983            (Some(true), _, idx, _, _) | (_, _, idx @ Some(_), _, _) => FocusInfo::Focusable {
1984                tab_index: idx.unwrap_or(TabIndex::AUTO),
1985                skip_directional: self.skip_directional.unwrap_or_default(),
1986            },
1987
1988            _ => FocusInfo::NotFocusable,
1989        }
1990    }
1991}
1992
1993/// Builder for [`FocusInfo`] accessible in a [`WidgetInfoBuilder`].
1994///
1995/// There are multiple focusable metadata that can be set on a widget. These rules define how the focusable
1996/// state of a widget is derived from the focusable metadata.
1997///
1998/// ### Rules
1999///
2000/// The widget is not focusable nor a focus scope if it set [`focusable`](Self::focusable) to `false`.
2001///
2002/// The widget is a *focus scope* if it set [`scope`](Self::scope) to `true` **or** if it set [`tab_nav`](Self::tab_nav) or
2003/// [`directional_nav`](Self::directional_nav) and did not set [`scope`](Self::scope) to `false`.
2004///
2005/// The widget is *focusable* if it set [`focusable`](Self::focusable) to `true` **or** if it set the [`tab_index`](Self::tab_index).
2006///
2007/// The widget is a *focus scope* if it sets [`nested_window`](NestedWindowWidgetInfoExt::nested_window), but the focus will always move inside
2008/// the nested window.
2009///
2010/// The widget is not focusable if it did not set any of the members mentioned.
2011///
2012/// ##### Tab Index
2013///
2014/// If the [`tab_index`](Self::tab_index) was not set but the widget is focusable or a focus scope, the [`TabIndex::AUTO`]
2015/// is used for the widget.
2016///
2017/// ##### Skip Directional
2018///
2019/// If the [`skip_directional`](Self::skip_directional) was not set but the widget is focusable or a focus scope, it is
2020/// set to `false` for the widget.
2021///
2022/// ##### Focus Scope
2023///
2024/// If the widget is a focus scope, it is configured using [`alt_scope`](Self::alt_scope) and [`on_focus`](Self::on_focus).
2025/// If the widget is not a scope these members are ignored.
2026///
2027/// ##### Tab Navigation
2028///
2029/// If [`tab_nav`](Self::tab_nav) is not set but the widget is a focus scope, [`TabNav::Continue`] is used.
2030///
2031/// ##### Directional Navigation
2032///
2033/// If [`directional_nav`](Self::directional_nav) is not set but the widget is a focus scope, [`DirectionalNav::Continue`] is used.
2034///
2035/// [`WidgetInfoBuilder`]: zng_app::widget::info::WidgetInfoBuilder
2036/// [`new`]: Self::new
2037pub struct FocusInfoBuilder<'a>(&'a mut WidgetInfoBuilder);
2038impl<'a> FocusInfoBuilder<'a> {
2039    /// New the builder.
2040    pub fn new(builder: &'a mut WidgetInfoBuilder) -> Self {
2041        let mut r = Self(builder);
2042        r.with_tree_data(|_| {}); // ensure that build meta is allocated.
2043        r
2044    }
2045
2046    fn with_data<R>(&mut self, visitor: impl FnOnce(&mut FocusInfoData) -> R) -> R {
2047        let mut access = self.0.access().is_some();
2048
2049        let r = self.0.with_meta(|m| {
2050            let data = m.into_entry(*FOCUS_INFO_ID).or_default();
2051
2052            if access {
2053                access = !std::mem::replace(&mut data.access_handler_registered, true);
2054            }
2055
2056            visitor(data)
2057        });
2058
2059        if access {
2060            // access info required and not registered
2061            self.0.access().unwrap().on_access_build(|args| {
2062                if args.widget.info().clone().into_focusable(true, false).is_some() {
2063                    args.node.commands.push(zng_view_api::access::AccessCmdName::Focus);
2064                }
2065            });
2066        }
2067
2068        r
2069    }
2070
2071    fn with_tree_data<R>(&mut self, visitor: impl FnOnce(&mut FocusTreeData) -> R) -> R {
2072        self.0.with_build_meta(|m| visitor(m.into_entry(*FOCUS_TREE_ID).or_default()))
2073    }
2074
2075    /// If the widget is definitely focusable or not.
2076    pub fn focusable(&mut self, is_focusable: bool) -> &mut Self {
2077        self.with_data(|data| {
2078            data.focusable = Some(is_focusable);
2079        });
2080        self
2081    }
2082
2083    /// Sets [`focusable`], only if it was not already set.
2084    ///
2085    /// [`focusable`]: Self::focusable
2086    pub fn focusable_passive(&mut self, is_focusable: bool) -> &mut Self {
2087        self.with_data(|data| {
2088            if data.focusable.is_none() {
2089                data.focusable = Some(is_focusable);
2090            }
2091        });
2092        self
2093    }
2094
2095    /// If the widget is definitely a focus scope or not.
2096    pub fn scope(&mut self, is_focus_scope: bool) -> &mut Self {
2097        self.with_data(|data| {
2098            data.scope = Some(is_focus_scope);
2099        });
2100        self
2101    }
2102
2103    /// If the widget is definitely an ALT focus scope or not.
2104    ///
2105    /// If `true` this also sets `TabIndex::SKIP`, `skip_directional_nav`, `TabNav::Cycle` and `DirectionalNav::Cycle` as default.
2106    pub fn alt_scope(&mut self, is_alt_focus_scope: bool) -> &mut Self {
2107        self.with_data(|data| {
2108            data.alt_scope = is_alt_focus_scope;
2109            if is_alt_focus_scope {
2110                data.scope = Some(true);
2111
2112                if data.tab_index.is_none() {
2113                    data.tab_index = Some(TabIndex::SKIP);
2114                }
2115                if data.tab_nav.is_none() {
2116                    data.tab_nav = Some(TabNav::Cycle);
2117                }
2118                if data.directional_nav.is_none() {
2119                    data.directional_nav = Some(DirectionalNav::Cycle);
2120                }
2121                if data.skip_directional.is_none() {
2122                    data.skip_directional = Some(true);
2123                }
2124            }
2125        });
2126        if is_alt_focus_scope {
2127            let wgt_id = self.0.widget_id();
2128            self.with_tree_data(|d| d.alt_scopes.lock().insert(wgt_id));
2129        }
2130        self
2131    }
2132
2133    /// When the widget is a focus scope, its behavior on receiving direct focus.
2134    pub fn on_focus(&mut self, as_focus_scope_on_focus: FocusScopeOnFocus) -> &mut Self {
2135        self.with_data(|data| {
2136            data.on_focus = as_focus_scope_on_focus;
2137        });
2138        self
2139    }
2140
2141    /// Widget TAB index.
2142    pub fn tab_index(&mut self, tab_index: TabIndex) -> &mut Self {
2143        self.with_data(|data| {
2144            data.tab_index = Some(tab_index);
2145        });
2146        self
2147    }
2148
2149    /// TAB navigation within this widget, if set turns the widget into a focus scope.
2150    pub fn tab_nav(&mut self, scope_tab_nav: TabNav) -> &mut Self {
2151        self.with_data(|data| {
2152            data.tab_nav = Some(scope_tab_nav);
2153        });
2154        self
2155    }
2156
2157    /// Directional navigation within this widget, if set turns the widget into a focus scope.
2158    pub fn directional_nav(&mut self, scope_directional_nav: DirectionalNav) -> &mut Self {
2159        self.with_data(|data| {
2160            data.directional_nav = Some(scope_directional_nav);
2161        });
2162        self
2163    }
2164    /// If directional navigation skips over this widget.
2165    pub fn skip_directional(&mut self, skip: bool) -> &mut Self {
2166        self.with_data(|data| {
2167            data.skip_directional = Some(skip);
2168        });
2169        self
2170    }
2171}