Skip to main content

tessera_ui/
modifier.rs

1//! Modifier chains for node-local layout, drawing, focus, semantics, and other
2//! node-scoped behavior.
3//!
4//! ## Usage
5//!
6//! Build reusable modifier chains that attach behavior directly to the current
7//! component node.
8
9use std::{
10    any::{Any, TypeId},
11    collections::HashMap,
12    fmt,
13    hash::{Hash, Hasher},
14    sync::Arc,
15};
16
17use smallvec::SmallVec;
18
19use crate::{
20    AccessibilityActionHandler, AccessibilityNode, ComputedData, Constraint, FocusGroupNode,
21    FocusProperties, FocusRequester, FocusScopeNode, FocusState, FocusTraversalPolicy, ImeInput,
22    KeyboardInput, MeasurementError, PointerInput, PxPosition,
23    focus::{FocusDirection, FocusNode, FocusRevealRequest},
24    layout::{LayoutInput, RenderInput},
25    prop::CallbackWith,
26    runtime::{TesseraRuntime, ensure_build_phase},
27    winit::window::CursorIcon,
28};
29
30/// Parent-data payloads collected from modifier nodes.
31pub type ParentDataMap = HashMap<TypeId, Arc<dyn Any + Send + Sync>>;
32
33/// Child measurement entry used by layout modifier nodes.
34pub trait LayoutModifierChild {
35    /// Measures the wrapped content under the given constraint.
36    fn measure(&mut self, constraint: &Constraint) -> Result<ComputedData, MeasurementError>;
37
38    /// Places the wrapped content at the provided relative position.
39    fn place(&mut self, position: PxPosition);
40}
41
42/// Input passed to layout modifier nodes.
43pub struct LayoutModifierInput<'a> {
44    /// The original layout input for the current node.
45    pub layout_input: &'a LayoutInput<'a>,
46}
47
48/// Output produced by a layout modifier node.
49pub struct LayoutModifierOutput {
50    /// Final computed size for the current node.
51    pub size: ComputedData,
52}
53
54/// Draw continuation used by draw modifier nodes.
55pub trait DrawModifierContent {
56    /// Records the wrapped content.
57    fn draw(&mut self, input: &mut RenderInput<'_>);
58}
59
60/// Draw input passed to draw modifier nodes.
61pub struct DrawModifierContext<'a, 'b> {
62    /// The render input for the current node.
63    pub render_input: &'a mut RenderInput<'b>,
64}
65
66/// A node-local layout modifier.
67pub trait LayoutModifierNode: Send + Sync + 'static {
68    /// Measures and places the wrapped content.
69    fn measure(
70        &self,
71        input: &LayoutModifierInput<'_>,
72        child: &mut dyn LayoutModifierChild,
73    ) -> Result<LayoutModifierOutput, MeasurementError>;
74}
75
76/// A node-local placement modifier that transforms the current node position
77/// without affecting measured size.
78pub trait PlacementModifierNode: Send + Sync + 'static {
79    /// Returns the transformed node position relative to the parent.
80    fn transform_position(&self, position: PxPosition) -> PxPosition;
81}
82
83/// A node-local draw modifier.
84pub trait DrawModifierNode: Send + Sync + 'static {
85    /// Records drawing behavior around the wrapped content.
86    fn draw(&self, ctx: &mut DrawModifierContext<'_, '_>, content: &mut dyn DrawModifierContent);
87}
88
89/// A node-local parent-data modifier.
90pub trait ParentDataModifierNode: Send + Sync + 'static {
91    /// Applies parent data visible to the parent layout.
92    fn apply_parent_data(&self, data: &mut ParentDataMap);
93}
94
95/// A node-local build modifier.
96pub trait BuildModifierNode: Send + Sync + 'static {
97    /// Applies build-time effects to the current component node.
98    fn apply(&self, runtime: &mut TesseraRuntime);
99}
100
101/// A node-local semantics modifier.
102pub trait SemanticsModifierNode: Send + Sync + 'static {
103    /// Applies accessibility metadata and optional action handling.
104    fn apply(
105        &self,
106        accessibility: &mut AccessibilityNode,
107        action_handler: &mut Option<AccessibilityActionHandler>,
108    );
109}
110
111/// A node-local pointer input modifier.
112pub trait PointerInputModifierNode: Send + Sync + 'static {
113    /// Handles pointer input for the current node.
114    ///
115    /// Pointer modifiers should operate on pointer-specific event flow and
116    /// local interaction state. Cross-cutting concerns such as semantics,
117    /// hover cursors, and IME publication should use their dedicated modifier
118    /// or session APIs.
119    fn on_pointer_input(&self, input: PointerInput<'_>);
120}
121
122/// A node-local hover cursor modifier.
123pub trait CursorModifierNode: Send + Sync + 'static {
124    /// Returns the cursor icon that should be used when the pointer hovers this
125    /// node.
126    fn cursor_icon(&self) -> CursorIcon;
127}
128
129/// A node-local keyboard input modifier.
130pub trait KeyboardInputModifierNode: Send + Sync + 'static {
131    /// Handles keyboard input for the current node.
132    fn on_keyboard_input(&self, input: KeyboardInput<'_>);
133}
134
135/// A node-local IME input modifier.
136pub trait ImeInputModifierNode: Send + Sync + 'static {
137    /// Handles IME input for the current node.
138    fn on_ime_input(&self, input: ImeInput<'_>);
139}
140
141/// Low-level modifier primitive API for framework crates that build semantic
142/// modifier extensions.
143///
144/// This trait is intended for crates such as `tessera-foundation` and
145/// `tessera-components` that implement higher-level `Modifier` extensions. Most
146/// application code should prefer those semantic extensions instead of calling
147/// these methods directly.
148pub trait ModifierCapabilityExt {
149    /// Appends a layout modifier node to the current modifier chain.
150    fn push_layout<N>(self, node: N) -> Self
151    where
152        N: LayoutModifierNode + PartialEq;
153
154    /// Appends a placement modifier node to the current modifier chain.
155    fn push_placement<N>(self, node: N) -> Self
156    where
157        N: PlacementModifierNode + PartialEq;
158
159    /// Appends a draw modifier node to the current modifier chain.
160    fn push_draw<N>(self, node: N) -> Self
161    where
162        N: DrawModifierNode;
163
164    /// Appends a parent-data modifier node to the current modifier chain.
165    fn push_parent_data<N>(self, node: N) -> Self
166    where
167        N: ParentDataModifierNode;
168
169    /// Appends a build modifier node to the current modifier chain.
170    fn push_build<N>(self, node: N) -> Self
171    where
172        N: BuildModifierNode;
173
174    /// Appends a semantics modifier node to the current modifier chain.
175    fn push_semantics<N>(self, node: N) -> Self
176    where
177        N: SemanticsModifierNode;
178
179    /// Appends a preview pointer-input modifier node to the current modifier
180    /// chain.
181    fn push_pointer_preview_input<N>(self, node: N) -> Self
182    where
183        N: PointerInputModifierNode;
184
185    /// Appends a pointer-input modifier node to the current modifier chain.
186    fn push_pointer_input<N>(self, node: N) -> Self
187    where
188        N: PointerInputModifierNode;
189
190    /// Appends a final pointer-input modifier node to the current modifier
191    /// chain.
192    fn push_pointer_final_input<N>(self, node: N) -> Self
193    where
194        N: PointerInputModifierNode;
195
196    /// Appends a preview keyboard-input modifier node to the current modifier
197    /// chain.
198    fn push_keyboard_preview_input<N>(self, node: N) -> Self
199    where
200        N: KeyboardInputModifierNode;
201
202    /// Appends a keyboard-input modifier node to the current modifier chain.
203    fn push_keyboard_input<N>(self, node: N) -> Self
204    where
205        N: KeyboardInputModifierNode;
206
207    /// Appends a preview IME-input modifier node to the current modifier chain.
208    fn push_ime_preview_input<N>(self, node: N) -> Self
209    where
210        N: ImeInputModifierNode;
211
212    /// Appends an IME-input modifier node to the current modifier chain.
213    fn push_ime_input<N>(self, node: N) -> Self
214    where
215        N: ImeInputModifierNode;
216}
217
218#[derive(Clone, PartialEq, Eq)]
219pub(crate) enum FocusModifierRegistration {
220    Target(Option<FocusNode>),
221    Scope(Option<FocusScopeNode>),
222    Group(Option<FocusGroupNode>),
223    Restorer {
224        scope: Option<FocusScopeNode>,
225        fallback: Option<FocusRequester>,
226    },
227}
228
229#[derive(Clone, PartialEq, Eq)]
230enum FocusModifierOp {
231    Requester(FocusRequester),
232    Registration(FocusModifierRegistration),
233    Properties(FocusProperties),
234    TraversalPolicy(FocusTraversalPolicy),
235    ChangedHandler(CallbackWith<FocusState>),
236    EventHandler(CallbackWith<FocusState>),
237    BeyondBoundsHandler(CallbackWith<FocusDirection, bool>),
238    RevealHandler(CallbackWith<FocusRevealRequest, bool>),
239}
240
241pub(crate) trait ErasedLayoutModifierNode: Send + Sync + 'static {
242    fn node(&self) -> Arc<dyn LayoutModifierNode>;
243
244    fn measure_eq(&self, other: &dyn ErasedLayoutModifierNode) -> bool;
245
246    fn placement_eq(&self, other: &dyn ErasedLayoutModifierNode) -> bool;
247
248    fn as_any(&self) -> &dyn Any;
249}
250
251pub(crate) trait ErasedPlacementModifierNode: Send + Sync + 'static {
252    fn node(&self) -> Arc<dyn PlacementModifierNode>;
253
254    fn eq(&self, other: &dyn ErasedPlacementModifierNode) -> bool;
255
256    fn as_any(&self) -> &dyn Any;
257}
258
259struct ComparableLayoutModifierNode<N>
260where
261    N: LayoutModifierNode + PartialEq,
262{
263    node: Arc<N>,
264}
265
266impl<N> ErasedLayoutModifierNode for ComparableLayoutModifierNode<N>
267where
268    N: LayoutModifierNode + PartialEq,
269{
270    fn node(&self) -> Arc<dyn LayoutModifierNode> {
271        self.node.clone()
272    }
273
274    fn measure_eq(&self, other: &dyn ErasedLayoutModifierNode) -> bool {
275        other
276            .as_any()
277            .downcast_ref::<Self>()
278            .is_some_and(|other| self.node.as_ref() == other.node.as_ref())
279    }
280
281    fn placement_eq(&self, other: &dyn ErasedLayoutModifierNode) -> bool {
282        self.measure_eq(other)
283    }
284
285    fn as_any(&self) -> &dyn Any {
286        self
287    }
288}
289
290struct ComparablePlacementModifierNode<N>
291where
292    N: PlacementModifierNode + PartialEq,
293{
294    node: Arc<N>,
295}
296
297impl<N> ErasedPlacementModifierNode for ComparablePlacementModifierNode<N>
298where
299    N: PlacementModifierNode + PartialEq,
300{
301    fn node(&self) -> Arc<dyn PlacementModifierNode> {
302        self.node.clone()
303    }
304
305    fn eq(&self, other: &dyn ErasedPlacementModifierNode) -> bool {
306        other
307            .as_any()
308            .downcast_ref::<Self>()
309            .is_some_and(|other| self.node.as_ref() == other.node.as_ref())
310    }
311
312    fn as_any(&self) -> &dyn Any {
313        self
314    }
315}
316
317#[derive(Clone)]
318enum ModifierAction {
319    Layout(Arc<dyn ErasedLayoutModifierNode>),
320    Placement(Arc<dyn ErasedPlacementModifierNode>),
321    Draw(Arc<dyn DrawModifierNode>),
322    ParentData(Arc<dyn ParentDataModifierNode>),
323    Build(Arc<dyn BuildModifierNode>),
324    Semantics(Arc<dyn SemanticsModifierNode>),
325    Cursor(Arc<dyn CursorModifierNode>),
326    PointerPreviewInput(Arc<dyn PointerInputModifierNode>),
327    PointerInput(Arc<dyn PointerInputModifierNode>),
328    PointerFinalInput(Arc<dyn PointerInputModifierNode>),
329    KeyboardPreviewInput(Arc<dyn KeyboardInputModifierNode>),
330    KeyboardInput(Arc<dyn KeyboardInputModifierNode>),
331    ImePreviewInput(Arc<dyn ImeInputModifierNode>),
332    ImeInput(Arc<dyn ImeInputModifierNode>),
333    Focus(FocusModifierOp),
334}
335
336#[derive(Clone)]
337pub(crate) enum OrderedModifierAction {
338    Layout(Arc<dyn ErasedLayoutModifierNode>),
339    Placement(Arc<dyn ErasedPlacementModifierNode>),
340    Draw(Arc<dyn DrawModifierNode>),
341    ParentData(Arc<dyn ParentDataModifierNode>),
342    Cursor(Arc<dyn CursorModifierNode>),
343    PointerPreviewInput(Arc<dyn PointerInputModifierNode>),
344    PointerInput(Arc<dyn PointerInputModifierNode>),
345    PointerFinalInput(Arc<dyn PointerInputModifierNode>),
346    KeyboardPreviewInput(Arc<dyn KeyboardInputModifierNode>),
347    KeyboardInput(Arc<dyn KeyboardInputModifierNode>),
348    ImePreviewInput(Arc<dyn ImeInputModifierNode>),
349    ImeInput(Arc<dyn ImeInputModifierNode>),
350}
351
352#[derive(Clone)]
353struct ModifierLink {
354    prev: Option<Arc<ModifierLink>>,
355    action: ModifierAction,
356}
357
358fn collect_actions(mut node: Option<Arc<ModifierLink>>) -> Vec<ModifierAction> {
359    let mut actions: SmallVec<[ModifierAction; 8]> = SmallVec::new();
360    while let Some(current) = node {
361        actions.push(current.action.clone());
362        node = current.prev.clone();
363    }
364    actions.into_vec()
365}
366
367fn collect_actions_in_source_order(node: Option<Arc<ModifierLink>>) -> Vec<ModifierAction> {
368    let mut actions = collect_actions(node);
369    actions.reverse();
370    actions
371}
372
373/// A persistent handle to a modifier chain.
374#[derive(Clone, Default)]
375pub struct Modifier {
376    tail: Option<Arc<ModifierLink>>,
377}
378
379/// Focus-specific modifier extensions for [`Modifier`].
380pub trait FocusModifierExt {
381    /// Registers a focus target for this subtree.
382    fn focusable(self) -> Modifier;
383
384    /// Binds an explicit focus requester to this subtree.
385    fn focus_requester(self, requester: FocusRequester) -> Modifier;
386
387    /// Applies explicit focus properties to this subtree.
388    fn focus_properties(self, properties: FocusProperties) -> Modifier;
389
390    /// Registers a traversal-only focus group for this subtree.
391    fn focus_group(self) -> Modifier;
392
393    /// Registers an explicit focus scope handle for this subtree.
394    fn focus_scope_with(self, scope: FocusScopeNode) -> Modifier;
395
396    /// Registers an explicit focus group handle for this subtree.
397    fn focus_group_with(self, group: FocusGroupNode) -> Modifier;
398
399    /// Registers a focus scope with restore behavior for this subtree.
400    fn focus_restorer(self, fallback: Option<FocusRequester>) -> Modifier;
401
402    /// Registers an explicit focus restorer scope for this subtree.
403    fn focus_restorer_with(
404        self,
405        scope: FocusScopeNode,
406        fallback: Option<FocusRequester>,
407    ) -> Modifier;
408
409    /// Applies a traversal policy to the current focus group or scope.
410    fn focus_traversal_policy(self, policy: FocusTraversalPolicy) -> Modifier;
411
412    /// Registers a callback that runs when the subtree focus state changes.
413    fn on_focus_changed<F>(self, handler: F) -> Modifier
414    where
415        F: Into<CallbackWith<FocusState>>;
416
417    /// Registers a callback that observes focus events for this subtree.
418    fn on_focus_event<F>(self, handler: F) -> Modifier
419    where
420        F: Into<CallbackWith<FocusState>>;
421
422    /// Registers a callback that moves focus beyond the current viewport.
423    fn focus_beyond_bounds_handler<F>(self, handler: F) -> Modifier
424    where
425        F: Into<CallbackWith<FocusDirection, bool>>;
426
427    /// Registers a callback that reveals the focused target within the
428    /// viewport.
429    fn focus_reveal_handler<F>(self, handler: F) -> Modifier
430    where
431        F: Into<CallbackWith<FocusRevealRequest, bool>>;
432}
433
434/// Cursor-specific modifier extensions for [`Modifier`].
435pub trait CursorModifierExt {
436    /// Sets the cursor icon used while the pointer hovers this node.
437    fn hover_cursor_icon(self, icon: CursorIcon) -> Modifier;
438}
439
440impl Modifier {
441    /// Creates an empty modifier chain.
442    pub fn new() -> Self {
443        ensure_build_phase();
444        Self::default()
445    }
446
447    fn push_action(self, action: ModifierAction) -> Self {
448        ensure_build_phase();
449        Self {
450            tail: Some(Arc::new(ModifierLink {
451                prev: self.tail,
452                action,
453            })),
454        }
455    }
456
457    /// Appends another modifier chain after this one.
458    pub fn then(mut self, other: Modifier) -> Self {
459        let actions = collect_actions(other.tail);
460        for action in actions.into_iter().rev() {
461            self = self.push_action(action);
462        }
463        self
464    }
465
466    pub(crate) fn push_layout<N>(self, node: N) -> Self
467    where
468        N: LayoutModifierNode + PartialEq,
469    {
470        self.push_action(ModifierAction::Layout(Arc::new(
471            ComparableLayoutModifierNode {
472                node: Arc::new(node),
473            },
474        )))
475    }
476
477    pub(crate) fn push_placement<N>(self, node: N) -> Self
478    where
479        N: PlacementModifierNode + PartialEq,
480    {
481        self.push_action(ModifierAction::Placement(Arc::new(
482            ComparablePlacementModifierNode {
483                node: Arc::new(node),
484            },
485        )))
486    }
487
488    pub(crate) fn push_draw<N>(self, node: N) -> Self
489    where
490        N: DrawModifierNode,
491    {
492        self.push_action(ModifierAction::Draw(Arc::new(node)))
493    }
494
495    pub(crate) fn push_parent_data<N>(self, node: N) -> Self
496    where
497        N: ParentDataModifierNode,
498    {
499        self.push_action(ModifierAction::ParentData(Arc::new(node)))
500    }
501
502    pub(crate) fn push_build<N>(self, node: N) -> Self
503    where
504        N: BuildModifierNode,
505    {
506        self.push_action(ModifierAction::Build(Arc::new(node)))
507    }
508
509    pub(crate) fn push_semantics<N>(self, node: N) -> Self
510    where
511        N: SemanticsModifierNode,
512    {
513        self.push_action(ModifierAction::Semantics(Arc::new(node)))
514    }
515
516    fn push_cursor<N>(self, node: N) -> Self
517    where
518        N: CursorModifierNode,
519    {
520        self.push_action(ModifierAction::Cursor(Arc::new(node)))
521    }
522
523    pub(crate) fn push_pointer_preview_input<N>(self, node: N) -> Self
524    where
525        N: PointerInputModifierNode,
526    {
527        self.push_action(ModifierAction::PointerPreviewInput(Arc::new(node)))
528    }
529
530    pub(crate) fn push_pointer_input<N>(self, node: N) -> Self
531    where
532        N: PointerInputModifierNode,
533    {
534        self.push_action(ModifierAction::PointerInput(Arc::new(node)))
535    }
536
537    pub(crate) fn push_pointer_final_input<N>(self, node: N) -> Self
538    where
539        N: PointerInputModifierNode,
540    {
541        self.push_action(ModifierAction::PointerFinalInput(Arc::new(node)))
542    }
543
544    pub(crate) fn push_keyboard_preview_input<N>(self, node: N) -> Self
545    where
546        N: KeyboardInputModifierNode,
547    {
548        self.push_action(ModifierAction::KeyboardPreviewInput(Arc::new(node)))
549    }
550
551    pub(crate) fn push_keyboard_input<N>(self, node: N) -> Self
552    where
553        N: KeyboardInputModifierNode,
554    {
555        self.push_action(ModifierAction::KeyboardInput(Arc::new(node)))
556    }
557
558    pub(crate) fn push_ime_preview_input<N>(self, node: N) -> Self
559    where
560        N: ImeInputModifierNode,
561    {
562        self.push_action(ModifierAction::ImePreviewInput(Arc::new(node)))
563    }
564
565    pub(crate) fn push_ime_input<N>(self, node: N) -> Self
566    where
567        N: ImeInputModifierNode,
568    {
569        self.push_action(ModifierAction::ImeInput(Arc::new(node)))
570    }
571
572    fn push_focus_requester(self, requester: FocusRequester) -> Self {
573        self.push_focus_op(FocusModifierOp::Requester(requester))
574    }
575
576    fn push_focus_target(self) -> Self {
577        self.push_focus_op(FocusModifierOp::Registration(
578            FocusModifierRegistration::Target(None),
579        ))
580    }
581
582    fn push_focus_scope_with(self, scope: FocusScopeNode) -> Self {
583        self.push_focus_op(FocusModifierOp::Registration(
584            FocusModifierRegistration::Scope(Some(scope)),
585        ))
586    }
587
588    fn push_focus_group(self) -> Self {
589        self.push_focus_op(FocusModifierOp::Registration(
590            FocusModifierRegistration::Group(None),
591        ))
592    }
593
594    fn push_focus_group_with(self, group: FocusGroupNode) -> Self {
595        self.push_focus_op(FocusModifierOp::Registration(
596            FocusModifierRegistration::Group(Some(group)),
597        ))
598    }
599
600    fn push_focus_restorer(self, fallback: Option<FocusRequester>) -> Self {
601        self.push_focus_op(FocusModifierOp::Registration(
602            FocusModifierRegistration::Restorer {
603                scope: None,
604                fallback,
605            },
606        ))
607    }
608
609    fn push_focus_restorer_with(
610        self,
611        scope: FocusScopeNode,
612        fallback: Option<FocusRequester>,
613    ) -> Self {
614        self.push_focus_op(FocusModifierOp::Registration(
615            FocusModifierRegistration::Restorer {
616                scope: Some(scope),
617                fallback,
618            },
619        ))
620    }
621
622    fn push_focus_properties(self, properties: FocusProperties) -> Self {
623        self.push_focus_op(FocusModifierOp::Properties(properties))
624    }
625
626    fn push_focus_traversal_policy(self, policy: FocusTraversalPolicy) -> Self {
627        self.push_focus_op(FocusModifierOp::TraversalPolicy(policy))
628    }
629
630    fn push_focus_changed_handler(self, handler: CallbackWith<FocusState>) -> Self {
631        self.push_focus_op(FocusModifierOp::ChangedHandler(handler))
632    }
633
634    fn push_focus_event_handler(self, handler: CallbackWith<FocusState>) -> Self {
635        self.push_focus_op(FocusModifierOp::EventHandler(handler))
636    }
637
638    fn push_focus_beyond_bounds_handler(self, handler: CallbackWith<FocusDirection, bool>) -> Self {
639        self.push_focus_op(FocusModifierOp::BeyondBoundsHandler(handler))
640    }
641
642    fn push_focus_reveal_handler(self, handler: CallbackWith<FocusRevealRequest, bool>) -> Self {
643        self.push_focus_op(FocusModifierOp::RevealHandler(handler))
644    }
645
646    fn push_focus_op(self, op: FocusModifierOp) -> Self {
647        self.push_action(ModifierAction::Focus(op))
648    }
649
650    /// Attaches this modifier chain to the current component node.
651    pub fn attach(self) {
652        ensure_build_phase();
653
654        let actions = collect_actions(self.tail.clone());
655        TesseraRuntime::with_mut(|runtime| {
656            runtime.append_current_modifier(self.clone());
657        });
658
659        let mut accessibility = AccessibilityNode::new();
660        let mut action_handler = None;
661        let mut has_semantics = false;
662        for action in actions.into_iter().rev() {
663            match action {
664                ModifierAction::Build(node) => {
665                    TesseraRuntime::with_mut(|runtime| node.apply(runtime));
666                }
667                ModifierAction::Semantics(node) => {
668                    has_semantics = true;
669                    node.apply(&mut accessibility, &mut action_handler);
670                }
671                ModifierAction::Focus(op) => {
672                    TesseraRuntime::with_mut(|runtime| {
673                        apply_focus_op(runtime::FocusModifierRuntime::new(runtime), op);
674                    });
675                }
676                _ => {}
677            }
678        }
679
680        TesseraRuntime::with_mut(|runtime| {
681            runtime.set_current_accessibility(has_semantics.then_some(accessibility));
682            runtime.set_current_accessibility_action_handler(action_handler);
683        });
684    }
685
686    /// Attaches this modifier chain to the current node and then runs `child`.
687    pub fn run<F>(self, child: F)
688    where
689        F: Fn() + Send + Sync + 'static,
690    {
691        self.attach();
692        child();
693    }
694
695    /// Returns true when the modifier has no actions.
696    pub fn is_empty(&self) -> bool {
697        self.tail.is_none()
698    }
699
700    pub(crate) fn ordered_actions(&self) -> Vec<OrderedModifierAction> {
701        collect_actions_in_source_order(self.tail.clone())
702            .into_iter()
703            .filter_map(|action| match action {
704                ModifierAction::Layout(node) => Some(OrderedModifierAction::Layout(node)),
705                ModifierAction::Placement(node) => Some(OrderedModifierAction::Placement(node)),
706                ModifierAction::Draw(node) => Some(OrderedModifierAction::Draw(node)),
707                ModifierAction::ParentData(node) => Some(OrderedModifierAction::ParentData(node)),
708                ModifierAction::Cursor(node) => Some(OrderedModifierAction::Cursor(node)),
709                ModifierAction::PointerPreviewInput(node) => {
710                    Some(OrderedModifierAction::PointerPreviewInput(node))
711                }
712                ModifierAction::PointerInput(node) => {
713                    Some(OrderedModifierAction::PointerInput(node))
714                }
715                ModifierAction::PointerFinalInput(node) => {
716                    Some(OrderedModifierAction::PointerFinalInput(node))
717                }
718                ModifierAction::KeyboardPreviewInput(node) => {
719                    Some(OrderedModifierAction::KeyboardPreviewInput(node))
720                }
721                ModifierAction::KeyboardInput(node) => {
722                    Some(OrderedModifierAction::KeyboardInput(node))
723                }
724                ModifierAction::ImePreviewInput(node) => {
725                    Some(OrderedModifierAction::ImePreviewInput(node))
726                }
727                ModifierAction::ImeInput(node) => Some(OrderedModifierAction::ImeInput(node)),
728                ModifierAction::Build(_)
729                | ModifierAction::Semantics(_)
730                | ModifierAction::Focus(_) => None,
731            })
732            .collect()
733    }
734
735    pub(crate) fn layout_measure_eq(&self, other: &Self) -> bool {
736        let lhs: Vec<_> = self
737            .ordered_actions()
738            .into_iter()
739            .filter_map(|action| match action {
740                OrderedModifierAction::Layout(node) => Some(node),
741                _ => None,
742            })
743            .collect();
744        let rhs: Vec<_> = other
745            .ordered_actions()
746            .into_iter()
747            .filter_map(|action| match action {
748                OrderedModifierAction::Layout(node) => Some(node),
749                _ => None,
750            })
751            .collect();
752        lhs.len() == rhs.len()
753            && lhs
754                .iter()
755                .zip(rhs.iter())
756                .all(|(lhs, rhs)| lhs.measure_eq(rhs.as_ref()))
757    }
758
759    pub(crate) fn layout_placement_eq(&self, other: &Self) -> bool {
760        #[derive(Clone)]
761        enum PlacementComparableAction {
762            Layout(Arc<dyn ErasedLayoutModifierNode>),
763            Placement(Arc<dyn ErasedPlacementModifierNode>),
764        }
765
766        let lhs: Vec<_> = self
767            .ordered_actions()
768            .into_iter()
769            .filter_map(|action| match action {
770                OrderedModifierAction::Layout(node) => {
771                    Some(PlacementComparableAction::Layout(node))
772                }
773                OrderedModifierAction::Placement(node) => {
774                    Some(PlacementComparableAction::Placement(node))
775                }
776                _ => None,
777            })
778            .collect();
779        let rhs: Vec<_> = other
780            .ordered_actions()
781            .into_iter()
782            .filter_map(|action| match action {
783                OrderedModifierAction::Layout(node) => {
784                    Some(PlacementComparableAction::Layout(node))
785                }
786                OrderedModifierAction::Placement(node) => {
787                    Some(PlacementComparableAction::Placement(node))
788                }
789                _ => None,
790            })
791            .collect();
792        lhs.len() == rhs.len()
793            && lhs
794                .iter()
795                .zip(rhs.iter())
796                .all(|(lhs, rhs)| match (lhs, rhs) {
797                    (
798                        PlacementComparableAction::Layout(lhs),
799                        PlacementComparableAction::Layout(rhs),
800                    ) => lhs.placement_eq(rhs.as_ref()),
801                    (
802                        PlacementComparableAction::Placement(lhs),
803                        PlacementComparableAction::Placement(rhs),
804                    ) => lhs.eq(rhs.as_ref()),
805                    _ => false,
806                })
807    }
808}
809
810impl ModifierCapabilityExt for Modifier {
811    fn push_layout<N>(self, node: N) -> Self
812    where
813        N: LayoutModifierNode + PartialEq,
814    {
815        Modifier::push_layout(self, node)
816    }
817
818    fn push_placement<N>(self, node: N) -> Self
819    where
820        N: PlacementModifierNode + PartialEq,
821    {
822        Modifier::push_placement(self, node)
823    }
824
825    fn push_draw<N>(self, node: N) -> Self
826    where
827        N: DrawModifierNode,
828    {
829        Modifier::push_draw(self, node)
830    }
831
832    fn push_parent_data<N>(self, node: N) -> Self
833    where
834        N: ParentDataModifierNode,
835    {
836        Modifier::push_parent_data(self, node)
837    }
838
839    fn push_build<N>(self, node: N) -> Self
840    where
841        N: BuildModifierNode,
842    {
843        Modifier::push_build(self, node)
844    }
845
846    fn push_semantics<N>(self, node: N) -> Self
847    where
848        N: SemanticsModifierNode,
849    {
850        Modifier::push_semantics(self, node)
851    }
852
853    fn push_pointer_preview_input<N>(self, node: N) -> Self
854    where
855        N: PointerInputModifierNode,
856    {
857        Modifier::push_pointer_preview_input(self, node)
858    }
859
860    fn push_pointer_input<N>(self, node: N) -> Self
861    where
862        N: PointerInputModifierNode,
863    {
864        Modifier::push_pointer_input(self, node)
865    }
866
867    fn push_pointer_final_input<N>(self, node: N) -> Self
868    where
869        N: PointerInputModifierNode,
870    {
871        Modifier::push_pointer_final_input(self, node)
872    }
873
874    fn push_keyboard_preview_input<N>(self, node: N) -> Self
875    where
876        N: KeyboardInputModifierNode,
877    {
878        Modifier::push_keyboard_preview_input(self, node)
879    }
880
881    fn push_keyboard_input<N>(self, node: N) -> Self
882    where
883        N: KeyboardInputModifierNode,
884    {
885        Modifier::push_keyboard_input(self, node)
886    }
887
888    fn push_ime_preview_input<N>(self, node: N) -> Self
889    where
890        N: ImeInputModifierNode,
891    {
892        Modifier::push_ime_preview_input(self, node)
893    }
894
895    fn push_ime_input<N>(self, node: N) -> Self
896    where
897        N: ImeInputModifierNode,
898    {
899        Modifier::push_ime_input(self, node)
900    }
901}
902
903#[derive(Clone, Copy)]
904struct StaticCursorModifierNode {
905    icon: CursorIcon,
906}
907
908impl CursorModifierNode for StaticCursorModifierNode {
909    fn cursor_icon(&self) -> CursorIcon {
910        self.icon
911    }
912}
913
914impl CursorModifierExt for Modifier {
915    fn hover_cursor_icon(self, icon: CursorIcon) -> Modifier {
916        self.push_cursor(StaticCursorModifierNode { icon })
917    }
918}
919
920impl FocusModifierExt for Modifier {
921    fn focusable(self) -> Modifier {
922        self.push_focus_target()
923    }
924
925    fn focus_requester(self, requester: FocusRequester) -> Modifier {
926        self.push_focus_requester(requester)
927    }
928
929    fn focus_properties(self, properties: FocusProperties) -> Modifier {
930        self.push_focus_properties(properties)
931    }
932
933    fn focus_group(self) -> Modifier {
934        self.push_focus_group()
935    }
936
937    fn focus_scope_with(self, scope: FocusScopeNode) -> Modifier {
938        self.push_focus_scope_with(scope)
939    }
940
941    fn focus_group_with(self, group: FocusGroupNode) -> Modifier {
942        self.push_focus_group_with(group)
943    }
944
945    fn focus_restorer(self, fallback: Option<FocusRequester>) -> Modifier {
946        self.push_focus_restorer(fallback)
947    }
948
949    fn focus_restorer_with(
950        self,
951        scope: FocusScopeNode,
952        fallback: Option<FocusRequester>,
953    ) -> Modifier {
954        self.push_focus_restorer_with(scope, fallback)
955    }
956
957    fn focus_traversal_policy(self, policy: FocusTraversalPolicy) -> Modifier {
958        self.push_focus_traversal_policy(policy)
959    }
960
961    fn on_focus_changed<F>(self, handler: F) -> Modifier
962    where
963        F: Into<CallbackWith<FocusState>>,
964    {
965        self.push_focus_changed_handler(handler.into())
966    }
967
968    fn on_focus_event<F>(self, handler: F) -> Modifier
969    where
970        F: Into<CallbackWith<FocusState>>,
971    {
972        self.push_focus_event_handler(handler.into())
973    }
974
975    fn focus_beyond_bounds_handler<F>(self, handler: F) -> Modifier
976    where
977        F: Into<CallbackWith<FocusDirection, bool>>,
978    {
979        self.push_focus_beyond_bounds_handler(handler.into())
980    }
981
982    fn focus_reveal_handler<F>(self, handler: F) -> Modifier
983    where
984        F: Into<CallbackWith<FocusRevealRequest, bool>>,
985    {
986        self.push_focus_reveal_handler(handler.into())
987    }
988}
989
990impl fmt::Debug for Modifier {
991    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
992        f.debug_struct("Modifier")
993            .field("is_empty", &self.tail.is_none())
994            .finish()
995    }
996}
997
998impl PartialEq for Modifier {
999    fn eq(&self, other: &Self) -> bool {
1000        match (&self.tail, &other.tail) {
1001            (None, None) => true,
1002            (Some(lhs), Some(rhs)) => Arc::ptr_eq(lhs, rhs),
1003            _ => false,
1004        }
1005    }
1006}
1007
1008impl Eq for Modifier {}
1009
1010impl Hash for Modifier {
1011    fn hash<H: Hasher>(&self, state: &mut H) {
1012        match &self.tail {
1013            Some(node) => std::ptr::hash(Arc::as_ptr(node), state),
1014            None => 0u8.hash(state),
1015        }
1016    }
1017}
1018
1019mod runtime {
1020    use super::FocusModifierRegistration;
1021    use crate::{
1022        FocusProperties, FocusRequester, FocusScopeNode, FocusState, FocusTraversalPolicy,
1023        focus::{FocusDirection, FocusRevealRequest},
1024        prop::CallbackWith,
1025        runtime::TesseraRuntime,
1026    };
1027
1028    pub(super) struct FocusModifierRuntime<'a> {
1029        runtime: &'a mut TesseraRuntime,
1030    }
1031
1032    impl<'a> FocusModifierRuntime<'a> {
1033        pub(super) fn new(runtime: &'a mut TesseraRuntime) -> Self {
1034            Self { runtime }
1035        }
1036
1037        pub(super) fn bind_requester(&mut self, requester: FocusRequester) {
1038            self.runtime.bind_current_focus_requester(requester);
1039        }
1040
1041        pub(super) fn ensure_registration(&mut self, registration: FocusModifierRegistration) {
1042            match registration {
1043                FocusModifierRegistration::Target(node) => {
1044                    let node = node.unwrap_or_else(|| {
1045                        self.runtime
1046                            .current_focus_target_handle()
1047                            .unwrap_or_else(|| {
1048                                crate::runtime::persistent_focus_target_for_current_instance(
1049                                    "__tessera_focus_target",
1050                                )
1051                            })
1052                    });
1053                    self.runtime.ensure_current_focus_target(node);
1054                }
1055                FocusModifierRegistration::Scope(scope) => {
1056                    let scope = scope.unwrap_or_else(|| {
1057                        self.runtime
1058                            .current_focus_scope_handle()
1059                            .unwrap_or_else(|| {
1060                                crate::runtime::persistent_focus_scope_for_current_instance(
1061                                    "__tessera_focus_scope",
1062                                )
1063                            })
1064                    });
1065                    self.runtime.ensure_current_focus_scope(scope);
1066                }
1067                FocusModifierRegistration::Group(group) => {
1068                    let group = group.unwrap_or_else(|| {
1069                        self.runtime
1070                            .current_focus_group_handle()
1071                            .unwrap_or_else(|| {
1072                                crate::runtime::persistent_focus_group_for_current_instance(
1073                                    "__tessera_focus_group",
1074                                )
1075                            })
1076                    });
1077                    self.runtime.ensure_current_focus_group(group);
1078                }
1079                FocusModifierRegistration::Restorer { scope, fallback } => {
1080                    let scope: FocusScopeNode = scope.unwrap_or_else(|| {
1081                        self.runtime
1082                            .current_focus_scope_handle()
1083                            .unwrap_or_else(|| {
1084                                crate::runtime::persistent_focus_scope_for_current_instance(
1085                                    "__tessera_focus_scope",
1086                                )
1087                            })
1088                    });
1089                    self.runtime.ensure_current_focus_scope(scope);
1090                    if let Some(fallback) = fallback {
1091                        self.runtime.set_current_focus_restorer_fallback(fallback);
1092                    }
1093                }
1094            }
1095        }
1096
1097        pub(super) fn set_properties(&mut self, properties: FocusProperties) {
1098            self.runtime.set_current_focus_properties(properties);
1099        }
1100
1101        pub(super) fn set_traversal_policy(&mut self, policy: FocusTraversalPolicy) {
1102            self.runtime.set_current_focus_traversal_policy(policy);
1103        }
1104
1105        pub(super) fn set_changed_handler(&mut self, handler: CallbackWith<FocusState>) {
1106            self.runtime.set_current_focus_changed_handler(handler);
1107        }
1108
1109        pub(super) fn set_event_handler(&mut self, handler: CallbackWith<FocusState>) {
1110            self.runtime.set_current_focus_event_handler(handler);
1111        }
1112
1113        pub(super) fn set_beyond_bounds_handler(
1114            &mut self,
1115            handler: CallbackWith<FocusDirection, bool>,
1116        ) {
1117            self.runtime
1118                .set_current_focus_beyond_bounds_handler(handler);
1119        }
1120
1121        pub(super) fn set_reveal_handler(
1122            &mut self,
1123            handler: CallbackWith<FocusRevealRequest, bool>,
1124        ) {
1125            self.runtime.set_current_focus_reveal_handler(handler);
1126        }
1127    }
1128}
1129
1130fn apply_focus_op(runtime: runtime::FocusModifierRuntime<'_>, op: FocusModifierOp) {
1131    let mut runtime = runtime;
1132    match op {
1133        FocusModifierOp::Requester(requester) => runtime.bind_requester(requester),
1134        FocusModifierOp::Registration(registration) => runtime.ensure_registration(registration),
1135        FocusModifierOp::Properties(properties) => runtime.set_properties(properties),
1136        FocusModifierOp::TraversalPolicy(policy) => runtime.set_traversal_policy(policy),
1137        FocusModifierOp::ChangedHandler(handler) => runtime.set_changed_handler(handler),
1138        FocusModifierOp::EventHandler(handler) => runtime.set_event_handler(handler),
1139        FocusModifierOp::BeyondBoundsHandler(handler) => runtime.set_beyond_bounds_handler(handler),
1140        FocusModifierOp::RevealHandler(handler) => runtime.set_reveal_handler(handler),
1141    }
1142}