tessera_ui/
focus.rs

1//! Focus ownership, traversal, and restoration for interactive UI.
2//!
3//! ## Usage
4//!
5//! Register focus targets, scopes, and traversal rules for keyboard and IME
6//! input.
7
8use std::{
9    ptr::NonNull,
10    sync::atomic::{AtomicU64, Ordering},
11};
12
13use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
14
15use crate::{
16    NodeId, PxRect,
17    component_tree::{ComponentNodeMetaDatas, ComponentNodeTree},
18    execution_context::{with_execution_context, with_execution_context_mut},
19    prop::CallbackWith,
20    px::PxSize,
21    runtime::{
22        TesseraRuntime, focus_read_subscribers, focus_requester_read_subscribers,
23        has_persistent_focus_handle, record_component_invalidation_for_instance_key,
24        track_focus_read_dependency, track_focus_requester_read_dependency,
25    },
26};
27
28static NEXT_FOCUS_TARGET_ID: AtomicU64 = AtomicU64::new(1);
29static NEXT_FOCUS_REQUESTER_ID: AtomicU64 = AtomicU64::new(1);
30const ROOT_SCOPE_ID: FocusHandleId = 0;
31
32pub(crate) type FocusHandleId = u64;
33pub(crate) type FocusRequesterId = u64;
34
35fn next_focus_handle_id() -> FocusHandleId {
36    NEXT_FOCUS_TARGET_ID.fetch_add(1, Ordering::Relaxed)
37}
38
39fn next_focus_requester_id() -> FocusRequesterId {
40    NEXT_FOCUS_REQUESTER_ID.fetch_add(1, Ordering::Relaxed)
41}
42
43fn with_bound_focus_owner<R>(f: impl FnOnce(&FocusOwner) -> R) -> Option<R> {
44    let ptr = with_execution_context(|context| context.current_focus_owner_stack.last().copied())?;
45    // SAFETY: The binding guard only pushes a pointer that remains valid for
46    // the duration of the handler dispatch on the current thread.
47    Some(unsafe { f(ptr.as_ref()) })
48}
49
50fn with_bound_focus_owner_mut<R>(f: impl FnOnce(&mut FocusOwner) -> R) -> Option<R> {
51    let ptr = with_execution_context(|context| context.current_focus_owner_stack.last().copied())?;
52    // SAFETY: The binding guard only pushes a pointer that remains valid for
53    // the duration of the handler dispatch on the current thread.
54    Some(unsafe { f(&mut *ptr.as_ptr()) })
55}
56
57fn with_focus_owner<R>(f: impl FnOnce(&FocusOwner) -> R) -> R {
58    let mut f = Some(f);
59    if let Some(result) = with_bound_focus_owner(|owner| {
60        f.take().expect("focus owner callback should run once")(owner)
61    }) {
62        return result;
63    }
64    TesseraRuntime::with(|runtime| {
65        f.take().expect("focus owner callback should run once")(
66            runtime.component_tree.focus_owner(),
67        )
68    })
69}
70
71fn with_focus_owner_mut<R>(f: impl FnOnce(&mut FocusOwner) -> R) -> R {
72    let mut f = Some(f);
73    if let Some(result) = with_bound_focus_owner_mut(|owner| {
74        f.take().expect("focus owner callback should run once")(owner)
75    }) {
76        return result;
77    }
78    let result = TesseraRuntime::with_mut(|runtime| {
79        f.take().expect("focus owner callback should run once")(
80            runtime.component_tree.focus_owner_mut(),
81        )
82    });
83    flush_pending_focus_callbacks();
84    result
85}
86
87pub(crate) struct FocusOwnerBindingGuard {
88    active: bool,
89}
90
91impl Drop for FocusOwnerBindingGuard {
92    fn drop(&mut self) {
93        if !self.active {
94            return;
95        }
96        with_execution_context_mut(|context| {
97            let popped = context.current_focus_owner_stack.pop();
98            debug_assert!(popped.is_some(), "focus owner binding stack underflow");
99        });
100        self.active = false;
101    }
102}
103
104pub(crate) fn bind_focus_owner(owner: &mut FocusOwner) -> FocusOwnerBindingGuard {
105    with_execution_context_mut(|context| {
106        context.current_focus_owner_stack.push(NonNull::from(owner));
107    });
108    FocusOwnerBindingGuard { active: true }
109}
110
111/// Focus state for a registered focus node.
112///
113/// Use this to render focus-dependent UI and distinguish between the primary
114/// focused target and its focused ancestors.
115///
116/// # Examples
117///
118/// ```
119/// use tessera_ui::FocusState;
120///
121/// assert!(!FocusState::Inactive.has_focus());
122/// assert!(FocusState::ActiveParent.has_focus());
123/// assert!(FocusState::Active.is_focused());
124/// assert!(FocusState::Captured.is_captured());
125/// ```
126#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
127pub enum FocusState {
128    /// The node is not participating in the active focus path.
129    #[default]
130    Inactive,
131    /// A descendant of this node currently holds focus.
132    ActiveParent,
133    /// This node currently holds focus.
134    Active,
135    /// This node currently holds captured focus.
136    Captured,
137}
138
139impl FocusState {
140    /// Returns `true` when this node is in the active focus path.
141    pub fn has_focus(self) -> bool {
142        !matches!(self, Self::Inactive)
143    }
144
145    /// Returns `true` when this node is the primary focused node.
146    pub fn is_focused(self) -> bool {
147        matches!(self, Self::Active | Self::Captured)
148    }
149
150    /// Returns `true` when this node has captured focus.
151    pub fn is_captured(self) -> bool {
152        matches!(self, Self::Captured)
153    }
154}
155
156/// Focus traversal direction for owner-level movement.
157///
158/// These directions are used by [`FocusManager`], [`FocusScopeNode`], and
159/// [`FocusGroupNode`] when keyboard or programmatic traversal moves focus.
160#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
161pub enum FocusDirection {
162    /// Move to the next focusable target in traversal order.
163    Next,
164    /// Move to the previous focusable target in traversal order.
165    Previous,
166    /// Move focus upward.
167    Up,
168    /// Move focus downward.
169    Down,
170    /// Move focus leftward.
171    Left,
172    /// Move focus rightward.
173    Right,
174    /// Enter a nested focus group or scope.
175    Enter,
176    /// Exit the current focus group or scope.
177    Exit,
178}
179
180/// Strategy used by a focus traversal policy.
181#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
182pub enum FocusTraversalStrategy {
183    /// Traverse in declaration order using previous/next semantics.
184    Linear,
185    /// Traverse horizontally using left/right arrows.
186    Horizontal,
187    /// Traverse vertically using up/down arrows.
188    Vertical,
189    /// Traverse spatially using candidate rectangles.
190    Spatial,
191}
192
193/// Policy applied by a focus scope or group when traversal starts inside it.
194///
195/// Use policies to describe how a container handles directional keys and
196/// whether `Tab` navigation should stay inside the container.
197///
198/// # Examples
199///
200/// ```
201/// use tessera_ui::{FocusTraversalPolicy, FocusTraversalStrategy};
202///
203/// let policy = FocusTraversalPolicy::vertical()
204///     .wrap(true)
205///     .tab_navigation(true);
206///
207/// assert_eq!(policy.strategy, FocusTraversalStrategy::Vertical);
208/// assert!(policy.wrap);
209/// assert!(policy.tab_navigation);
210/// ```
211#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
212pub struct FocusTraversalPolicy {
213    /// Traversal strategy used for arrow-key navigation.
214    pub strategy: FocusTraversalStrategy,
215    /// Whether traversal wraps when it reaches either end of the group.
216    pub wrap: bool,
217    /// Whether `Tab` and `Shift+Tab` should be handled by this policy.
218    pub tab_navigation: bool,
219}
220
221impl FocusTraversalPolicy {
222    /// Creates a new traversal policy for the given strategy.
223    pub const fn new(strategy: FocusTraversalStrategy) -> Self {
224        Self {
225            strategy,
226            wrap: false,
227            tab_navigation: false,
228        }
229    }
230
231    /// Creates a linear traversal policy.
232    pub const fn linear() -> Self {
233        Self::new(FocusTraversalStrategy::Linear)
234    }
235
236    /// Creates a horizontal traversal policy.
237    pub const fn horizontal() -> Self {
238        Self::new(FocusTraversalStrategy::Horizontal)
239    }
240
241    /// Creates a vertical traversal policy.
242    pub const fn vertical() -> Self {
243        Self::new(FocusTraversalStrategy::Vertical)
244    }
245
246    /// Creates a spatial traversal policy.
247    pub const fn spatial() -> Self {
248        Self::new(FocusTraversalStrategy::Spatial)
249    }
250
251    /// Sets whether traversal wraps when it reaches either end.
252    pub const fn wrap(mut self, wrap: bool) -> Self {
253        self.wrap = wrap;
254        self
255    }
256
257    /// Sets whether `Tab` and `Shift+Tab` should be handled inside this
258    /// policy owner.
259    pub const fn tab_navigation(mut self, tab_navigation: bool) -> Self {
260        self.tab_navigation = tab_navigation;
261        self
262    }
263
264    fn scoped_direction(self, direction: FocusDirection) -> Option<FocusDirection> {
265        if self.tab_navigation {
266            match direction {
267                FocusDirection::Next | FocusDirection::Previous => return Some(direction),
268                _ => {}
269            }
270        }
271
272        match self.strategy {
273            FocusTraversalStrategy::Linear => match direction {
274                FocusDirection::Left | FocusDirection::Up => Some(FocusDirection::Previous),
275                FocusDirection::Right | FocusDirection::Down => Some(FocusDirection::Next),
276                _ => None,
277            },
278            FocusTraversalStrategy::Horizontal => match direction {
279                FocusDirection::Left => Some(FocusDirection::Previous),
280                FocusDirection::Right => Some(FocusDirection::Next),
281                _ => None,
282            },
283            FocusTraversalStrategy::Vertical => match direction {
284                FocusDirection::Up => Some(FocusDirection::Previous),
285                FocusDirection::Down => Some(FocusDirection::Next),
286                _ => None,
287            },
288            FocusTraversalStrategy::Spatial => match direction {
289                FocusDirection::Left
290                | FocusDirection::Right
291                | FocusDirection::Up
292                | FocusDirection::Down => Some(direction),
293                _ => None,
294            },
295        }
296    }
297}
298
299/// A request for scroll containers to reveal a focused rectangle.
300#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
301pub struct FocusRevealRequest {
302    /// The absolute rectangle of the focused target.
303    pub target_rect: PxRect,
304    /// The absolute visible viewport of the current reveal container.
305    pub viewport_rect: PxRect,
306}
307
308impl FocusRevealRequest {
309    /// Creates a new focus reveal request.
310    pub(crate) const fn new(target_rect: PxRect, viewport_rect: PxRect) -> Self {
311        Self {
312            target_rect,
313            viewport_rect,
314        }
315    }
316}
317
318/// Focus properties used when registering a focus node on the current
319/// component.
320///
321/// Use properties to enable or disable focus participation and to declare
322/// explicit traversal neighbors for complex layouts.
323///
324/// # Examples
325///
326/// ```
327/// use tessera_ui::{FocusProperties, FocusRequester};
328///
329/// let next = FocusRequester::new();
330/// let right = FocusRequester::new();
331/// let props = FocusProperties::new()
332///     .can_focus(true)
333///     .skip_traversal(false)
334///     .next(next)
335///     .right(right);
336///
337/// assert_eq!(props.next, Some(next));
338/// assert_eq!(props.right, Some(right));
339/// assert!(props.can_focus);
340/// assert!(!props.skip_traversal);
341/// ```
342#[derive(Clone, Copy, Debug, PartialEq, Eq)]
343pub struct FocusProperties {
344    /// Whether this node may receive focus.
345    pub can_focus: bool,
346    /// Whether this node may be the target of focus requests.
347    pub can_request_focus: bool,
348    /// Whether traversal should skip this node.
349    pub skip_traversal: bool,
350    /// Explicit target for `Next` traversal.
351    pub next: Option<FocusRequester>,
352    /// Explicit target for `Previous` traversal.
353    pub previous: Option<FocusRequester>,
354    /// Explicit target for `Up` traversal.
355    pub up: Option<FocusRequester>,
356    /// Explicit target for `Down` traversal.
357    pub down: Option<FocusRequester>,
358    /// Explicit target for `Left` traversal.
359    pub left: Option<FocusRequester>,
360    /// Explicit target for `Right` traversal.
361    pub right: Option<FocusRequester>,
362    /// Explicit target when entering a nested focus region.
363    pub enter: Option<FocusRequester>,
364    /// Explicit target when exiting a focus region.
365    pub exit: Option<FocusRequester>,
366}
367
368impl FocusProperties {
369    /// Creates the default focus properties for focus targets.
370    pub fn new() -> Self {
371        Self::default()
372    }
373
374    /// Sets whether this node may receive focus.
375    pub fn can_focus(mut self, can_focus: bool) -> Self {
376        self.can_focus = can_focus;
377        self
378    }
379
380    /// Sets whether this node may be the target of focus requests.
381    pub fn can_request_focus(mut self, can_request_focus: bool) -> Self {
382        self.can_request_focus = can_request_focus;
383        self
384    }
385
386    /// Sets whether traversal should skip this node.
387    pub fn skip_traversal(mut self, skip_traversal: bool) -> Self {
388        self.skip_traversal = skip_traversal;
389        self
390    }
391
392    /// Sets the explicit requester for `Next` traversal.
393    pub fn next(mut self, requester: FocusRequester) -> Self {
394        self.next = Some(requester);
395        self
396    }
397
398    /// Sets the explicit requester for `Previous` traversal.
399    pub fn previous(mut self, requester: FocusRequester) -> Self {
400        self.previous = Some(requester);
401        self
402    }
403
404    /// Sets the explicit requester for `Up` traversal.
405    pub fn up(mut self, requester: FocusRequester) -> Self {
406        self.up = Some(requester);
407        self
408    }
409
410    /// Sets the explicit requester for `Down` traversal.
411    pub fn down(mut self, requester: FocusRequester) -> Self {
412        self.down = Some(requester);
413        self
414    }
415
416    /// Sets the explicit requester for `Left` traversal.
417    pub fn left(mut self, requester: FocusRequester) -> Self {
418        self.left = Some(requester);
419        self
420    }
421
422    /// Sets the explicit requester for `Right` traversal.
423    pub fn right(mut self, requester: FocusRequester) -> Self {
424        self.right = Some(requester);
425        self
426    }
427
428    /// Sets the explicit requester used when moving focus into a group.
429    pub fn enter(mut self, requester: FocusRequester) -> Self {
430        self.enter = Some(requester);
431        self
432    }
433
434    /// Sets the explicit requester used when moving focus out of a group.
435    pub fn exit(mut self, requester: FocusRequester) -> Self {
436        self.exit = Some(requester);
437        self
438    }
439}
440
441impl Default for FocusProperties {
442    fn default() -> Self {
443        Self {
444            can_focus: true,
445            can_request_focus: true,
446            skip_traversal: false,
447            next: None,
448            previous: None,
449            up: None,
450            down: None,
451            left: None,
452            right: None,
453            enter: None,
454            exit: None,
455        }
456    }
457}
458
459#[derive(Clone, Copy, Debug, PartialEq, Eq)]
460pub(crate) enum FocusRegistrationKind {
461    Target,
462    Scope,
463    Group,
464}
465
466#[derive(Clone, Copy, Debug, PartialEq, Eq)]
467pub(crate) struct FocusRegistration {
468    pub(crate) id: FocusHandleId,
469    pub(crate) kind: FocusRegistrationKind,
470    pub(crate) properties: FocusProperties,
471}
472
473impl FocusRegistration {
474    pub(crate) fn target(node: FocusNode) -> Self {
475        Self {
476            id: node.id,
477            kind: FocusRegistrationKind::Target,
478            properties: FocusProperties::default(),
479        }
480    }
481
482    pub(crate) fn scope(scope: FocusScopeNode) -> Self {
483        Self {
484            id: scope.id,
485            kind: FocusRegistrationKind::Scope,
486            properties: FocusProperties::default().can_focus(false),
487        }
488    }
489
490    pub(crate) fn group(group: FocusGroupNode) -> Self {
491        Self {
492            id: group.id,
493            kind: FocusRegistrationKind::Group,
494            properties: FocusProperties::default()
495                .can_focus(false)
496                .can_request_focus(false),
497        }
498    }
499}
500
501/// Imperative handle used to request focus for a registered target.
502///
503/// Requesters are stable handles that can be stored in component state and
504/// passed across component boundaries without exposing the underlying focus
505/// tree.
506///
507/// # Examples
508///
509/// ```
510/// use tessera_ui::FocusRequester;
511///
512/// let first = FocusRequester::new();
513/// let second = FocusRequester::new();
514/// assert_ne!(first, second);
515/// ```
516#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
517pub struct FocusRequester {
518    id: FocusRequesterId,
519}
520
521impl FocusRequester {
522    /// Creates a new focus requester.
523    pub fn new() -> Self {
524        Self {
525            id: next_focus_requester_id(),
526        }
527    }
528
529    /// Requests focus for the bound target.
530    pub fn request_focus(&self) {
531        with_focus_owner_mut(|owner| owner.request_focus_by_requester(self.id));
532    }
533
534    /// Clears focus from the bound target if it currently holds it.
535    pub fn clear_focus(&self) {
536        with_focus_owner_mut(|owner| owner.clear_focus_by_requester(self.id));
537    }
538
539    /// Alias for [`Self::clear_focus`].
540    pub fn unfocus(&self) {
541        self.clear_focus();
542    }
543
544    /// Captures focus on this node, preventing focus from moving elsewhere
545    /// until released or force-cleared.
546    pub fn capture_focus(&self) {
547        with_focus_owner_mut(|owner| owner.capture_focus_by_requester(self.id));
548    }
549
550    /// Releases captured focus from this node.
551    pub fn free_focus(&self) {
552        with_focus_owner_mut(|owner| owner.free_focus_by_requester(self.id));
553    }
554
555    /// Returns the current focus state for the bound target.
556    pub fn state(&self) -> FocusState {
557        track_focus_requester_read_dependency(self.id);
558        with_focus_owner(|owner| owner.state_of_requester(self.id))
559    }
560
561    /// Returns `true` when this node is in the active focus path.
562    pub fn has_focus(&self) -> bool {
563        self.state().has_focus()
564    }
565
566    /// Returns `true` when this node is the primary focused node.
567    pub fn is_focused(&self) -> bool {
568        self.state().is_focused()
569    }
570
571    /// Returns `true` when this node has captured focus.
572    pub fn is_captured(&self) -> bool {
573        self.state().is_captured()
574    }
575
576    pub(crate) fn requester_id(self) -> FocusRequesterId {
577        self.id
578    }
579}
580
581impl Default for FocusRequester {
582    fn default() -> Self {
583        Self::new()
584    }
585}
586
587/// Persistent focus target handle.
588///
589/// This is the low-level target identity used by focus modifiers. Most code
590/// should prefer [`FocusRequester`] and [`crate::modifier::FocusModifierExt`].
591#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
592pub(crate) struct FocusNode {
593    id: FocusHandleId,
594}
595
596impl FocusNode {
597    pub(crate) fn new() -> Self {
598        Self {
599            id: next_focus_handle_id(),
600        }
601    }
602
603    pub(crate) fn handle_id(self) -> FocusHandleId {
604        self.id
605    }
606
607    pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
608        Self { id }
609    }
610}
611
612impl Default for FocusNode {
613    fn default() -> Self {
614        Self::new()
615    }
616}
617
618/// Persistent focus scope handle.
619///
620/// Scopes own restore behavior and provide imperative traversal within a
621/// subtree.
622///
623/// # Examples
624///
625/// ```
626/// use tessera_ui::FocusScopeNode;
627///
628/// let first = FocusScopeNode::new();
629/// let second = FocusScopeNode::new();
630/// assert_ne!(first, second);
631/// ```
632#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
633pub struct FocusScopeNode {
634    id: FocusHandleId,
635}
636
637impl FocusScopeNode {
638    /// Creates a new persistent focus scope handle.
639    pub fn new() -> Self {
640        Self {
641            id: next_focus_handle_id(),
642        }
643    }
644
645    pub(crate) fn handle_id(self) -> FocusHandleId {
646        self.id
647    }
648
649    pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
650        Self { id }
651    }
652
653    /// Requests focus within this scope, restoring the last focused descendant
654    /// when possible.
655    pub fn request_focus(&self) {
656        with_focus_owner_mut(|owner| owner.request_focus(self.id));
657    }
658
659    /// Clears focus from this scope.
660    pub fn clear_focus(&self) {
661        with_focus_owner_mut(|owner| owner.clear_focus(self.id));
662    }
663
664    /// Restores focus to the last focused descendant of this scope.
665    pub fn restore_focus(&self) {
666        with_focus_owner_mut(|owner| owner.restore_focus(self.id));
667    }
668
669    /// Moves focus to another focusable descendant inside this scope.
670    pub fn move_focus(&self, direction: FocusDirection) -> bool {
671        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, false))
672    }
673
674    /// Cycles focus inside this scope, wrapping when traversal reaches an end.
675    pub fn cycle_focus(&self, direction: FocusDirection) -> bool {
676        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, true))
677    }
678
679    /// Returns the current focus state for this scope.
680    pub fn state(&self) -> FocusState {
681        track_focus_read_dependency(self.id);
682        with_focus_owner(|owner| owner.state_of(self.id))
683    }
684
685    /// Returns `true` when this scope participates in the active focus path.
686    pub fn has_focus(&self) -> bool {
687        self.state().has_focus()
688    }
689
690    /// Returns `true` when this scope itself is the primary focused node.
691    pub fn is_focused(&self) -> bool {
692        self.state().is_focused()
693    }
694}
695
696impl Default for FocusScopeNode {
697    fn default() -> Self {
698        Self::new()
699    }
700}
701
702/// Persistent traversal-only focus group handle.
703///
704/// Groups define traversal boundaries without taking on scope restore
705/// semantics.
706///
707/// # Examples
708///
709/// ```
710/// use tessera_ui::FocusGroupNode;
711///
712/// let first = FocusGroupNode::new();
713/// let second = FocusGroupNode::new();
714/// assert_ne!(first, second);
715/// ```
716#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
717pub struct FocusGroupNode {
718    id: FocusHandleId,
719}
720
721impl FocusGroupNode {
722    /// Creates a new persistent focus group handle.
723    pub fn new() -> Self {
724        Self {
725            id: next_focus_handle_id(),
726        }
727    }
728
729    pub(crate) fn handle_id(self) -> FocusHandleId {
730        self.id
731    }
732
733    pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
734        Self { id }
735    }
736
737    /// Moves focus to another focusable descendant inside this group.
738    pub fn move_focus(&self, direction: FocusDirection) -> bool {
739        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, false))
740    }
741
742    /// Cycles focus inside this group, wrapping when traversal reaches an end.
743    pub fn cycle_focus(&self, direction: FocusDirection) -> bool {
744        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, true))
745    }
746
747    /// Returns the current focus state for this group.
748    pub fn state(&self) -> FocusState {
749        track_focus_read_dependency(self.id);
750        with_focus_owner(|owner| owner.state_of(self.id))
751    }
752
753    /// Returns `true` when this group participates in the active focus path.
754    pub fn has_focus(&self) -> bool {
755        self.state().has_focus()
756    }
757
758    /// Returns `true` when this group itself is the primary focused node.
759    pub fn is_focused(&self) -> bool {
760        self.state().is_focused()
761    }
762}
763
764impl Default for FocusGroupNode {
765    fn default() -> Self {
766        Self::new()
767    }
768}
769
770/// Owner-scoped focus manager for traversal and forced clear operations.
771///
772/// Use the focus manager to trigger application-level traversal without
773/// storing a specific scope or requester.
774///
775/// # Examples
776///
777/// ```
778/// use tessera_ui::FocusManager;
779///
780/// let _manager = FocusManager::current();
781/// ```
782#[derive(Clone, Copy, Debug, Default)]
783pub struct FocusManager;
784
785impl FocusManager {
786    /// Returns the focus manager for the current component tree.
787    pub fn current() -> Self {
788        Self
789    }
790
791    /// Clears the current focus. Set `force` to `true` to break captured focus.
792    pub fn clear_focus(self, force: bool) {
793        with_focus_owner_mut(|owner| {
794            owner.clear_focus_global(force);
795        });
796    }
797
798    /// Moves focus in the requested direction.
799    pub fn move_focus(self, direction: FocusDirection) -> bool {
800        with_focus_owner_mut(|owner| owner.move_focus(direction))
801    }
802}
803
804#[derive(Clone, Copy, Debug)]
805struct FocusAttachment {
806    host_instance_key: u64,
807    live_node_id: Option<NodeId>,
808    focus_rect: Option<PxRect>,
809    traversal_order: Option<u64>,
810    parent: FocusHandleId,
811    scope_parent: FocusHandleId,
812}
813
814impl FocusAttachment {
815    fn root_scope() -> Self {
816        Self {
817            host_instance_key: 0,
818            live_node_id: None,
819            focus_rect: None,
820            traversal_order: None,
821            parent: ROOT_SCOPE_ID,
822            scope_parent: ROOT_SCOPE_ID,
823        }
824    }
825}
826
827#[derive(Clone, Copy, Debug)]
828struct FocusTreeNode {
829    kind: FocusRegistrationKind,
830    attachment: Option<FocusAttachment>,
831    last_parent: FocusHandleId,
832    last_scope_parent: FocusHandleId,
833    props: FocusProperties,
834    traversal_policy: Option<FocusTraversalPolicy>,
835    state: FocusState,
836    last_focused_descendant: Option<FocusHandleId>,
837    restorer_fallback: Option<FocusRequesterId>,
838}
839
840impl FocusTreeNode {
841    fn new_root_scope() -> Self {
842        Self {
843            kind: FocusRegistrationKind::Scope,
844            attachment: Some(FocusAttachment::root_scope()),
845            last_parent: ROOT_SCOPE_ID,
846            last_scope_parent: ROOT_SCOPE_ID,
847            props: FocusProperties::default()
848                .can_focus(false)
849                .can_request_focus(false)
850                .skip_traversal(true),
851            traversal_policy: None,
852            state: FocusState::Inactive,
853            last_focused_descendant: None,
854            restorer_fallback: None,
855        }
856    }
857
858    fn new(kind: FocusRegistrationKind) -> Self {
859        Self {
860            kind,
861            attachment: None,
862            last_parent: ROOT_SCOPE_ID,
863            last_scope_parent: ROOT_SCOPE_ID,
864            props: FocusProperties::default(),
865            traversal_policy: None,
866            state: FocusState::Inactive,
867            last_focused_descendant: None,
868            restorer_fallback: None,
869        }
870    }
871
872    fn is_attached(&self) -> bool {
873        self.attachment.is_some()
874    }
875}
876
877#[derive(Clone)]
878pub(crate) struct PendingFocusCallbackInvocation {
879    callback: CallbackWith<FocusState>,
880    state: FocusState,
881}
882
883impl PendingFocusCallbackInvocation {
884    pub(crate) fn new(callback: CallbackWith<FocusState>, state: FocusState) -> Self {
885        Self { callback, state }
886    }
887
888    pub(crate) fn invoke(self) {
889        self.callback.call(self.state);
890    }
891}
892
893#[derive(Clone, Copy, Debug)]
894pub(crate) struct FocusNotification {
895    pub handle_id: FocusHandleId,
896    pub state: FocusState,
897    pub changed: bool,
898}
899
900#[derive(Clone, Copy, Debug)]
901enum FocusCommand {
902    Request(FocusHandleId),
903    Clear(FocusHandleId),
904    Capture(FocusHandleId),
905    Free(FocusHandleId),
906    Restore(FocusHandleId),
907}
908
909/// Per-component-tree focus owner.
910#[derive(Default)]
911pub(crate) struct FocusOwner {
912    nodes: HashMap<FocusHandleId, FocusTreeNode>,
913    children_by_parent: HashMap<FocusHandleId, Vec<FocusHandleId>>,
914    requester_bindings: HashMap<FocusRequesterId, FocusHandleId>,
915    requesters_by_handle: HashMap<FocusHandleId, Vec<FocusRequesterId>>,
916    active: Option<FocusHandleId>,
917    captured: Option<FocusHandleId>,
918    suspended: Option<FocusHandleId>,
919    owner_focused: bool,
920    pending: Vec<FocusCommand>,
921    pending_notifications: Vec<FocusNotification>,
922    pending_reveal: Option<FocusHandleId>,
923}
924
925impl FocusOwner {
926    pub(crate) fn new() -> Self {
927        let mut nodes = HashMap::default();
928        nodes.insert(ROOT_SCOPE_ID, FocusTreeNode::new_root_scope());
929        Self {
930            nodes,
931            children_by_parent: HashMap::default(),
932            requester_bindings: HashMap::default(),
933            requesters_by_handle: HashMap::default(),
934            active: None,
935            captured: None,
936            suspended: None,
937            owner_focused: true,
938            pending: Vec::new(),
939            pending_notifications: Vec::new(),
940            pending_reveal: None,
941        }
942    }
943
944    pub(crate) fn reset(&mut self) {
945        *self = Self::new();
946    }
947
948    pub(crate) fn state_of(&self, id: FocusHandleId) -> FocusState {
949        self.nodes
950            .get(&id)
951            .filter(|node| node.is_attached())
952            .map(|node| node.state)
953            .unwrap_or(FocusState::Inactive)
954    }
955
956    pub(crate) fn active_component_node_id(&self) -> Option<NodeId> {
957        let active = self.active?;
958        self.nodes
959            .get(&active)
960            .and_then(|node| node.attachment)
961            .and_then(|attachment| attachment.live_node_id)
962    }
963
964    pub(crate) fn component_node_id_of(&self, id: FocusHandleId) -> Option<NodeId> {
965        self.nodes
966            .get(&id)
967            .and_then(|node| node.attachment)
968            .and_then(|attachment| attachment.live_node_id)
969    }
970
971    pub(crate) fn active_handle_id(&self) -> Option<FocusHandleId> {
972        self.active
973    }
974
975    pub(crate) fn take_pending_reveal(&mut self) -> Option<FocusHandleId> {
976        self.pending_reveal.take()
977    }
978
979    pub(crate) fn state_of_requester(&self, id: FocusRequesterId) -> FocusState {
980        self.requester_bindings
981            .get(&id)
982            .copied()
983            .map(|handle_id| self.state_of(handle_id))
984            .unwrap_or(FocusState::Inactive)
985    }
986
987    pub(crate) fn request_focus_by_requester(&mut self, id: FocusRequesterId) {
988        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
989            self.request_focus(handle_id);
990        }
991    }
992
993    pub(crate) fn clear_focus_by_requester(&mut self, id: FocusRequesterId) {
994        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
995            self.clear_focus(handle_id);
996        }
997    }
998
999    pub(crate) fn capture_focus_by_requester(&mut self, id: FocusRequesterId) {
1000        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1001            self.capture_focus(handle_id);
1002        }
1003    }
1004
1005    pub(crate) fn free_focus_by_requester(&mut self, id: FocusRequesterId) {
1006        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1007            self.free_focus(handle_id);
1008        }
1009    }
1010
1011    pub(crate) fn request_focus(&mut self, id: FocusHandleId) {
1012        if !self.apply_command(FocusCommand::Request(id)) {
1013            self.pending.push(FocusCommand::Request(id));
1014        }
1015    }
1016
1017    pub(crate) fn clear_focus(&mut self, id: FocusHandleId) {
1018        if !self.apply_command(FocusCommand::Clear(id)) {
1019            self.pending.push(FocusCommand::Clear(id));
1020        }
1021    }
1022
1023    pub(crate) fn capture_focus(&mut self, id: FocusHandleId) {
1024        if !self.apply_command(FocusCommand::Capture(id)) {
1025            self.pending.push(FocusCommand::Capture(id));
1026        }
1027    }
1028
1029    pub(crate) fn free_focus(&mut self, id: FocusHandleId) {
1030        if !self.apply_command(FocusCommand::Free(id)) {
1031            self.pending.push(FocusCommand::Free(id));
1032        }
1033    }
1034
1035    pub(crate) fn restore_focus(&mut self, id: FocusHandleId) {
1036        if !self.apply_command(FocusCommand::Restore(id)) {
1037            self.pending.push(FocusCommand::Restore(id));
1038        }
1039    }
1040
1041    pub(crate) fn set_owner_focused(&mut self, focused: bool) {
1042        if self.owner_focused == focused {
1043            return;
1044        }
1045
1046        let previous_states = self.snapshot_live_states();
1047        self.owner_focused = focused;
1048        if focused {
1049            if let Some(suspended) = self.suspended.take() {
1050                if let Some(target) = self.resolve_request_target(suspended) {
1051                    self.active = Some(target);
1052                    self.pending_reveal = Some(target);
1053                } else {
1054                    self.suspended = Some(suspended);
1055                }
1056            }
1057        } else {
1058            self.suspended = self.active;
1059            self.active = None;
1060            self.captured = None;
1061            self.pending_reveal = None;
1062        }
1063        self.recompute_states();
1064        self.notify_state_changes(previous_states);
1065    }
1066
1067    pub(crate) fn sync_from_component_tree(&mut self, root_node: NodeId, tree: &ComponentNodeTree) {
1068        self.nodes
1069            .entry(ROOT_SCOPE_ID)
1070            .or_insert_with(FocusTreeNode::new_root_scope);
1071
1072        let previous_states = self.snapshot_live_states();
1073        let previous_requester_bindings = self.requester_bindings.clone();
1074        for node in self.nodes.values_mut() {
1075            let is_root_scope = matches!(
1076                node.attachment,
1077                Some(FocusAttachment {
1078                    host_instance_key: 0,
1079                    ..
1080                })
1081            );
1082            if !is_root_scope {
1083                node.attachment = None;
1084                node.state = FocusState::Inactive;
1085            }
1086        }
1087        self.children_by_parent.clear();
1088        self.children_by_parent.insert(ROOT_SCOPE_ID, Vec::new());
1089        self.requester_bindings.clear();
1090        self.requesters_by_handle.clear();
1091        if let Some(root) = self.nodes.get_mut(&ROOT_SCOPE_ID) {
1092            root.attachment = Some(FocusAttachment::root_scope());
1093            root.state = FocusState::Inactive;
1094        }
1095
1096        let mut seen = HashSet::default();
1097        self.collect_focus_nodes(root_node, tree, ROOT_SCOPE_ID, ROOT_SCOPE_ID, &mut seen);
1098
1099        self.repair_after_sync();
1100        self.recompute_states();
1101        self.notify_state_changes(previous_states);
1102        self.notify_requester_binding_changes(previous_requester_bindings);
1103    }
1104
1105    pub(crate) fn sync_layout_from_component_tree(
1106        &mut self,
1107        root_node: NodeId,
1108        tree: &ComponentNodeTree,
1109        metadatas: &ComponentNodeMetaDatas,
1110    ) {
1111        let handles_by_node_id: HashMap<NodeId, FocusHandleId> = self
1112            .nodes
1113            .iter()
1114            .filter_map(|(&handle_id, node)| {
1115                node.attachment
1116                    .and_then(|attachment| attachment.live_node_id)
1117                    .map(|node_id| (node_id, handle_id))
1118            })
1119            .collect();
1120
1121        for node in self.nodes.values_mut() {
1122            if let Some(attachment) = node.attachment.as_mut() {
1123                attachment.focus_rect = None;
1124                attachment.traversal_order = None;
1125            }
1126        }
1127
1128        let mut next_traversal_order = 0_u64;
1129        self.assign_layout_info_for_subtree(
1130            root_node,
1131            tree,
1132            metadatas,
1133            &handles_by_node_id,
1134            &mut next_traversal_order,
1135        );
1136        self.sort_children_by_traversal_order();
1137    }
1138
1139    pub(crate) fn commit_pending(&mut self) {
1140        if self.pending.is_empty() {
1141            return;
1142        }
1143
1144        let previous_states = self.snapshot_live_states();
1145        let commands = std::mem::take(&mut self.pending);
1146        for command in commands {
1147            if !self.apply_command_inner(command) {
1148                self.pending.push(command);
1149            }
1150        }
1151        self.recompute_states();
1152        self.notify_state_changes(previous_states);
1153    }
1154
1155    pub(crate) fn take_pending_notifications(&mut self) -> Vec<FocusNotification> {
1156        std::mem::take(&mut self.pending_notifications)
1157    }
1158
1159    pub(crate) fn clear_focus_global(&mut self, force: bool) -> bool {
1160        let previous_states = self.snapshot_live_states();
1161        let cleared = if self.active.is_some() && (force || self.captured.is_none()) {
1162            self.active = None;
1163            self.captured = None;
1164            self.pending_reveal = None;
1165            true
1166        } else {
1167            false
1168        };
1169        self.recompute_states();
1170        self.notify_state_changes(previous_states);
1171        cleared
1172    }
1173
1174    pub(crate) fn move_focus(&mut self, direction: FocusDirection) -> bool {
1175        if !self.owner_focused {
1176            return false;
1177        }
1178        let previous_states = self.snapshot_live_states();
1179        let moved = self
1180            .resolve_policy_move_target(direction)
1181            .or_else(|| self.resolve_move_target(direction))
1182            .is_some_and(|target| self.set_active(target));
1183        self.recompute_states();
1184        self.notify_state_changes(previous_states);
1185        moved
1186    }
1187
1188    pub(crate) fn move_focus_in_scope(
1189        &mut self,
1190        scope_id: FocusHandleId,
1191        direction: FocusDirection,
1192        wrap: bool,
1193    ) -> bool {
1194        if !self.owner_focused {
1195            return false;
1196        }
1197        let previous_states = self.snapshot_live_states();
1198        let moved = self
1199            .resolve_move_target_in_scope(scope_id, direction, wrap)
1200            .is_some_and(|target| self.set_active(target));
1201        self.recompute_states();
1202        self.notify_state_changes(previous_states);
1203        moved
1204    }
1205
1206    fn resolve_policy_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
1207        let active = self
1208            .active
1209            .and_then(|current| self.resolve_request_target(current))?;
1210        let (owner_id, policy) = self.nearest_traversal_policy_owner(active)?;
1211        let scoped_direction = policy.scoped_direction(direction)?;
1212        self.resolve_move_target_in_scope(owner_id, scoped_direction, policy.wrap)
1213    }
1214
1215    fn nearest_traversal_policy_owner(
1216        &self,
1217        start: FocusHandleId,
1218    ) -> Option<(FocusHandleId, FocusTraversalPolicy)> {
1219        let mut current = Some(start);
1220        while let Some(id) = current {
1221            let node = self.nodes.get(&id)?;
1222            if matches!(
1223                node.kind,
1224                FocusRegistrationKind::Scope | FocusRegistrationKind::Group
1225            ) && let Some(policy) = node.traversal_policy
1226            {
1227                return Some((id, policy));
1228            }
1229            current = (id != ROOT_SCOPE_ID).then_some(node.last_parent);
1230        }
1231        None
1232    }
1233
1234    fn collect_focus_nodes(
1235        &mut self,
1236        node_id: NodeId,
1237        tree: &ComponentNodeTree,
1238        parent_focus_id: FocusHandleId,
1239        current_scope_id: FocusHandleId,
1240        seen: &mut HashSet<FocusHandleId>,
1241    ) {
1242        let Some(node_ref) = tree.get(node_id) else {
1243            return;
1244        };
1245        let node = node_ref.get();
1246
1247        let mut next_parent_focus_id = parent_focus_id;
1248        let mut next_scope_id = current_scope_id;
1249
1250        if let Some(registration) = node.focus_registration {
1251            if !seen.insert(registration.id) {
1252                debug_assert!(
1253                    false,
1254                    "Focus handle {} was registered on multiple component nodes in the same frame",
1255                    registration.id
1256                );
1257            }
1258            let entry = self
1259                .nodes
1260                .entry(registration.id)
1261                .or_insert_with(|| FocusTreeNode::new(registration.kind));
1262            entry.kind = registration.kind;
1263            entry.last_parent = parent_focus_id;
1264            entry.last_scope_parent = current_scope_id;
1265            entry.attachment = Some(FocusAttachment {
1266                host_instance_key: node.instance_key,
1267                live_node_id: Some(node_id),
1268                focus_rect: None,
1269                traversal_order: None,
1270                parent: parent_focus_id,
1271                scope_parent: current_scope_id,
1272            });
1273            entry.props = registration.properties;
1274            entry.traversal_policy = node.focus_traversal_policy;
1275            entry.restorer_fallback = (registration.kind == FocusRegistrationKind::Scope)
1276                .then(|| {
1277                    node.focus_restorer_fallback
1278                        .map(|fallback| fallback.requester_id())
1279                })
1280                .flatten();
1281
1282            self.children_by_parent
1283                .entry(parent_focus_id)
1284                .or_default()
1285                .push(registration.id);
1286            self.children_by_parent.entry(registration.id).or_default();
1287            if let Some(requester) = node.focus_requester_binding {
1288                let replaced = self
1289                    .requester_bindings
1290                    .insert(requester.requester_id(), registration.id);
1291                debug_assert!(
1292                    replaced.is_none() || replaced == Some(registration.id),
1293                    "FocusRequester {} was bound to multiple focus nodes in the same frame",
1294                    requester.requester_id()
1295                );
1296                self.requesters_by_handle
1297                    .entry(registration.id)
1298                    .or_default()
1299                    .push(requester.requester_id());
1300            }
1301
1302            next_parent_focus_id = registration.id;
1303            if registration.kind == FocusRegistrationKind::Scope {
1304                next_scope_id = registration.id;
1305            }
1306        } else if node.focus_requester_binding.is_some() {
1307            debug_assert!(
1308                false,
1309                "focus_requester requires focus_target or focus_scope on the same component node"
1310            );
1311        }
1312
1313        for child_id in node_id.children(tree) {
1314            self.collect_focus_nodes(child_id, tree, next_parent_focus_id, next_scope_id, seen);
1315        }
1316    }
1317
1318    fn assign_layout_info_for_subtree(
1319        &mut self,
1320        node_id: NodeId,
1321        tree: &ComponentNodeTree,
1322        metadatas: &ComponentNodeMetaDatas,
1323        handles_by_node_id: &HashMap<NodeId, FocusHandleId>,
1324        next_traversal_order: &mut u64,
1325    ) {
1326        if let Some(handle_id) = handles_by_node_id.get(&node_id).copied() {
1327            let focus_rect = metadatas.get(&node_id).and_then(|metadata| {
1328                let abs_position = metadata.abs_position?;
1329                let computed_data = metadata.computed_data?;
1330                let node_rect = PxRect::from_position_size(
1331                    abs_position,
1332                    PxSize::new(computed_data.width, computed_data.height),
1333                );
1334                Some(if let Some(clip_rect) = metadata.event_clip_rect {
1335                    clip_rect.intersection(&node_rect).unwrap_or(PxRect::ZERO)
1336                } else {
1337                    node_rect
1338                })
1339            });
1340            if let Some(node) = self.nodes.get_mut(&handle_id)
1341                && let Some(attachment) = node.attachment.as_mut()
1342            {
1343                attachment.focus_rect = focus_rect;
1344                attachment.traversal_order = Some(*next_traversal_order);
1345            }
1346            *next_traversal_order += 1;
1347        }
1348
1349        let mut children: Vec<_> = node_id.children(tree).enumerate().collect();
1350        children.sort_by_key(|(composition_order, child_id)| {
1351            let placement_order = metadatas
1352                .get(child_id)
1353                .and_then(|metadata| metadata.placement_order)
1354                .unwrap_or(u64::MAX);
1355            (placement_order, *composition_order as u64)
1356        });
1357
1358        for (_, child_id) in children {
1359            self.assign_layout_info_for_subtree(
1360                child_id,
1361                tree,
1362                metadatas,
1363                handles_by_node_id,
1364                next_traversal_order,
1365            );
1366        }
1367    }
1368
1369    fn sort_children_by_traversal_order(&mut self) {
1370        let order_by_handle: HashMap<FocusHandleId, (u64, u64)> = self
1371            .nodes
1372            .iter()
1373            .map(|(&handle_id, node)| {
1374                (
1375                    handle_id,
1376                    (
1377                        node.attachment
1378                            .and_then(|attachment| attachment.traversal_order)
1379                            .unwrap_or(u64::MAX),
1380                        node.attachment
1381                            .map(|attachment| attachment.host_instance_key)
1382                            .unwrap_or(u64::MAX),
1383                    ),
1384                )
1385            })
1386            .collect();
1387
1388        for children in self.children_by_parent.values_mut() {
1389            children.sort_by_key(|child| {
1390                order_by_handle
1391                    .get(child)
1392                    .copied()
1393                    .unwrap_or((u64::MAX, u64::MAX))
1394            });
1395        }
1396    }
1397
1398    fn repair_after_sync(&mut self) {
1399        if self
1400            .active
1401            .is_some_and(|id| !self.nodes.get(&id).is_some_and(|node| node.is_attached()))
1402        {
1403            let previous_active = self.active;
1404            if !previous_active.is_some_and(|id| self.should_wait_for_reattach(id)) {
1405                let previous_active = self.active.take();
1406                self.active = previous_active.and_then(|id| self.restore_from_detached(id));
1407                self.captured = None;
1408                if let Some(active) = self.active {
1409                    self.update_scope_restore_chain(active);
1410                    self.pending_reveal = Some(active);
1411                }
1412            }
1413        }
1414
1415        if self
1416            .captured
1417            .is_some_and(|id| !self.nodes.get(&id).is_some_and(|node| node.is_attached()))
1418        {
1419            self.captured = None;
1420        }
1421
1422        if self.owner_focused
1423            && self.active.is_none()
1424            && let Some(suspended) = self.suspended
1425            && let Some(target) = self.resolve_request_target(suspended)
1426        {
1427            self.active = Some(target);
1428            self.suspended = None;
1429            self.pending_reveal = Some(target);
1430        }
1431
1432        if self.active.is_some_and(|id| {
1433            self.nodes.get(&id).is_some_and(|node| {
1434                node.is_attached() && (!self.can_focus(id) || !self.can_request_focus(id))
1435            })
1436        }) {
1437            self.active = None;
1438            self.captured = None;
1439            self.pending_reveal = None;
1440        }
1441
1442        let live_ids = self
1443            .nodes
1444            .iter()
1445            .filter_map(|(&id, node)| node.is_attached().then_some(id))
1446            .collect::<HashSet<_>>();
1447        for node in self.nodes.values_mut() {
1448            if node
1449                .last_focused_descendant
1450                .is_some_and(|last| !live_ids.contains(&last))
1451            {
1452                node.last_focused_descendant = None;
1453            }
1454            if node
1455                .restorer_fallback
1456                .is_some_and(|fallback| !self.requester_bindings.contains_key(&fallback))
1457            {
1458                node.restorer_fallback = None;
1459            }
1460        }
1461    }
1462
1463    fn should_wait_for_reattach(&self, id: FocusHandleId) -> bool {
1464        let Some(node) = self.nodes.get(&id) else {
1465            return false;
1466        };
1467        if node.is_attached() {
1468            return false;
1469        }
1470        if has_persistent_focus_handle(id) {
1471            return true;
1472        }
1473        let waiting_scope_id = node.last_scope_parent;
1474        waiting_scope_id != ROOT_SCOPE_ID
1475            && self
1476                .nodes
1477                .get(&waiting_scope_id)
1478                .is_some_and(|scope| !scope.is_attached())
1479    }
1480
1481    pub(crate) fn remove_handles(
1482        &mut self,
1483        removed_handles: &HashSet<FocusHandleId>,
1484        removed_requesters: &HashSet<FocusRequesterId>,
1485    ) {
1486        if removed_handles.is_empty() && removed_requesters.is_empty() {
1487            return;
1488        }
1489
1490        let previous_states = self.snapshot_live_states();
1491        let previous_requester_bindings = self.requester_bindings.clone();
1492
1493        for requester_id in removed_requesters {
1494            self.requester_bindings.remove(requester_id);
1495        }
1496        for requesters in self.requesters_by_handle.values_mut() {
1497            requesters.retain(|requester_id| !removed_requesters.contains(requester_id));
1498        }
1499
1500        let active_was_removed = self.active.filter(|id| removed_handles.contains(id));
1501        if active_was_removed.is_some() {
1502            self.active = active_was_removed.and_then(|id| self.restore_from_detached(id));
1503            self.captured = None;
1504            if let Some(active) = self.active {
1505                self.update_scope_restore_chain(active);
1506                self.pending_reveal = Some(active);
1507            } else {
1508                self.pending_reveal = None;
1509            }
1510        }
1511
1512        if self
1513            .captured
1514            .is_some_and(|id| removed_handles.contains(&id))
1515        {
1516            self.captured = None;
1517        }
1518        if self
1519            .suspended
1520            .is_some_and(|id| removed_handles.contains(&id))
1521        {
1522            self.suspended = None;
1523        }
1524
1525        for handle_id in removed_handles {
1526            self.nodes.remove(handle_id);
1527            self.children_by_parent.remove(handle_id);
1528            self.requesters_by_handle.remove(handle_id);
1529        }
1530        for children in self.children_by_parent.values_mut() {
1531            children.retain(|child| !removed_handles.contains(child));
1532        }
1533        for node in self.nodes.values_mut() {
1534            if node
1535                .last_focused_descendant
1536                .is_some_and(|candidate| removed_handles.contains(&candidate))
1537            {
1538                node.last_focused_descendant = None;
1539            }
1540            if node
1541                .restorer_fallback
1542                .is_some_and(|requester_id| removed_requesters.contains(&requester_id))
1543            {
1544                node.restorer_fallback = None;
1545            }
1546        }
1547
1548        self.recompute_states();
1549        self.notify_state_changes(previous_states);
1550        self.notify_requester_binding_changes(previous_requester_bindings);
1551    }
1552
1553    fn apply_command(&mut self, command: FocusCommand) -> bool {
1554        let previous_states = self.snapshot_live_states();
1555        let applied = self.apply_command_inner(command);
1556        self.recompute_states();
1557        self.notify_state_changes(previous_states);
1558        applied
1559    }
1560
1561    fn apply_command_inner(&mut self, command: FocusCommand) -> bool {
1562        match command {
1563            FocusCommand::Request(id) => {
1564                if !self.owner_focused {
1565                    self.suspended = Some(id);
1566                    return true;
1567                }
1568                let Some(target) = self.resolve_request_target(id) else {
1569                    return false;
1570                };
1571                self.set_active(target)
1572            }
1573            FocusCommand::Clear(id) => self.clear_active_for(id),
1574            FocusCommand::Capture(id) => {
1575                if self.active == Some(id)
1576                    && self.nodes.get(&id).is_some_and(|node| node.is_attached())
1577                {
1578                    self.captured = Some(id);
1579                    true
1580                } else {
1581                    false
1582                }
1583            }
1584            FocusCommand::Free(id) => {
1585                if self.captured == Some(id) {
1586                    self.captured = None;
1587                    true
1588                } else {
1589                    false
1590                }
1591            }
1592            FocusCommand::Restore(id) => {
1593                let Some(target) = self.resolve_restore_candidate(id) else {
1594                    return false;
1595                };
1596                self.set_active(target)
1597            }
1598        }
1599    }
1600
1601    fn set_active(&mut self, target: FocusHandleId) -> bool {
1602        if self.captured.is_some() && self.captured != Some(target) {
1603            return false;
1604        }
1605        let changed = self.active != Some(target) || self.captured.is_some_and(|id| id != target);
1606        self.active = Some(target);
1607        if self.captured.is_some_and(|id| id != target) {
1608            self.captured = None;
1609        }
1610        self.update_scope_restore_chain(target);
1611        if changed {
1612            self.pending_reveal = Some(target);
1613        }
1614        changed
1615    }
1616
1617    fn clear_active_for(&mut self, id: FocusHandleId) -> bool {
1618        let Some(active) = self.active else {
1619            return false;
1620        };
1621        let affects_active = active == id || self.is_ancestor(id, active);
1622        if !affects_active {
1623            return false;
1624        }
1625        if self.captured.is_some() {
1626            return false;
1627        }
1628
1629        self.active = None;
1630        self.captured = None;
1631        self.pending_reveal = None;
1632        true
1633    }
1634
1635    fn resolve_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
1636        if let Some(active) = self.active
1637            && let Some(explicit) = self.resolve_explicit_direction_target(active, direction)
1638        {
1639            return Some(explicit);
1640        }
1641
1642        if matches!(
1643            direction,
1644            FocusDirection::Left
1645                | FocusDirection::Right
1646                | FocusDirection::Up
1647                | FocusDirection::Down
1648        ) && let Some(target) = self.resolve_geometric_move_target(direction)
1649        {
1650            return Some(target);
1651        }
1652
1653        let candidates = self.traversable_focus_handles();
1654        if candidates.is_empty() {
1655            return None;
1656        }
1657
1658        let forward = matches!(
1659            direction,
1660            FocusDirection::Next
1661                | FocusDirection::Down
1662                | FocusDirection::Right
1663                | FocusDirection::Enter
1664        );
1665
1666        let Some(active) = self
1667            .active
1668            .and_then(|current| self.resolve_request_target(current))
1669        else {
1670            return if forward {
1671                candidates.first().copied()
1672            } else {
1673                candidates.last().copied()
1674            };
1675        };
1676
1677        let Some(index) = candidates.iter().position(|candidate| *candidate == active) else {
1678            return if forward {
1679                candidates.first().copied()
1680            } else {
1681                candidates.last().copied()
1682            };
1683        };
1684
1685        if forward {
1686            candidates.get(index + 1).copied()
1687        } else if index > 0 {
1688            candidates.get(index - 1).copied()
1689        } else {
1690            None
1691        }
1692    }
1693
1694    fn resolve_move_target_in_scope(
1695        &self,
1696        scope_id: FocusHandleId,
1697        direction: FocusDirection,
1698        wrap: bool,
1699    ) -> Option<FocusHandleId> {
1700        let candidates = self.traversable_focus_handles_in_scope(scope_id);
1701        if candidates.is_empty() {
1702            return None;
1703        }
1704
1705        let active = self
1706            .active
1707            .and_then(|current| self.resolve_request_target(current))
1708            .filter(|current| self.is_ancestor(scope_id, *current));
1709
1710        if let Some(active) = active
1711            && let Some(explicit) = self.resolve_explicit_direction_target(active, direction)
1712            && self.is_ancestor(scope_id, explicit)
1713        {
1714            return Some(explicit);
1715        }
1716
1717        if matches!(
1718            direction,
1719            FocusDirection::Left
1720                | FocusDirection::Right
1721                | FocusDirection::Up
1722                | FocusDirection::Down
1723        ) && let Some(target) =
1724            self.resolve_geometric_move_target_in_candidates(direction, &candidates, active)
1725        {
1726            return Some(target);
1727        }
1728
1729        let forward = matches!(
1730            direction,
1731            FocusDirection::Next
1732                | FocusDirection::Down
1733                | FocusDirection::Right
1734                | FocusDirection::Enter
1735        );
1736
1737        let Some(active) = active else {
1738            return if forward {
1739                candidates.first().copied()
1740            } else {
1741                candidates.last().copied()
1742            };
1743        };
1744
1745        let Some(index) = candidates.iter().position(|candidate| *candidate == active) else {
1746            return if forward {
1747                candidates.first().copied()
1748            } else {
1749                candidates.last().copied()
1750            };
1751        };
1752
1753        if forward {
1754            candidates
1755                .get(index + 1)
1756                .copied()
1757                .or_else(|| wrap.then_some(candidates.first().copied()).flatten())
1758        } else if index > 0 {
1759            candidates.get(index - 1).copied()
1760        } else if wrap {
1761            candidates.last().copied()
1762        } else {
1763            None
1764        }
1765    }
1766
1767    fn resolve_geometric_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
1768        let active = self.active.and_then(|id| self.resolve_request_target(id))?;
1769        let focused_rect = self.nodes.get(&active)?.attachment?.focus_rect?;
1770        let mut best_candidate = initial_best_candidate_rect(focused_rect, direction);
1771        let mut best_handle = None;
1772
1773        for handle_id in self.traversable_focus_handles() {
1774            if handle_id == active {
1775                continue;
1776            }
1777            let Some(candidate_rect) = self
1778                .nodes
1779                .get(&handle_id)
1780                .and_then(|node| node.attachment)
1781                .and_then(|attachment| attachment.focus_rect)
1782            else {
1783                continue;
1784            };
1785            if !is_eligible_focus_rect(candidate_rect) {
1786                continue;
1787            }
1788            if is_better_focus_candidate(candidate_rect, best_candidate, focused_rect, direction) {
1789                best_candidate = candidate_rect;
1790                best_handle = Some(handle_id);
1791            }
1792        }
1793
1794        best_handle
1795    }
1796
1797    fn resolve_geometric_move_target_in_candidates(
1798        &self,
1799        direction: FocusDirection,
1800        candidates: &[FocusHandleId],
1801        active: Option<FocusHandleId>,
1802    ) -> Option<FocusHandleId> {
1803        let active = active?;
1804        let focused_rect = self.nodes.get(&active)?.attachment?.focus_rect?;
1805        let mut best_candidate = initial_best_candidate_rect(focused_rect, direction);
1806        let mut best_handle = None;
1807
1808        for &handle_id in candidates {
1809            if handle_id == active {
1810                continue;
1811            }
1812            let Some(candidate_rect) = self
1813                .nodes
1814                .get(&handle_id)
1815                .and_then(|node| node.attachment)
1816                .and_then(|attachment| attachment.focus_rect)
1817            else {
1818                continue;
1819            };
1820            if !is_eligible_focus_rect(candidate_rect) {
1821                continue;
1822            }
1823            if is_better_focus_candidate(candidate_rect, best_candidate, focused_rect, direction) {
1824                best_candidate = candidate_rect;
1825                best_handle = Some(handle_id);
1826            }
1827        }
1828
1829        best_handle
1830    }
1831
1832    fn resolve_request_target(&self, id: FocusHandleId) -> Option<FocusHandleId> {
1833        let node = self.nodes.get(&id)?;
1834        if !node.is_attached() {
1835            return None;
1836        }
1837        match node.kind {
1838            FocusRegistrationKind::Target => self.can_request_focus(id).then_some(id),
1839            FocusRegistrationKind::Scope => self
1840                .resolve_restore_candidate(id)
1841                .or_else(|| self.first_focusable_descendant(id))
1842                .or_else(|| self.can_request_focus(id).then_some(id)),
1843            FocusRegistrationKind::Group => self
1844                .first_focusable_descendant(id)
1845                .or_else(|| self.can_request_focus(id).then_some(id)),
1846        }
1847    }
1848
1849    fn resolve_requester_target(&self, requester_id: FocusRequesterId) -> Option<FocusHandleId> {
1850        self.requester_bindings.get(&requester_id).copied()
1851    }
1852
1853    fn resolve_explicit_direction_target(
1854        &self,
1855        id: FocusHandleId,
1856        direction: FocusDirection,
1857    ) -> Option<FocusHandleId> {
1858        let requester = self.nodes.get(&id).and_then(|node| match direction {
1859            FocusDirection::Next => node.props.next,
1860            FocusDirection::Previous => node.props.previous,
1861            FocusDirection::Up => node.props.up,
1862            FocusDirection::Down => node.props.down,
1863            FocusDirection::Left => node.props.left,
1864            FocusDirection::Right => node.props.right,
1865            FocusDirection::Enter => node.props.enter,
1866            FocusDirection::Exit => node.props.exit,
1867        })?;
1868        let handle_id = self.resolve_requester_target(requester.requester_id())?;
1869        self.resolve_request_target(handle_id)
1870    }
1871
1872    fn resolve_restore_candidate(&self, id: FocusHandleId) -> Option<FocusHandleId> {
1873        let scope = self.nodes.get(&id)?;
1874        if !scope.is_attached() || scope.kind != FocusRegistrationKind::Scope {
1875            return None;
1876        }
1877        scope
1878            .last_focused_descendant
1879            .filter(|candidate| self.can_request_focus(*candidate))
1880            .or_else(|| {
1881                scope
1882                    .restorer_fallback
1883                    .and_then(|requester_id| self.resolve_requester_target(requester_id))
1884                    .and_then(|candidate| self.resolve_request_target(candidate))
1885            })
1886            .or_else(|| self.first_focusable_descendant(id))
1887    }
1888
1889    fn traversable_focus_handles(&self) -> Vec<FocusHandleId> {
1890        let mut ordered = Vec::new();
1891        self.collect_traversable_focus_handles(ROOT_SCOPE_ID, &mut ordered);
1892        ordered
1893    }
1894
1895    fn traversable_focus_handles_in_scope(&self, scope_id: FocusHandleId) -> Vec<FocusHandleId> {
1896        let mut ordered = Vec::new();
1897        self.collect_traversable_focus_handles(scope_id, &mut ordered);
1898        ordered
1899    }
1900
1901    fn collect_traversable_focus_handles(
1902        &self,
1903        parent: FocusHandleId,
1904        ordered: &mut Vec<FocusHandleId>,
1905    ) {
1906        let Some(children) = self.children_by_parent.get(&parent) else {
1907            return;
1908        };
1909        for &child in children {
1910            if self.is_traversable_focus_handle(child) {
1911                ordered.push(child);
1912            }
1913            self.collect_traversable_focus_handles(child, ordered);
1914        }
1915    }
1916
1917    fn is_traversable_focus_handle(&self, id: FocusHandleId) -> bool {
1918        self.nodes.get(&id).is_some_and(|node| {
1919            node.is_attached()
1920                && !node.props.skip_traversal
1921                && node.props.can_focus
1922                && node.props.can_request_focus
1923        })
1924    }
1925
1926    fn first_focusable_descendant(&self, parent: FocusHandleId) -> Option<FocusHandleId> {
1927        let mut stack = self
1928            .children_by_parent
1929            .get(&parent)
1930            .cloned()
1931            .unwrap_or_default();
1932        while let Some(id) = stack.first().copied() {
1933            stack.remove(0);
1934            if self.can_request_focus(id) {
1935                return Some(id);
1936            }
1937            if let Some(children) = self.children_by_parent.get(&id) {
1938                let mut descendants = children.clone();
1939                descendants.extend(stack);
1940                stack = descendants;
1941            }
1942        }
1943        None
1944    }
1945
1946    fn restore_from_detached(&self, id: FocusHandleId) -> Option<FocusHandleId> {
1947        let mut current_scope = self.nodes.get(&id).map(|node| node.last_scope_parent)?;
1948        loop {
1949            if let Some(candidate) = self.resolve_restore_candidate(current_scope) {
1950                return Some(candidate);
1951            }
1952            if current_scope == ROOT_SCOPE_ID {
1953                break;
1954            }
1955            current_scope = self
1956                .nodes
1957                .get(&current_scope)
1958                .map(|node| node.last_scope_parent)
1959                .unwrap_or(ROOT_SCOPE_ID);
1960        }
1961        None
1962    }
1963
1964    fn update_scope_restore_chain(&mut self, target: FocusHandleId) {
1965        let mut current = Some(target);
1966        while let Some(id) = current {
1967            if let Some(node) = self.nodes.get_mut(&id)
1968                && node.kind == FocusRegistrationKind::Scope
1969            {
1970                node.last_focused_descendant = Some(target);
1971            }
1972            if id == ROOT_SCOPE_ID {
1973                break;
1974            }
1975            current = self
1976                .nodes
1977                .get(&id)
1978                .and_then(|node| node.attachment)
1979                .map(|attachment| attachment.scope_parent);
1980            if current == Some(id) {
1981                break;
1982            }
1983        }
1984        if let Some(root) = self.nodes.get_mut(&ROOT_SCOPE_ID) {
1985            root.last_focused_descendant = Some(target);
1986        }
1987    }
1988
1989    fn snapshot_live_states(&self) -> HashMap<FocusHandleId, FocusState> {
1990        self.nodes
1991            .iter()
1992            .filter_map(|(&id, node)| node.is_attached().then_some((id, node.state)))
1993            .collect()
1994    }
1995
1996    fn notify_requester_binding_changes(
1997        &self,
1998        previous_bindings: HashMap<FocusRequesterId, FocusHandleId>,
1999    ) {
2000        let mut changed = HashSet::default();
2001        for (&requester_id, &previous_handle_id) in &previous_bindings {
2002            let current = self.requester_bindings.get(&requester_id).copied();
2003            if current != Some(previous_handle_id) {
2004                changed.insert(requester_id);
2005            }
2006        }
2007        for (&requester_id, &current_handle_id) in &self.requester_bindings {
2008            let previous = previous_bindings.get(&requester_id).copied();
2009            if previous != Some(current_handle_id) {
2010                changed.insert(requester_id);
2011            }
2012        }
2013        for requester_id in changed {
2014            for reader in focus_requester_read_subscribers(requester_id) {
2015                record_component_invalidation_for_instance_key(reader);
2016            }
2017        }
2018    }
2019
2020    fn notify_state_changes(&mut self, previous_states: HashMap<FocusHandleId, FocusState>) {
2021        let mut changed = HashSet::default();
2022        let mut events = HashSet::default();
2023        let mut changed_requesters = HashSet::default();
2024
2025        for (&id, &previous) in &previous_states {
2026            let current = self
2027                .nodes
2028                .get(&id)
2029                .filter(|node| node.is_attached())
2030                .map(|node| node.state)
2031                .unwrap_or(FocusState::Inactive);
2032            if previous != current {
2033                changed.insert(id);
2034            }
2035            if previous.has_focus() {
2036                events.insert(id);
2037            }
2038        }
2039
2040        for (&id, node) in &self.nodes {
2041            if !node.is_attached() {
2042                continue;
2043            }
2044            let previous = previous_states
2045                .get(&id)
2046                .copied()
2047                .unwrap_or(FocusState::Inactive);
2048            if previous != node.state {
2049                changed.insert(id);
2050            }
2051            if node.state.has_focus() {
2052                events.insert(id);
2053            }
2054        }
2055
2056        for &id in &changed {
2057            let state = self
2058                .nodes
2059                .get(&id)
2060                .filter(|node| node.is_attached())
2061                .map(|node| node.state)
2062                .unwrap_or(FocusState::Inactive);
2063            self.pending_notifications.push(FocusNotification {
2064                handle_id: id,
2065                state,
2066                changed: true,
2067            });
2068            for reader in focus_read_subscribers(id) {
2069                record_component_invalidation_for_instance_key(reader);
2070            }
2071            if let Some(node) = self.nodes.get(&id)
2072                && let Some(attachment) = node.attachment
2073                && attachment.host_instance_key != 0
2074            {
2075                record_component_invalidation_for_instance_key(attachment.host_instance_key);
2076            }
2077            if let Some(requesters) = self.requesters_by_handle.get(&id) {
2078                changed_requesters.extend(requesters.iter().copied());
2079            }
2080        }
2081
2082        for id in events {
2083            if changed.contains(&id) {
2084                continue;
2085            }
2086            let state = self
2087                .nodes
2088                .get(&id)
2089                .filter(|node| node.is_attached())
2090                .map(|node| node.state)
2091                .unwrap_or(FocusState::Inactive);
2092            self.pending_notifications.push(FocusNotification {
2093                handle_id: id,
2094                state,
2095                changed: false,
2096            });
2097        }
2098
2099        for requester_id in changed_requesters {
2100            for reader in focus_requester_read_subscribers(requester_id) {
2101                record_component_invalidation_for_instance_key(reader);
2102            }
2103        }
2104    }
2105
2106    fn recompute_states(&mut self) {
2107        for node in self.nodes.values_mut() {
2108            if node.is_attached() {
2109                node.state = FocusState::Inactive;
2110            }
2111        }
2112        let Some(active) = self.active else {
2113            return;
2114        };
2115        if !self
2116            .nodes
2117            .get(&active)
2118            .is_some_and(|node| node.is_attached())
2119        {
2120            return;
2121        }
2122
2123        let mut current = Some(active);
2124        let active_state = if self.captured == Some(active) {
2125            FocusState::Captured
2126        } else {
2127            FocusState::Active
2128        };
2129        let mut first = true;
2130        while let Some(id) = current {
2131            if let Some(node) = self.nodes.get_mut(&id)
2132                && node.is_attached()
2133            {
2134                node.state = if first {
2135                    active_state
2136                } else {
2137                    FocusState::ActiveParent
2138                };
2139            }
2140            if id == ROOT_SCOPE_ID {
2141                break;
2142            }
2143            current = self
2144                .nodes
2145                .get(&id)
2146                .and_then(|node| node.attachment)
2147                .map(|attachment| attachment.parent);
2148            first = false;
2149        }
2150    }
2151
2152    fn can_focus(&self, id: FocusHandleId) -> bool {
2153        self.nodes
2154            .get(&id)
2155            .is_some_and(|node| node.is_attached() && node.props.can_focus)
2156    }
2157
2158    fn can_request_focus(&self, id: FocusHandleId) -> bool {
2159        self.nodes.get(&id).is_some_and(|node| {
2160            node.is_attached() && node.props.can_focus && node.props.can_request_focus
2161        })
2162    }
2163
2164    fn is_ancestor(&self, ancestor: FocusHandleId, descendant: FocusHandleId) -> bool {
2165        let mut current = Some(descendant);
2166        while let Some(id) = current {
2167            if id == ancestor {
2168                return true;
2169            }
2170            if id == ROOT_SCOPE_ID {
2171                break;
2172            }
2173            current = self
2174                .nodes
2175                .get(&id)
2176                .and_then(|node| node.attachment)
2177                .map(|attachment| attachment.parent);
2178        }
2179        false
2180    }
2181}
2182
2183fn is_eligible_focus_rect(rect: PxRect) -> bool {
2184    rect.width.0 > 0 && rect.height.0 > 0
2185}
2186
2187fn initial_best_candidate_rect(focused_rect: PxRect, direction: FocusDirection) -> PxRect {
2188    match direction {
2189        FocusDirection::Left => PxRect::new(
2190            focused_rect.x + focused_rect.width + crate::Px::new(1),
2191            focused_rect.y,
2192            focused_rect.width,
2193            focused_rect.height,
2194        ),
2195        FocusDirection::Right => PxRect::new(
2196            focused_rect.x - focused_rect.width - crate::Px::new(1),
2197            focused_rect.y,
2198            focused_rect.width,
2199            focused_rect.height,
2200        ),
2201        FocusDirection::Up => PxRect::new(
2202            focused_rect.x,
2203            focused_rect.y + focused_rect.height + crate::Px::new(1),
2204            focused_rect.width,
2205            focused_rect.height,
2206        ),
2207        FocusDirection::Down => PxRect::new(
2208            focused_rect.x,
2209            focused_rect.y - focused_rect.height - crate::Px::new(1),
2210            focused_rect.width,
2211            focused_rect.height,
2212        ),
2213        _ => focused_rect,
2214    }
2215}
2216
2217fn is_better_focus_candidate(
2218    proposed_candidate: PxRect,
2219    current_candidate: PxRect,
2220    focused_rect: PxRect,
2221    direction: FocusDirection,
2222) -> bool {
2223    if !is_focus_candidate(proposed_candidate, focused_rect, direction) {
2224        return false;
2225    }
2226    if !is_focus_candidate(current_candidate, focused_rect, direction) {
2227        return true;
2228    }
2229    if focus_beam_beats(
2230        focused_rect,
2231        proposed_candidate,
2232        current_candidate,
2233        direction,
2234    ) {
2235        return true;
2236    }
2237    if focus_beam_beats(
2238        focused_rect,
2239        current_candidate,
2240        proposed_candidate,
2241        direction,
2242    ) {
2243        return false;
2244    }
2245    weighted_focus_distance(proposed_candidate, focused_rect, direction)
2246        < weighted_focus_distance(current_candidate, focused_rect, direction)
2247}
2248
2249fn is_focus_candidate(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> bool {
2250    match direction {
2251        FocusDirection::Left => {
2252            (focused_rect_right(focused_rect) > focused_rect_right(rect)
2253                || focused_rect.x >= focused_rect_right(rect))
2254                && focused_rect.x > rect.x
2255        }
2256        FocusDirection::Right => {
2257            (focused_rect.x < rect.x || focused_rect_right(focused_rect) <= rect.x)
2258                && focused_rect_right(focused_rect) < focused_rect_right(rect)
2259        }
2260        FocusDirection::Up => {
2261            (focused_rect_bottom(focused_rect) > focused_rect_bottom(rect)
2262                || focused_rect.y >= focused_rect_bottom(rect))
2263                && focused_rect.y > rect.y
2264        }
2265        FocusDirection::Down => {
2266            (focused_rect.y < rect.y || focused_rect_bottom(focused_rect) <= rect.y)
2267                && focused_rect_bottom(focused_rect) < focused_rect_bottom(rect)
2268        }
2269        _ => false,
2270    }
2271}
2272
2273fn weighted_focus_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2274    let major = major_axis_distance(rect, focused_rect, direction);
2275    let minor = minor_axis_distance(rect, focused_rect, direction);
2276    13 * major * major + minor * minor
2277}
2278
2279fn focus_beam_beats(
2280    source: PxRect,
2281    rect1: PxRect,
2282    rect2: PxRect,
2283    direction: FocusDirection,
2284) -> bool {
2285    if rect2_in_source_beam(rect2, source, direction)
2286        || !rect2_in_source_beam(rect1, source, direction)
2287    {
2288        return false;
2289    }
2290    if !is_in_direction_of_search(rect2, source, direction) {
2291        return true;
2292    }
2293    if matches!(direction, FocusDirection::Left | FocusDirection::Right) {
2294        return true;
2295    }
2296    major_axis_distance(rect1, source, direction)
2297        < major_axis_distance_to_far_edge(rect2, source, direction)
2298}
2299
2300fn rect2_in_source_beam(rect: PxRect, source: PxRect, direction: FocusDirection) -> bool {
2301    match direction {
2302        FocusDirection::Left | FocusDirection::Right => {
2303            focused_rect_bottom(rect) > source.y && rect.y < focused_rect_bottom(source)
2304        }
2305        FocusDirection::Up | FocusDirection::Down => {
2306            focused_rect_right(rect) > source.x && rect.x < focused_rect_right(source)
2307        }
2308        _ => false,
2309    }
2310}
2311
2312fn is_in_direction_of_search(rect: PxRect, source: PxRect, direction: FocusDirection) -> bool {
2313    match direction {
2314        FocusDirection::Left => source.x >= focused_rect_right(rect),
2315        FocusDirection::Right => focused_rect_right(source) <= rect.x,
2316        FocusDirection::Up => source.y >= focused_rect_bottom(rect),
2317        FocusDirection::Down => focused_rect_bottom(source) <= rect.y,
2318        _ => false,
2319    }
2320}
2321
2322fn major_axis_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2323    let distance = match direction {
2324        FocusDirection::Left => focused_rect.x.0 - focused_rect_right(rect).0,
2325        FocusDirection::Right => rect.x.0 - focused_rect_right(focused_rect).0,
2326        FocusDirection::Up => focused_rect.y.0 - focused_rect_bottom(rect).0,
2327        FocusDirection::Down => rect.y.0 - focused_rect_bottom(focused_rect).0,
2328        _ => 0,
2329    };
2330    i64::from(distance.max(0))
2331}
2332
2333fn major_axis_distance_to_far_edge(rect: PxRect, source: PxRect, direction: FocusDirection) -> i64 {
2334    let distance = match direction {
2335        FocusDirection::Left => source.x.0 - rect.x.0,
2336        FocusDirection::Right => focused_rect_right(rect).0 - focused_rect_right(source).0,
2337        FocusDirection::Up => source.y.0 - rect.y.0,
2338        FocusDirection::Down => focused_rect_bottom(rect).0 - focused_rect_bottom(source).0,
2339        _ => 1,
2340    };
2341    i64::from(distance.max(1))
2342}
2343
2344fn minor_axis_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2345    let focused_center = match direction {
2346        FocusDirection::Left | FocusDirection::Right => {
2347            focused_rect.y.0 + focused_rect.height.0 / 2
2348        }
2349        FocusDirection::Up | FocusDirection::Down => focused_rect.x.0 + focused_rect.width.0 / 2,
2350        _ => 0,
2351    };
2352    let candidate_center = match direction {
2353        FocusDirection::Left | FocusDirection::Right => rect.y.0 + rect.height.0 / 2,
2354        FocusDirection::Up | FocusDirection::Down => rect.x.0 + rect.width.0 / 2,
2355        _ => 0,
2356    };
2357    i64::from(focused_center - candidate_center)
2358}
2359
2360fn focused_rect_right(rect: PxRect) -> crate::Px {
2361    rect.x + rect.width
2362}
2363
2364fn focused_rect_bottom(rect: PxRect) -> crate::Px {
2365    rect.y + rect.height
2366}
2367
2368pub(crate) fn flush_pending_focus_callbacks() {
2369    let callbacks = TesseraRuntime::with_mut(|runtime| {
2370        runtime
2371            .component_tree
2372            .take_pending_focus_callback_invocations()
2373    });
2374    for callback in callbacks {
2375        callback.invoke();
2376    }
2377}