Skip to main content

floem/view/
id.rs

1#![deny(missing_docs)]
2//! # `ViewId`s
3//!
4//! [`ViewId`]s are unique identifiers for views.
5//! They're used to identify views in the view tree.
6
7use std::{any::Any, cell::RefCell, collections::HashSet, rc::Rc};
8
9use floem_reactive::Scope;
10use peniko::kurbo::{Affine, Point, Rect, RoundedRect, Size};
11use smallvec::smallvec;
12use taffy::{Layout, NodeId};
13use winit::window::WindowId;
14
15use ui_events::pointer::PointerId;
16
17use super::{IntoView, StackOffset, VIEW_STORAGE, View, ViewState, ViewStorage};
18
19thread_local! {
20    /// Views that have scopes but couldn't find a parent scope when added.
21    /// These need to be re-parented after the view tree is fully assembled.
22    static PENDING_SCOPE_REPARENTS: RefCell<HashSet<ViewId>> = RefCell::new(HashSet::new());
23}
24use crate::context::EventCallbackConfig;
25use crate::event::listener::EventListenerKey;
26use crate::event::{RouteKind, listener};
27use crate::style::recalc::StyleReason;
28use crate::view::LayoutTree;
29use crate::window::handle::get_current_view;
30use crate::{BoxTree, ElementId, FocusNavMeta};
31use crate::{
32    ScreenLayout,
33    action::add_update_message,
34    animate::{AnimStateCommand, Animation},
35    context::EventCallback,
36    message::{
37        CENTRAL_DEFERRED_UPDATE_MESSAGES, CENTRAL_UPDATE_MESSAGES, DeferredChild, DeferredChildren,
38        DeferredReactiveSetup, UpdateMessage,
39    },
40    platform::menu::Menu,
41    style::{Focusable, PointerEvents, Style, StyleClassRef, StyleSelector},
42    window::tracking::window_id_for_root,
43};
44
45use super::AnyView;
46
47#[allow(unused)]
48pub struct NotThreadSafe(*const ());
49
50/// A small unique identifier, and handle, for an instance of a [View](crate::View).
51///
52/// Through this handle, you can access the associated view [ViewState](crate::view_state::ViewState).
53/// You can also use this handle to access the children ViewId's which allows you access to their states.
54///
55/// This type is not thread safe and can only be used from the main thread.
56#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
57#[repr(transparent)]
58pub struct ViewId(
59    pub(crate) slotmap::KeyData,
60    std::marker::PhantomData<NotThreadSafe>,
61);
62impl std::fmt::Debug for ViewId {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        let debug_name = self.debug_name();
65        let mut start = f.debug_struct("ViewId");
66
67        if !debug_name.is_empty() {
68            start.field("id", &self.0).field("debug_name", &debug_name)
69        } else {
70            start.field("id", &self.0)
71        }
72        .finish()
73    }
74}
75impl slotmap::__impl::From<slotmap::KeyData> for ViewId {
76    fn from(k: slotmap::KeyData) -> Self {
77        ViewId(k, std::marker::PhantomData)
78    }
79}
80unsafe impl slotmap::Key for ViewId {
81    fn data(&self) -> slotmap::KeyData {
82        self.0
83    }
84}
85
86fn request_structural_selector_restyle(children: &[ViewId]) {
87    for child in children {
88        child.request_style(StyleReason::full_recalc());
89    }
90}
91
92impl ViewId {
93    /// Create a new unique `Viewid`.
94    pub fn new() -> ViewId {
95        VIEW_STORAGE.with_borrow_mut(|s| {
96            let root = get_current_view();
97            let new = s.view_ids.insert(());
98            s.root.insert(new, root);
99            new
100        })
101    }
102
103    pub(crate) fn new_root() -> ViewId {
104        VIEW_STORAGE.with_borrow_mut(|s| {
105            let new = s.view_ids.insert(());
106            s.root.insert(new, new);
107            new
108        })
109    }
110
111    /// Get the chain of debug names that have been applied to this view.
112    ///
113    /// This uses try_borrow on the view state so if the view state has already been borrowed when using this method, it won't crash and it will just return an empty string.
114    pub fn debug_name(&self) -> String {
115        let state_names = self
116            .state()
117            .try_borrow()
118            .ok()
119            .map(|state| state.debug_name.iter().rev().cloned().collect::<Vec<_>>())
120            .unwrap_or_default();
121
122        let view_name = self
123            .view()
124            .try_borrow()
125            .ok()
126            .map(|view| View::debug_name(view.as_ref()).to_string())
127            .unwrap_or_default();
128
129        state_names
130            .into_iter()
131            .chain(std::iter::once(view_name))
132            .collect::<Vec<_>>()
133            .join(" - ")
134    }
135
136    /// Check if this ViewId is still valid (exists in VIEW_STORAGE).
137    ///
138    /// A ViewId becomes invalid when it has been removed from the view tree.
139    /// This is useful for filtering out stale ViewIds from collections.
140    pub fn is_valid(&self) -> bool {
141        VIEW_STORAGE.with_borrow(|s| s.view_ids.contains_key(*self))
142    }
143
144    /// Remove this view id and all of its children from the `VIEW_STORAGE`.
145    ///
146    /// Note: For full cleanup including taffy nodes and cleanup listeners,
147    /// use `window_state.remove_view()` or send an `UpdateMessage::RemoveViews`.
148    pub fn remove(&self) {
149        let element_id = self.get_element_id();
150        // Dispose children scope if this view had reactive children
151        if let Some(scope) = self.take_children_scope() {
152            scope.dispose();
153        }
154        // Dispose keyed children scopes if this view had keyed reactive children
155        if let Some(keyed_children) = self.take_keyed_children() {
156            for (_child_id, scope) in keyed_children {
157                scope.dispose();
158            }
159        }
160        // Get parent before removing, for stacking cache invalidation
161        let parent = self.parent();
162        VIEW_STORAGE.with_borrow_mut(|s| {
163            // remove the reverse mapping for taffy nodes
164            let taffy_node = s.state(*self).borrow().layout_id;
165            s.taffy_to_view.remove(&taffy_node);
166
167            // Remove the cached root, in the (unlikely) case that this view is
168            // re-added to a different window
169            s.root.remove(*self);
170            // Remove from overlays if registered
171            s.overlays.remove(*self);
172            // Remove self from parent's children list
173            if let Some(Some(parent)) = s.parent.get(*self)
174                && let Some(children) = s.children.get_mut(*parent)
175            {
176                children.retain(|c| c != self);
177            }
178            // Clean up all SecondaryMap entries for this view to prevent
179            // stale data when slots are reused. SecondaryMaps don't auto-clean
180            // when the primary SlotMap key is removed.
181            s.children.remove(*self);
182            s.parent.remove(*self);
183            s.states.remove(*self);
184            s.views.remove(*self);
185            // Remove from primary SlotMap last
186            s.view_ids.remove(*self);
187        });
188        // Invalidate this view and parent cache entries. During removal, using
189        // explicit IDs avoids relying on storage lookups that may already be detached.
190        let parent_element_id = parent.map(|p| p.get_element_id());
191        {
192            let _element_id = element_id;
193            let _parent_element_id = parent_element_id;
194            // Hit testing now uses Understory ordering directly and caches the result in event/path.rs.
195            // Any stacking-affecting change must invalidate both caches together.
196            crate::event::clear_hit_test_cache();
197        };
198    }
199
200    /// Register this view as an overlay.
201    ///
202    /// Overlays escape z-index constraints and are painted at the root level,
203    /// above all other views. The root is determined at registration time.
204    pub(crate) fn register_overlay(&self) {
205        let root_id = self.root();
206        VIEW_STORAGE.with_borrow_mut(|s| {
207            s.overlays.insert(*self, root_id);
208            if let Some(logical_parent_id) = s.parent.get(*self).and_then(|p| *p) {
209                let this_element_id = s.state(*self).borrow().element_id;
210                let parent_element_id =
211                    box_tree_parent_element_id_for_child(s, logical_parent_id, *self);
212                let box_tree = s.box_tree(*self);
213                box_tree
214                    .borrow_mut()
215                    .reparent(this_element_id.0, Some(parent_element_id.0));
216            }
217        });
218    }
219
220    /// Unregister this view as an overlay.
221    #[expect(dead_code)] // Kept for API symmetry with register_overlay
222    pub(crate) fn unregister_overlay(&self) {
223        VIEW_STORAGE.with_borrow_mut(|s| {
224            s.overlays.remove(*self);
225            if let Some(logical_parent_id) = s.parent.get(*self).and_then(|p| *p) {
226                let this_element_id = s.state(*self).borrow().element_id;
227                let parent_element_id = s.state(logical_parent_id).borrow().element_id;
228                let box_tree = s.box_tree(*self);
229                box_tree
230                    .borrow_mut()
231                    .reparent(this_element_id.0, Some(parent_element_id.0));
232            }
233        });
234    }
235
236    /// Get access to the layout tree tree
237    /// TODO: rename layout tree
238    pub fn taffy(&self) -> Rc<RefCell<LayoutTree>> {
239        VIEW_STORAGE.with_borrow_mut(|s| s.taffy.clone())
240    }
241
242    /// Get access to the box tree
243    pub fn box_tree(&self) -> Rc<RefCell<BoxTree>> {
244        VIEW_STORAGE.with_borrow_mut(|s| s.box_tree(*self))
245    }
246
247    /// Create a new taffy layout node
248    pub fn new_taffy_node(&self) -> NodeId {
249        self.taffy()
250            .borrow_mut()
251            .new_leaf(taffy::style::Style::DEFAULT)
252            .unwrap()
253    }
254
255    /// Set the layout properties on a taffy node
256    pub fn set_taffy_style(&self, node: NodeId, style: taffy::Style) {
257        let _ = self.taffy().borrow_mut().set_style(node, style);
258    }
259
260    /// Get the layout for a taffy node relative to it's parent
261    pub fn taffy_layout(&self, node: NodeId) -> Option<taffy::Layout> {
262        self.taffy().borrow().layout(node).cloned().ok()
263    }
264
265    /// Mark the taffy node associated with this view as dirty.
266    pub fn mark_view_layout_dirty(&self) -> taffy::TaffyResult<()> {
267        let node = self.taffy_node();
268        self.taffy().borrow_mut().mark_dirty(node)
269    }
270    /// Get the taffy node associated with this Id
271    pub fn taffy_node(&self) -> NodeId {
272        self.state().borrow().layout_id
273    }
274
275    /// set the transform on a view that is applied after style transforms
276    pub fn set_transform(&self, transform: Affine) {
277        self.state().borrow_mut().transform = transform;
278        self.request_box_tree_update_for_view();
279    }
280
281    pub(crate) fn state(&self) -> Rc<RefCell<ViewState>> {
282        VIEW_STORAGE.with_borrow_mut(|s| s.state(*self))
283    }
284
285    /// Get access to the View
286    pub(crate) fn view(&self) -> Rc<RefCell<Box<dyn View>>> {
287        VIEW_STORAGE.with_borrow(|s| {
288            s.views.get(*self).cloned().unwrap_or_else(|| {
289                // eprintln!("stale");
290                s.stale_view.clone()
291            })
292        })
293    }
294
295    /// Add a child View to this Id's list of children
296    pub fn add_child(&self, child: Box<dyn View>) {
297        let child_id = child.id();
298        let child_element_id = child_id.get_element_id();
299        VIEW_STORAGE.with_borrow_mut(|s| {
300            s.children.entry(*self).unwrap().or_default().push(child_id);
301            s.parent.insert(child_id, Some(*self));
302            s.views.insert(child_id, Rc::new(RefCell::new(child)));
303            let parent_element_id = box_tree_parent_element_id_for_child(s, *self, child_id);
304            s.box_tree(child_id)
305                .borrow_mut()
306                .reparent(child_element_id.0, Some(parent_element_id.0));
307            let child_taffy_node = s.state(child_id).borrow().layout_id;
308            let this_taffy_node = s.state(*self).borrow().layout_id;
309            let _ = s
310                .taffy
311                .borrow_mut()
312                .add_child(this_taffy_node, child_taffy_node);
313        });
314        // Re-parent child's scope under nearest ancestor's scope to match view hierarchy.
315        // This ensures scope hierarchy matches view hierarchy for proper cleanup.
316        reparent_scope_if_needed(child_id, *self);
317        request_structural_selector_restyle(&self.children());
318    }
319
320    /// Append multiple children to this Id's list of children.
321    ///
322    /// This is more efficient than calling `add_child` multiple times
323    /// as it only borrows VIEW_STORAGE once.
324    ///
325    /// Takes a `Vec` to ensure views are fully constructed before borrowing
326    /// VIEW_STORAGE, avoiding potential borrow conflicts.
327    pub fn append_children(&self, children: Vec<Box<dyn View>>) {
328        let child_ids: Vec<ViewId> = children.iter().map(|c| c.id()).collect();
329        VIEW_STORAGE.with_borrow_mut(|s| {
330            let this_taffy_node = s.state(*self).borrow().layout_id;
331            let child_element_ids: Vec<_> = children
332                .iter()
333                .map(|c| s.state(c.id()).borrow().element_id)
334                .collect();
335            let child_taffy_nodes: Vec<_> = children
336                .iter()
337                .map(|c| s.state(c.id()).borrow().layout_id)
338                .collect();
339
340            let box_tree = s.box_tree(*self);
341            let layout_tree = s.taffy.clone();
342
343            for ((child, child_element_id), child_taffy_node) in children
344                .into_iter()
345                .zip(child_element_ids)
346                .zip(child_taffy_nodes)
347            {
348                let child_id = child.id();
349                s.children.entry(*self).unwrap().or_default().push(child_id);
350                s.parent.insert(child_id, Some(*self));
351                s.views.insert(child_id, Rc::new(RefCell::new(child)));
352                let parent_element_id = box_tree_parent_element_id_for_child(s, *self, child_id);
353                box_tree
354                    .borrow_mut()
355                    .reparent(child_element_id.0, Some(parent_element_id.0));
356                let _ = layout_tree
357                    .borrow_mut()
358                    .add_child(this_taffy_node, child_taffy_node);
359            }
360        });
361        // Re-parent child scopes under nearest ancestor's scope
362        for child_id in child_ids {
363            reparent_scope_if_needed(child_id, *self);
364        }
365        request_structural_selector_restyle(&self.children());
366    }
367
368    /// Set the children views of this Id
369    /// See also [`Self::set_children_vec`]
370    pub fn set_children<const N: usize, V: IntoView>(&self, children: [V; N]) {
371        let children_ids: Vec<ViewId> = VIEW_STORAGE.with_borrow_mut(|s| {
372            let mut children_ids = Vec::new();
373            let mut children_nodes = Vec::with_capacity(children.len());
374            let box_tree = s.box_tree(*self);
375            let layout_tree = s.taffy.clone();
376            for child in children {
377                let child_view = child.into_view();
378                let child_view_id = child_view.id();
379                let child_element_id = s.state(child_view_id).borrow().element_id;
380                let child_taffy_node = s.state(child_view_id).borrow().layout_id;
381                children_nodes.push(child_taffy_node);
382                children_ids.push(child_view_id);
383                s.parent.insert(child_view_id, Some(*self));
384                s.views
385                    .insert(child_view_id, Rc::new(RefCell::new(child_view.into_any())));
386                let parent_element_id =
387                    box_tree_parent_element_id_for_child(s, *self, child_view_id);
388
389                box_tree
390                    .borrow_mut()
391                    .reparent(child_element_id.0, Some(parent_element_id.0));
392            }
393            s.children.insert(*self, children_ids.clone());
394            let this_taffy_node = s.state(*self).borrow().layout_id;
395            let _ = layout_tree
396                .borrow_mut()
397                .set_children(this_taffy_node, &children_nodes);
398            children_ids
399        });
400        // Re-parent child scopes under nearest ancestor's scope
401        for child_id in children_ids {
402            reparent_scope_if_needed(child_id, *self);
403        }
404        request_structural_selector_restyle(&self.children());
405    }
406
407    /// Set the children views of this Id using a Vector
408    /// See also [`Self::set_children`] and [`Self::set_children_iter`]
409    pub fn set_children_vec(&self, children: Vec<impl IntoView>) {
410        self.set_children_iter(children.into_iter().map(|c| c.into_any()));
411    }
412
413    /// Set the children views of this Id using an iterator of boxed views.
414    ///
415    /// This is the most efficient way to set children when you already have
416    /// an iterator of `Box<dyn View>`, as it avoids intermediate allocations.
417    ///
418    /// See also [`Self::set_children`] and [`Self::set_children_vec`]
419    pub fn set_children_iter(&self, children: impl Iterator<Item = Box<dyn View>>) {
420        let children_ids: Vec<ViewId> = VIEW_STORAGE.with_borrow_mut(|s| {
421            let mut children_ids = Vec::new();
422            let mut children_nodes = Vec::new();
423            let box_tree = s.box_tree(*self);
424            let layout_tree = s.taffy.clone();
425            for child_view in children {
426                let child_view_id = child_view.id();
427                let child_element_id = s.state(child_view_id).borrow().element_id;
428                let child_taffy_node = s.state(child_view_id).borrow().layout_id;
429                children_ids.push(child_view_id);
430                children_nodes.push(child_taffy_node);
431                s.parent.insert(child_view_id, Some(*self));
432                s.views
433                    .insert(child_view_id, Rc::new(RefCell::new(child_view)));
434                let parent_element_id =
435                    box_tree_parent_element_id_for_child(s, *self, child_view_id);
436                box_tree
437                    .borrow_mut()
438                    .reparent(child_element_id.0, Some(parent_element_id.0));
439            }
440            s.children.insert(*self, children_ids.clone());
441            let this_taffy_node = s.state(*self).borrow().layout_id;
442            let _ = layout_tree
443                .borrow_mut()
444                .set_children(this_taffy_node, &children_nodes);
445            children_ids
446        });
447        // Re-parent child scopes under nearest ancestor's scope
448        for child_id in children_ids {
449            reparent_scope_if_needed(child_id, *self);
450        }
451        request_structural_selector_restyle(&self.children());
452    }
453
454    /// Set the view that should be associated with this Id
455    pub fn set_view(&self, view: Box<dyn View>) {
456        VIEW_STORAGE.with_borrow_mut(|s| {
457            if s.view_ids.contains_key(*self) {
458                s.views.insert(*self, Rc::new(RefCell::new(view)));
459            }
460        });
461    }
462
463    /// Set the Id that should be used as the parent of this Id
464    pub fn set_parent(&self, parent: ViewId) {
465        VIEW_STORAGE.with_borrow_mut(|s| {
466            if s.view_ids.contains_key(*self) {
467                let this_element_id = s.state(*self).borrow().element_id;
468                s.parent.insert(*self, Some(parent));
469                let parent_element_id = box_tree_parent_element_id_for_child(s, parent, *self);
470                let box_tree = s.box_tree(*self);
471                box_tree
472                    .borrow_mut()
473                    .reparent(this_element_id.0, Some(parent_element_id.0));
474            }
475        });
476    }
477
478    /// Set the Ids that should be used as the children of this Id
479    pub fn set_children_ids(&self, children: Vec<ViewId>) {
480        VIEW_STORAGE.with_borrow_mut(|s| {
481            if !s.view_ids.contains_key(*self) {
482                return;
483            }
484
485            let this_taffy_node = s.state(*self).borrow().layout_id;
486
487            let child_element_ids: Vec<_> = children
488                .iter()
489                .map(|&child_id| s.state(child_id).borrow().element_id)
490                .collect();
491            let taffy_children: Vec<_> = children
492                .iter()
493                .map(|&child_id| s.state(child_id).borrow().layout_id)
494                .collect();
495
496            let box_tree = s.box_tree(*self);
497            let layout_tree = s.taffy.clone();
498            for (&child_id, child_element_id) in children.iter().zip(child_element_ids) {
499                s.parent.insert(child_id, Some(*self));
500                let parent_element_id = box_tree_parent_element_id_for_child(s, *self, child_id);
501                box_tree
502                    .borrow_mut()
503                    .reparent(child_element_id.0, Some(parent_element_id.0));
504            }
505
506            let _ = layout_tree
507                .borrow_mut()
508                .set_children(this_taffy_node, &taffy_children);
509            s.children.insert(*self, children);
510        });
511        request_structural_selector_restyle(&self.children());
512    }
513
514    /// Get the list of `ViewId`s that are associated with the children views of this `ViewId`
515    pub fn children(&self) -> Vec<ViewId> {
516        VIEW_STORAGE.with_borrow(|s| s.children.get(*self).cloned().unwrap_or_default())
517    }
518
519    /// Get access to the list of `ViewId`s that are associated with the children views of this `ViewId`
520    pub fn with_children<R>(&self, mut children: impl FnMut(&[ViewId]) -> R) -> R {
521        VIEW_STORAGE.with_borrow(|s| children(s.children.get(*self).map_or(&[], |v| v)))
522    }
523
524    /// Get the `ViewId` that has been set as this `ViewId`'s parent
525    pub fn parent(&self) -> Option<ViewId> {
526        VIEW_STORAGE.with_borrow(|s| s.parent.get(*self).cloned().flatten())
527    }
528
529    /// Get the root view of the window that the given view is in
530    pub fn root(&self) -> ViewId {
531        VIEW_STORAGE.with_borrow(|s| {
532            *s.root.get(*self).expect(
533                "all view ids are entered into the root map and have a root id upon creation",
534            )
535        })
536    }
537
538    /// try to get the root. use this if it is possible that the view has been deleted
539    pub(crate) fn try_root(&self) -> Option<ViewId> {
540        VIEW_STORAGE.with_borrow(|s| s.root.get(*self).copied())
541    }
542
543    /// Get the size of this View
544    pub fn get_size(&self) -> Option<Size> {
545        self.get_layout()
546            .map(|l| Size::new(l.size.width as f64, l.size.height as f64))
547    }
548
549    /// Get the Size of the parent View
550    pub fn parent_size(&self) -> Option<Size> {
551        let parent_id = self.parent()?;
552        parent_id.get_size()
553    }
554
555    /// This gets the Taffy Layout and adjusts it to be relative to the parent `View`.
556    pub fn get_layout(&self) -> Option<Layout> {
557        let widget_parent = self.parent().map(|id| id.state().borrow().layout_id);
558
559        let taffy = self.taffy();
560        let mut node = self.state().borrow().layout_id;
561        let mut layout = *taffy.borrow().layout(node).ok()?;
562
563        loop {
564            let parent = taffy.borrow().parent(node);
565
566            if parent == widget_parent {
567                break;
568            }
569
570            node = parent?;
571
572            layout.location = layout.location + taffy.borrow().layout(node).ok()?.location;
573        }
574
575        Some(layout)
576    }
577
578    /// Returns the [`Visualid`] associated with this view.
579    ///
580    /// This id can be used with the box tree.
581    pub fn get_element_id(&self) -> ElementId {
582        self.state().borrow().element_id
583    }
584
585    /// Returns the complete local-to-window coordinate transform.
586    ///
587    /// This transform converts coordinates from this view's local space to window
588    /// coordinates. It combines:
589    /// - The view's position in the window
590    /// - Any CSS transforms (scale, rotate)
591    ///
592    /// To convert a local point to window coordinates: `visual_transform * point`
593    /// To convert a window point to local coordinates: `visual_transform.inverse() * point`
594    ///
595    /// This is the transform used by event dispatch to convert pointer coordinates.
596    pub fn get_visual_transform(&self) -> peniko::kurbo::Affine {
597        let element_id = self.get_element_id();
598        VIEW_STORAGE.with_borrow_mut(|s| {
599            s.box_tree(*self)
600                .borrow_mut()
601                .world_transform(element_id.0)
602                .unwrap_or_default()
603        })
604    }
605
606    /// Return the world-space axis-aligned bounding box for this view.
607    ///
608    /// This is the loose AABB computed after applying local transforms and any active clips.
609    /// It fully contains the transformed bounds but may not be tight, especially under rotation
610    /// or rounded clips.
611    pub fn get_visual_rect(&self) -> Rect {
612        let element_id = self.get_element_id();
613        VIEW_STORAGE.with_borrow_mut(|s| {
614            s.box_tree(*self)
615                .borrow_mut()
616                .world_bounds(element_id.0)
617                .unwrap_or_default()
618        })
619    }
620
621    /// Return the local bounds in world coordinate space
622    pub fn get_visual_rect_no_clip(&self) -> Rect {
623        let element_id = self.get_element_id();
624        let transform = self.get_visual_transform();
625        VIEW_STORAGE.with_borrow_mut(|s| {
626            let box_tree = s.box_tree(*self);
627
628            transform.transform_rect_bbox(
629                box_tree
630                    .borrow()
631                    .local_bounds(element_id.0)
632                    .unwrap_or_default(),
633            )
634        })
635    }
636
637    /// Returns the view's visual position (after applying all clips clips and css transforms) in window coordinates.
638    pub fn get_visual_origin(&self) -> peniko::kurbo::Point {
639        let element_id = self.get_element_id();
640        VIEW_STORAGE
641            .with_borrow_mut(|s| {
642                s.box_tree(*self)
643                    .borrow_mut()
644                    .world_bounds(element_id.0)
645                    .unwrap_or_default()
646            })
647            .origin()
648    }
649
650    /// Returns the layout rect relative to the parent view.
651    ///
652    /// The position is relative to the parent view's origin. This is the raw layout
653    /// as computed by Taffy, useful for measuring and positioning views within their
654    /// parent's coordinate space.
655    pub fn get_layout_rect(&self) -> Rect {
656        self.get_layout()
657            .map(|l| Rect {
658                x0: f64::from(l.location.x),
659                y0: f64::from(l.location.y),
660                x1: f64::from(l.location.x + l.size.width),
661                y1: f64::from(l.location.y + l.size.height),
662            })
663            .unwrap_or_default()
664    }
665
666    /// Returns the content rect relative to the parent view.
667    ///
668    /// The content rect excludes borders and padding, representing the area where
669    /// content is positioned. The position is relative to the parent view's
670    /// origin.
671    pub fn get_content_rect(&self) -> Rect {
672        self.get_layout()
673            .map(|l| Rect {
674                x0: f64::from(l.content_box_x()),
675                y0: f64::from(l.content_box_y()),
676                x1: f64::from(l.content_box_x() + l.content_box_width()),
677                y1: f64::from(l.content_box_y() + l.content_box_height()),
678            })
679            .unwrap_or_default()
680    }
681
682    /// Returns the layout rect in the view's local coordinate space.
683    pub fn get_layout_rect_local(&self) -> Rect {
684        self.get_layout()
685            .map(|l| Rect {
686                x0: 0.0,
687                y0: 0.0,
688                x1: f64::from(l.size.width),
689                y1: f64::from(l.size.height),
690            })
691            .unwrap_or_default()
692    }
693
694    /// Returns the content rect in the view's local coordinate space.
695    ///
696    /// The content rect excludes borders and padding, representing the area where
697    /// child content should be positioned. This is in the view's local coordinate
698    /// space, with an offset that accounts for borders and padding.
699    ///
700    /// Like `layout_rect_local()`, this is in the same coordinate space as events
701    /// transformed via `window_event_to_view()`.
702    pub fn get_content_rect_local(&self) -> Rect {
703        self.get_layout()
704            .map(|r| {
705                let x0 = f64::from(r.border.left + r.padding.left);
706                let y0 = f64::from(r.border.top + r.padding.top);
707                let x1 = x0 + f64::from(r.content_box_width());
708                let y1 = y0 + f64::from(r.content_box_height());
709                Rect { x0, y0, x1, y1 }
710            })
711            .unwrap_or_default()
712    }
713
714    /// Returns the content rect of a child layout node, relative to the parent layout node's origin.
715    ///
716    /// This walks up the Taffy layout tree from `child_node` to `parent_node`, accumulating
717    /// the positions to compute the final relative content rect.
718    ///
719    /// Returns `None` if either node doesn't exist or if `child_node` is not a descendant of `parent_node`.
720    pub fn get_content_rect_relative(
721        &self,
722        child_node: taffy::NodeId,
723        parent_node: taffy::NodeId,
724    ) -> Option<Rect> {
725        let taffy = self.taffy();
726        let taffy = taffy.borrow();
727        let mut node = child_node;
728        let mut child_layout = *taffy.layout(node).ok()?;
729
730        // Accumulate position offsets from child up to parent
731        loop {
732            let current_parent = taffy.parent(node);
733
734            if current_parent == Some(parent_node) {
735                break;
736            }
737
738            node = current_parent?;
739            child_layout.location = child_layout.location + taffy.layout(node).ok()?.location;
740        }
741
742        // Build the content rect relative to the parent
743        Some(Rect::from_origin_size(
744            (
745                f64::from(child_layout.content_box_x()),
746                f64::from(child_layout.content_box_y()),
747            ),
748            (
749                f64::from(child_layout.content_box_width()),
750                f64::from(child_layout.content_box_height()),
751            ),
752        ))
753    }
754
755    /// Set a translation that will affect children.
756    ///
757    /// If you have a view that visually affects how far children should scroll, set it here.
758    pub fn set_child_translation(&self, child_translation: peniko::kurbo::Vec2) -> bool {
759        let state = self.state();
760        let needs_box_tree_update = {
761            let mut state = state.borrow_mut();
762            if state.child_translation != child_translation {
763                state.child_translation = child_translation;
764                true
765            } else {
766                false
767            }
768        };
769        if needs_box_tree_update {
770            for child in self.children() {
771                child.request_box_tree_update_for_view();
772            }
773        }
774        needs_box_tree_update
775    }
776
777    /// Get the translation that affects children
778    pub fn get_child_translation(&self) -> peniko::kurbo::Vec2 {
779        self.state().borrow().child_translation
780    }
781
782    /// set the clip rectange in local coordinates in the box tree
783    pub fn set_box_tree_clip(&self, clip: Option<RoundedRect>) {
784        let element_id = self.get_element_id();
785        VIEW_STORAGE.with_borrow_mut(|s| {
786            let box_tree = s.box_tree(*self);
787            box_tree.borrow_mut().set_local_clip(element_id.0, clip);
788        })
789    }
790
791    /// Returns true if this view is hidden.
792    pub fn is_hidden(&self) -> bool {
793        let state = self.state();
794        let state = state.borrow();
795        state.visibility.is_hidden()
796    }
797
798    /// if the view has pointer events none
799    pub fn pointer_events_none(&self) -> bool {
800        let state = self.state();
801        let state = state.borrow();
802        state
803            .computed_style
804            .builtin()
805            .pointer_events()
806            .map(|p| p == PointerEvents::None)
807            .unwrap_or(false)
808    }
809
810    /// Returns true if the view is disabled
811    ///
812    /// This is done by checking if the style for this view has `Disabled` set to true.
813    pub fn is_disabled(&self) -> bool {
814        self.state().borrow_mut().style_interaction_cx.disabled
815    }
816
817    /// Returns true if the view is selected
818    ///
819    /// This is done by checking if the parent has set this view as selected
820    /// via `parent_set_selected()`.
821    pub fn is_selected(&self) -> bool {
822        self.state().borrow().parent_set_style_interaction.selected
823    }
824
825    /// Check if this id can be focused.
826    ///
827    /// This is done by checking if the style for this view has `Focusable` set to `Focus::PointerAndProgramatic` or `Focus::KeyboardNavigable`.
828    pub fn can_focus(&self) -> bool {
829        self.state()
830            .borrow()
831            .computed_style
832            .get(Focusable)
833            .is_focusable()
834    }
835
836    /// Request that this the `id` view be styled, laid out and painted again.
837    /// This will recursively request this for all parents.
838    pub fn request_all(&self) {
839        add_update_message(UpdateMessage::RequestStyle(
840            self.get_element_id(),
841            StyleReason::full_recalc(),
842        ));
843        self.request_layout();
844        self.request_box_tree_commit();
845        self.add_update_message(UpdateMessage::RequestPaint);
846    }
847
848    /// Request that this view have it's layout pass run
849    pub fn request_layout(&self) {
850        add_update_message(UpdateMessage::RequestLayout);
851    }
852
853    /// Request that this view have it's taffy node be marked dirty
854    pub fn request_mark_view_layout_dirty(&self) {
855        add_update_message(UpdateMessage::MarkViewLayoutDirty(*self));
856    }
857
858    /// Request that the box tree be updated from the layout tree (full walk) and committed.
859    /// Use this after layout changes that affect the entire tree.
860    pub fn request_box_tree_update(&self) {
861        add_update_message(UpdateMessage::RequestBoxTreeUpdate);
862    }
863
864    /// Request that this specific view's box tree node be updated and committed.
865    /// This is more efficient than a full tree update when only this view changed
866    /// (e.g., after a transform or scroll offset change).
867    pub fn request_box_tree_update_for_view(&self) {
868        add_update_message(UpdateMessage::RequestBoxTreeUpdateForView(*self));
869    }
870
871    /// Request that the box tree be committed without updating from layout.
872    /// Use this when you've manually updated box tree nodes and just need to commit.
873    pub fn request_box_tree_commit(&self) {
874        add_update_message(UpdateMessage::RequestBoxTreeCommit);
875    }
876
877    /// Get the window id of the window containing this view, if there is one.
878    pub fn window_id(&self) -> Option<WindowId> {
879        window_id_for_root(self.root())
880    }
881
882    /// Request that this view have it's paint pass run
883    pub fn request_paint(&self) {
884        self.add_update_message(UpdateMessage::RequestPaint);
885    }
886
887    /// request that this node be styled again
888    pub fn request_style(&self, reason: StyleReason) {
889        self.add_update_message(UpdateMessage::RequestStyle(self.get_element_id(), reason));
890    }
891
892    /// Use this when you want the `view_style` method from the `View` trait to be rerun.
893    ///
894    // TODO: Add this to style reason set
895    #[deprecated(note = "use `id.request_style(StyleReasonSet::view_style())` directly instead")]
896    pub fn request_view_style(&self) {
897        self.request_style(StyleReason::view_style());
898    }
899
900    /// Request that this view gain the window focus
901    pub fn request_focus(&self) {
902        self.add_update_message(UpdateMessage::Focus(self.get_element_id()));
903    }
904
905    /// Clear the focus from this window
906    pub fn clear_focus(&self) {
907        self.add_update_message(UpdateMessage::ClearFocus);
908    }
909
910    /// Set the system context menu that should be shown when this view is right-clicked
911    pub fn update_context_menu(&self, menu: impl Fn() -> Menu + 'static) {
912        self.state().borrow_mut().context_menu = Some(Rc::new(menu));
913    }
914
915    /// Set the system popout menu that should be shown when this view is clicked
916    ///
917    /// Adds a primary-click context menu, which opens below the view.
918    pub fn update_popout_menu(&self, menu: impl Fn() -> Menu + 'static) {
919        self.state().borrow_mut().popout_menu = Some(Rc::new(menu));
920    }
921
922    // =========================================================================
923    // Pointer Capture API (W3C Pointer Events)
924    // =========================================================================
925    //
926
927    /// Set pointer capture for this view.
928    ///
929    /// When a view has pointer capture for a pointer, all subsequent pointer events
930    /// for that pointer are dispatched directly to this view, regardless of where
931    /// the pointer moves. This is useful for:
932    /// - Drag operations that should continue even when the pointer leaves the view
933    /// - Sliders and scrollbars that need to track pointer movement globally
934    /// - Any interaction that requires reliable pointer tracking
935    ///
936    /// The capture will be applied on the next pointer event for this pointer ID.
937    /// When capture is set:
938    /// - `GainedPointerCapture` event is fired to this view
939    /// - All subsequent pointer events for this pointer are routed here
940    /// - When released, `LostPointerCapture` event is fired
941    ///
942    /// Capture is automatically released on `PointerUp` for the captured pointer.
943    ///
944    /// # Example
945    /// ```ignore
946    /// fn event_before_children(&mut self, cx: &mut EventCx, event: &Event) -> EventPropagation {
947    ///     if let Event::Pointer(PointerEvent::Down(e)) = event {
948    ///         if let Some(pointer_id) = e.pointer.pointer_id {
949    ///             self.id().set_pointer_capture(pointer_id);
950    ///         }
951    ///     }
952    ///     EventPropagation::Continue
953    /// }
954    /// ```
955    pub fn set_pointer_capture(&self, pointer_id: PointerId) {
956        self.add_update_message(UpdateMessage::SetPointerCapture {
957            element_id: self.get_element_id(),
958            pointer_id,
959        });
960    }
961
962    /// Release pointer capture from this view.
963    ///
964    /// If this view has capture for the specified pointer, the capture will be
965    /// released on the next pointer event. A `LostPointerCapture` event will be
966    /// fired when the release takes effect.
967    ///
968    /// Note: This only releases capture if this view currently has it.
969    /// It's safe to call even if this view doesn't have capture.
970    pub fn release_pointer_capture(&self, pointer_id: PointerId) {
971        self.add_update_message(UpdateMessage::ReleasePointerCapture {
972            element_id: self.get_element_id(),
973            pointer_id,
974        });
975    }
976
977    /// Send a message to the application to open the Inspector for this Window
978    pub fn inspect(&self) {
979        self.add_update_message(UpdateMessage::Inspect);
980    }
981
982    /// Scrolls the view and all direct and indirect children to bring the view to be
983    /// visible. The optional rectangle can be used to add an additional offset and intersection.
984    pub fn scroll_to(&self, rect: Option<Rect>) {
985        self.add_update_message(UpdateMessage::ScrollTo {
986            id: self.get_element_id(),
987            rect,
988        });
989    }
990
991    pub(crate) fn transition_anim_complete(&self) {
992        self.add_update_message(UpdateMessage::ViewTransitionAnimComplete(*self));
993    }
994
995    pub(crate) fn update_animation(&self, offset: StackOffset<Animation>, animation: Animation) {
996        let state = self.state();
997        state.borrow_mut().animations.set(offset, animation);
998        self.request_style(StyleReason::animation());
999    }
1000
1001    pub(crate) fn update_animation_state(
1002        &self,
1003        offset: StackOffset<Animation>,
1004        command: AnimStateCommand,
1005    ) {
1006        let view_state = self.state();
1007        view_state
1008            .borrow_mut()
1009            .animations
1010            .update(offset, move |anim| anim.transition(command));
1011        self.request_style(StyleReason::animation());
1012    }
1013
1014    /// Send a state update to the `update` method of the associated View
1015    pub fn update_state(&self, state: impl Any) {
1016        self.add_update_message(UpdateMessage::State {
1017            id: *self,
1018            state: Box::new(state),
1019        });
1020    }
1021
1022    /// Add an callback on an action for a given `EventListener`
1023    pub(crate) fn add_event_listener(
1024        &self,
1025        listener: EventListenerKey,
1026        action: Box<EventCallback>,
1027        config: EventCallbackConfig,
1028    ) {
1029        add_update_message(crate::message::UpdateMessage::RegisterListener(
1030            listener, *self,
1031        ));
1032        let state = self.state();
1033        state
1034            .borrow_mut()
1035            .add_event_listener(listener, action, config);
1036    }
1037
1038    /// Set a callback that should be run when the view is removed from the view tree
1039    pub fn add_cleanup_listener(&self, action: Rc<dyn Fn()>) {
1040        let state = self.state();
1041        state.borrow_mut().add_cleanup_listener(action);
1042    }
1043
1044    /// Get the resolved style for this view (base + selectors + classes).
1045    ///
1046    /// This contains all style properties explicitly set on this view, including
1047    /// properties from applied classes and resolved selectors. It does NOT include
1048    /// inherited properties from ancestor views (like font_size, color, etc.).
1049    ///
1050    /// ## When to use
1051    /// Use `combined_style` when you need to know what this specific view defines:
1052    /// - Checking if THIS view explicitly sets a property
1053    /// - Computing what should propagate to children (class definitions)
1054    /// - Building cache keys for style resolution
1055    /// - Style resolution logic that shouldn't include inherited noise
1056    ///
1057    /// ## When NOT to use
1058    /// Do not use for rendering or layout - use `computed_style` instead (accessed
1059    /// via prop extractors in style_pass), which includes inherited properties and
1060    /// represents what the user will actually see.
1061    ///
1062    /// ## Warning
1063    /// The view styles do not store property transition states, only markers of which
1064    /// properties _should_ be transitioned over time on change.
1065    ///
1066    /// If you have a property that could be transitioned over time, make sure to use
1067    /// a [prop extractor](crate::prop_extractor) that is updated in a style method
1068    /// of the View to extract the property.
1069    pub fn get_combined_style(&self) -> Style {
1070        self.state().borrow().combined_style.clone()
1071    }
1072
1073    /// Add a class to the list of style classes that are associated with this `ViewId`
1074    pub fn add_class(&self, class: StyleClassRef) {
1075        let state = self.state();
1076        state.borrow_mut().classes.push(class);
1077        self.request_style(StyleReason::class_cx(smallvec![class]));
1078    }
1079
1080    /// Remove a class from the list of style classes that are associated with this `ViewId`
1081    pub fn remove_class(&self, class: StyleClassRef) {
1082        let state = self.state();
1083        state.borrow_mut().classes.retain_mut(|c| *c != class);
1084        self.request_style(StyleReason::class_cx(smallvec![class]));
1085    }
1086
1087    pub(crate) fn update_style(&self, offset: StackOffset<Style>, style: Style) {
1088        let state = VIEW_STORAGE.with_borrow(|s| s.states.get(*self).cloned());
1089        if let Some(state) = state {
1090            state.borrow_mut().style.set(offset, style);
1091            self.request_style(StyleReason::full_recalc());
1092        }
1093    }
1094
1095    /// Set the cursor.
1096    ///
1097    /// This will be overridden by any cursor set by view styles and will be overriden by cursors set on visual ids.
1098    pub fn set_cursor(&self, cursor: Option<crate::style::CursorStyle>) {
1099        self.state().borrow_mut().user_cursor = cursor;
1100    }
1101
1102    /// Disables the default view behavior for the specified event.
1103    ///
1104    /// Children will still see the event, but the view event function will not be called nor the event listeners on the view
1105    pub fn disable_default_event(&self, event: EventListenerKey) {
1106        self.state()
1107            .borrow_mut()
1108            .disable_default_events
1109            .insert(event);
1110    }
1111
1112    /// Re-enables the default view behavior for a previously disabled event.
1113    pub fn remove_disable_default_event(&self, event: EventListenerKey) {
1114        self.state()
1115            .borrow_mut()
1116            .disable_default_events
1117            .remove(&event);
1118    }
1119
1120    /// Alter the visibility of the current window the view represented by this ID
1121    /// is in.
1122    pub fn window_visible(&self, visible: bool) {
1123        self.add_update_message(UpdateMessage::WindowVisible(visible));
1124    }
1125
1126    /// Request removal of views during the update phase.
1127    ///
1128    /// This schedules the views to be removed with proper cleanup
1129    /// (cleanup listeners, taffy nodes, recursive children removal).
1130    /// Used by `keyed_children` for efficient keyed diffing.
1131    pub fn request_remove_views(&self, view_ids: Vec<ViewId>) {
1132        if !view_ids.is_empty() {
1133            self.add_update_message(UpdateMessage::RemoveViews(view_ids));
1134        }
1135    }
1136
1137    /// Queue a child to be added during the next update cycle.
1138    ///
1139    /// The child will be constructed when the message is processed. The scope
1140    /// is resolved at build time by looking up the parent's context scope in
1141    /// the view hierarchy, enabling proper context propagation.
1142    pub fn add_child_deferred(&self, child_fn: impl FnOnce() -> AnyView + 'static) {
1143        self.add_update_message(UpdateMessage::AddChild {
1144            parent_id: *self,
1145            child: DeferredChild::new(child_fn),
1146        });
1147    }
1148
1149    /// Queue multiple children to be added during the next update cycle.
1150    ///
1151    /// The children will be constructed when the message is processed. The scope
1152    /// is resolved at build time by looking up the parent's context scope in
1153    /// the view hierarchy, enabling proper context propagation.
1154    pub fn add_children_deferred(&self, children_fn: impl FnOnce() -> Vec<AnyView> + 'static) {
1155        self.add_update_message(UpdateMessage::AddChildren {
1156            parent_id: *self,
1157            children: DeferredChildren::new(children_fn),
1158        });
1159    }
1160
1161    /// Queue a reactive children setup to run during the next update cycle.
1162    ///
1163    /// The setup function will be called inside the view's scope (resolved via `find_scope()`)
1164    /// when the message is processed. This enables lazy setup of reactive children
1165    /// (derived_children, derived_child, keyed_children) inside the correct scope for context access.
1166    pub fn setup_reactive_children_deferred(&self, setup: impl FnOnce() + 'static) {
1167        self.add_update_message(UpdateMessage::SetupReactiveChildren {
1168            setup: DeferredReactiveSetup::new(*self, setup),
1169        });
1170    }
1171
1172    fn add_update_message(&self, msg: UpdateMessage) {
1173        let _ = CENTRAL_UPDATE_MESSAGES.try_with(|msgs| {
1174            let mut msgs = msgs.borrow_mut();
1175            msgs.push((*self, msg));
1176        });
1177    }
1178
1179    /// Send a state update that will be placed in deferred messages
1180    // TODO: what is the difference?
1181    pub fn update_state_deferred(&self, state: impl Any) {
1182        CENTRAL_DEFERRED_UPDATE_MESSAGES.with_borrow_mut(|msgs| {
1183            msgs.push((*self, Box::new(state)));
1184        });
1185    }
1186
1187    /// Get a layout in screen-coordinates for this view, if possible.
1188    pub fn screen_layout(&self) -> Option<ScreenLayout> {
1189        crate::layout::try_create_screen_layout(self)
1190    }
1191
1192    /// Set the custom style parent to make it so that a view will pull it's style context from a different parent.
1193    /// This is useful for overlays that are children of the window root but should pull their style cx from the creating view
1194    pub fn set_style_parent(&self, parent_id: ViewId) {
1195        self.state().borrow_mut().style_cx_parent = Some(parent_id);
1196    }
1197
1198    /// Clear the custom style parent
1199    pub fn clear_style_parent(&self) {
1200        self.state().borrow_mut().style_cx_parent = None;
1201    }
1202
1203    /// Set the children scope for reactive children.
1204    ///
1205    /// This stores the scope used by `ParentView::derived_children` so that
1206    /// when children are updated, the old scope can be properly disposed.
1207    pub fn set_children_scope(&self, scope: Scope) {
1208        self.state().borrow_mut().children_scope = Some(scope);
1209    }
1210
1211    /// Take and dispose the children scope, returning the old scope if it existed.
1212    ///
1213    /// This is called when reactive children are updated to clean up the old scope.
1214    pub fn take_children_scope(&self) -> Option<Scope> {
1215        self.state().borrow_mut().children_scope.take()
1216    }
1217
1218    /// Set the keyed children state for reactive keyed children.
1219    ///
1220    /// This stores the children and their scopes used by `ParentView::keyed_children`.
1221    /// Each child has its own scope that gets disposed when the child is removed.
1222    pub fn set_keyed_children(&self, children: Vec<(ViewId, Scope)>) {
1223        self.state().borrow_mut().keyed_children = Some(children);
1224    }
1225
1226    /// Take the keyed children state, returning it if it existed.
1227    ///
1228    /// This is called when keyed children are updated to apply diffs.
1229    pub fn take_keyed_children(&self) -> Option<Vec<(ViewId, Scope)>> {
1230        self.state().borrow_mut().keyed_children.take()
1231    }
1232
1233    /// Set the scope for this view.
1234    ///
1235    /// Views that provide context to children (like Combobox, Dialog, etc.) should
1236    /// call this in their `into_view()` to store their scope. This scope is then
1237    /// used when processing deferred children so they have access to the context.
1238    ///
1239    /// The scope hierarchy is kept in sync with the view hierarchy, so when
1240    /// a parent scope is disposed, all child scopes are also disposed.
1241    pub fn set_scope(&self, scope: Scope) {
1242        self.state().borrow_mut().scope = Some(scope);
1243    }
1244
1245    /// Get the scope for this view, if one was set.
1246    pub fn scope(&self) -> Option<Scope> {
1247        self.state().borrow().scope
1248    }
1249
1250    /// Find the nearest ancestor (including self) that has a scope.
1251    ///
1252    /// This walks up the view tree to find the first view with a scope,
1253    /// which should be used when building deferred children.
1254    pub fn find_scope(&self) -> Option<Scope> {
1255        // Check self first
1256        if let Some(scope) = self.scope() {
1257            return Some(scope);
1258        }
1259        // Walk up ancestors
1260        let mut current = self.parent();
1261        while let Some(parent_id) = current {
1262            if let Some(scope) = parent_id.scope() {
1263                return Some(scope);
1264            }
1265            current = parent_id.parent();
1266        }
1267        None
1268    }
1269
1270    /// get the local clip
1271    pub fn get_local_clip(&self) -> Option<RoundedRect> {
1272        let element_id = self.get_element_id();
1273        VIEW_STORAGE
1274            .with_borrow_mut(|s| {
1275                let box_tree = s.box_tree(*self);
1276                box_tree.borrow().local_clip(element_id.0)
1277            })
1278            .flatten()
1279    }
1280
1281    /// Create a visual that is a child of the current view.
1282    ///
1283    /// This will make it so that the visual id can receive events through the `ViewID`
1284    pub fn create_child_element_id(&self, z_index: i32) -> ElementId {
1285        let parent_box_node = self.get_element_id();
1286        VIEW_STORAGE.with_borrow_mut(|s| {
1287            let box_tree = s.box_tree(*self);
1288            let child_element_id = box_tree.borrow_mut().push_child(
1289                Some(parent_box_node.0),
1290                understory_box_tree::LocalNode::default(),
1291            );
1292            let element_id = ElementId(child_element_id, *self, false);
1293            box_tree
1294                .borrow_mut()
1295                .set_element_meta(child_element_id, Some(crate::ElementMeta::new(element_id)));
1296            box_tree.borrow_mut().set_z_index(child_element_id, z_index);
1297            element_id
1298        })
1299    }
1300
1301    /// Read focus navigation metadata for a specific element owned by this view.
1302    pub fn focus_nav_meta_for_element(&self, element_id: ElementId) -> Option<FocusNavMeta> {
1303        let box_tree = self.box_tree();
1304        box_tree.borrow().focus_nav_meta(element_id.0)
1305    }
1306
1307    /// Replace focus navigation metadata for a specific element.
1308    ///
1309    /// Returns `false` when the element is stale and no metadata was written.
1310    pub fn set_focus_nav_meta_for_element(
1311        &self,
1312        element_id: ElementId,
1313        focus: FocusNavMeta,
1314    ) -> bool {
1315        debug_assert_eq!(
1316            element_id.owning_id(),
1317            *self,
1318            "element must be owned by this view"
1319        );
1320        let box_tree = self.box_tree();
1321        let mut box_tree = box_tree.borrow_mut();
1322        if !box_tree.set_focus_nav_meta(element_id.0, focus) {
1323            return false;
1324        }
1325        crate::bump_focus_nav_meta_revision();
1326        true
1327    }
1328
1329    /// Set whether an owned element can receive focus at all.
1330    ///
1331    /// Clearing focusability also clears keyboard navigation.
1332    pub fn set_focusable_for_element(&self, element_id: ElementId, focusable: bool) -> bool {
1333        debug_assert_eq!(
1334            element_id.owning_id(),
1335            *self,
1336            "element must be owned by this view"
1337        );
1338        let box_tree = self.box_tree();
1339        let mut box_tree = box_tree.borrow_mut();
1340        if !box_tree.set_focusable(element_id.0, focusable) {
1341            return false;
1342        }
1343        crate::bump_focus_nav_meta_revision();
1344        true
1345    }
1346
1347    /// Set whether an owned element participates in keyboard traversal.
1348    ///
1349    /// Enabling keyboard navigation also enables focusability.
1350    pub fn set_keyboard_navigable_for_element(
1351        &self,
1352        element_id: ElementId,
1353        keyboard_navigable: bool,
1354    ) -> bool {
1355        debug_assert_eq!(
1356            element_id.owning_id(),
1357            *self,
1358            "element must be owned by this view"
1359        );
1360        let box_tree = self.box_tree();
1361        let mut box_tree = box_tree.borrow_mut();
1362        if !box_tree.set_keyboard_navigable(element_id.0, keyboard_navigable) {
1363            return false;
1364        }
1365        crate::bump_focus_nav_meta_revision();
1366        true
1367    }
1368
1369    /// Set or clear group membership used by keyboard focus traversal policies.
1370    pub fn set_focus_group_for_element(
1371        &self,
1372        element_id: ElementId,
1373        group: Option<understory_focus::FocusSymbol>,
1374    ) -> bool {
1375        let Some(mut focus) = self.focus_nav_meta_for_element(element_id) else {
1376            return false;
1377        };
1378        focus.group = group;
1379        self.set_focus_nav_meta_for_element(element_id, focus)
1380    }
1381
1382    /// Register this view to receive a specific event type.
1383    ///
1384    /// Views must register for events they want to receive through the broadcast
1385    /// dispatch system, such as [`LayoutChanged`](crate::context::LayoutChanged)
1386    /// or [`VisualChanged`](crate::context::VisualChanged).
1387    pub fn register_listener(&self, key: listener::EventListenerKey) {
1388        self.add_update_message(UpdateMessage::RegisterListener(key, *self));
1389    }
1390
1391    /// Unregister this view from receiving a specific event type.
1392    pub fn remove_listener(&self, key: listener::EventListenerKey) {
1393        self.add_update_message(UpdateMessage::RemoveListener(key, *self));
1394    }
1395
1396    pub(crate) fn get_layout_window_origin(&self) -> Point {
1397        let element_id = self.get_element_id();
1398        VIEW_STORAGE.with_borrow_mut(|s| {
1399            s.box_tree(*self)
1400                .borrow_mut()
1401                .world_transform(element_id.0)
1402                .unwrap_or_default()
1403                * Point::ZERO
1404        })
1405    }
1406
1407    /// Dispatch an event to this view using the specified routing strategy.
1408    ///
1409    /// This queues an event to be dispatched during the next event processing cycle.
1410    /// The event will be routed according to the `dispatch_kind` parameter.
1411    ///
1412    /// # Arguments
1413    ///
1414    /// * `event` - The event to dispatch
1415    /// * `dispatch_kind` - The routing strategy to use:
1416    ///   - `DispatchKind::Directed { target, phases }` - Routes to target with specified phases
1417    ///     - Use `Phases::all()` for full capture/bubble
1418    ///     - Use `Phases::TARGET` for direct dispatch only
1419    ///     - Use `Phases::BUBBLE` for bubble-only dispatch
1420    ///   - `DispatchKind::Spatial { point, phases }` - Routes based on hit testing at a point
1421    ///   - `DispatchKind::Subtree { target, stop }` - Routes to target and all descendants
1422    ///   - `DispatchKind::Focused { phases }` - Routes to currently focused view
1423    ///   - `DispatchKind::Global { stop }` - Broadcasts to all views
1424    ///
1425    /// # Examples
1426    ///
1427    /// ```rust
1428    /// # use floem::context::Phases;
1429    /// # use floem::event::{Event, InteractionEvent, RouteKind};
1430    /// # use floem::ViewId;
1431    /// # let view_id = ViewId::new();
1432    /// # let focused_view = view_id.get_element_id();
1433    /// // Dispatch a click directly to a specific view (target only, no propagation)
1434    /// view_id.route_event(
1435    ///     Event::Interaction(InteractionEvent::Click),
1436    ///     RouteKind::Directed {
1437    ///         target: view_id.get_element_id(),
1438    ///         phases: Phases::TARGET
1439    ///     }
1440    /// );
1441    ///
1442    /// // Dispatch a key event with full capture/bubble phases
1443    /// # if false {
1444    /// # let key_event = unimplemented!();
1445    /// # view_id.route_event(
1446    /// #     Event::Key(key_event),
1447    /// #     RouteKind::Directed {
1448    /// #         target: focused_view,
1449    /// #         phases: Phases::all()
1450    /// #     }
1451    /// # );
1452    /// # }
1453    /// ```
1454    pub fn route_event(&self, event: crate::event::Event, route_kind: RouteKind) {
1455        self.route_event_with_caused_by(event, route_kind, None);
1456    }
1457
1458    /// Dispatch an event with an optional causing event.
1459    ///
1460    /// This is similar to `dispatch_event`, but allows you to specify an event that caused
1461    /// this dispatch. The causing event will be available in the `EventCx::caused_by` field.
1462    ///
1463    /// # Arguments
1464    ///
1465    /// * `event` - The event to dispatch
1466    /// * `dispatch_kind` - The routing strategy to use
1467    /// * `caused_by` - An optional event that caused this dispatch (e.g., a PointerDown that caused a Click)
1468    pub fn route_event_with_caused_by(
1469        &self,
1470        event: crate::event::Event,
1471        route_kind: RouteKind,
1472        caused_by: Option<crate::event::Event>,
1473    ) {
1474        self.add_update_message(UpdateMessage::RouteEvent {
1475            id: self.get_element_id(),
1476            event: Box::new(event),
1477            route_kind,
1478            triggered_by: caused_by.map(Box::new),
1479        });
1480    }
1481}
1482
1483impl From<ViewId> for ElementId {
1484    fn from(value: ViewId) -> Self {
1485        value.get_element_id()
1486    }
1487}
1488
1489/// Re-parent a child view's scope under the nearest ancestor's scope.
1490///
1491/// This ensures that the Scope hierarchy matches the View hierarchy, which is
1492/// important for proper cleanup - when a parent scope is disposed, all child
1493/// scopes (and their signals/effects) are also disposed.
1494///
1495/// This handles the case where views are constructed eagerly (children created
1496/// before parents) - the scopes may have been created in the wrong order, so
1497/// we fix up the hierarchy when the view tree is assembled.
1498///
1499/// If the parent scope can't be found yet (because the view tree isn't fully
1500/// assembled), the child is added to a pending list and will be re-parented
1501/// later via `process_pending_scope_reparents`.
1502fn reparent_scope_if_needed(child_id: ViewId, parent_id: ViewId) {
1503    // Get child's scope (if it has one)
1504    let child_scope = child_id.scope();
1505    if let Some(child_scope) = child_scope {
1506        // Find the nearest ancestor with a scope
1507        if let Some(parent_scope) = parent_id.find_scope() {
1508            // Guard: Don't create a cycle if same scope is on both views
1509            if child_scope != parent_scope {
1510                // Re-parent child's scope under parent's scope
1511                child_scope.set_parent(parent_scope);
1512            }
1513        } else {
1514            // Parent scope not found yet - the view tree might not be fully assembled.
1515            // Add to pending list for later processing.
1516            PENDING_SCOPE_REPARENTS.with_borrow_mut(|pending| {
1517                pending.insert(child_id);
1518            });
1519        }
1520    }
1521}
1522
1523/// Process any views that had scope re-parenting deferred.
1524///
1525/// This should be called after the view tree is fully assembled (e.g., after
1526/// processing all update messages). It attempts to re-parent scopes that
1527/// couldn't find a parent scope when they were first added.
1528pub fn process_pending_scope_reparents() {
1529    // Fast path: skip if nothing pending (common case)
1530    let has_pending = PENDING_SCOPE_REPARENTS.with_borrow(|pending| !pending.is_empty());
1531    if !has_pending {
1532        return;
1533    }
1534
1535    PENDING_SCOPE_REPARENTS.with_borrow_mut(|pending| {
1536        pending.retain(|child_id| {
1537            // First check if this ViewId is still valid (not from a disposed view/window)
1538            // This is important for parallel test isolation
1539            if !child_id.is_valid() {
1540                return false; // Remove stale ViewId from pending
1541            }
1542
1543            // Check if view still exists and has a scope
1544            let child_scope = child_id.scope();
1545            if let Some(child_scope) = child_scope {
1546                // Try to find a parent scope by walking up from the parent
1547                if let Some(parent_id) = child_id.parent()
1548                    && let Some(parent_scope) = parent_id.find_scope()
1549                {
1550                    // Guard: Don't create a cycle if same scope is on both views
1551                    if child_scope != parent_scope {
1552                        child_scope.set_parent(parent_scope);
1553                    }
1554                    return false; // Successfully handled, remove from pending
1555                }
1556                true // Still pending, keep in the set
1557            } else {
1558                false // No scope, remove from pending
1559            }
1560        });
1561    });
1562}
1563
1564fn box_tree_parent_element_id_for_child(
1565    storage: &mut ViewStorage,
1566    logical_parent_id: ViewId,
1567    child_id: ViewId,
1568) -> ElementId {
1569    if storage.overlays.contains_key(child_id) {
1570        let root_id = *storage
1571            .root
1572            .get(child_id)
1573            .expect("all view ids are created with a root");
1574        storage.state(root_id).borrow().element_id
1575    } else {
1576        storage.state(logical_parent_id).borrow().element_id
1577    }
1578}
1579
1580impl ViewId {
1581    /// Set the selected state for child views during styling.
1582    /// This should be used by parent views to propagate selected state to their children.
1583    /// Only requests a style update if the state actually changes.
1584    pub fn parent_set_selected(&self) {
1585        let changed = {
1586            let state = self.state();
1587            let mut state = state.borrow_mut();
1588            if !state.parent_set_style_interaction.selected {
1589                state.parent_set_style_interaction.selected = true;
1590                true
1591            } else {
1592                false
1593            }
1594        };
1595        if changed {
1596            self.request_style(StyleReason::with_selector(StyleSelector::Selected));
1597        }
1598    }
1599
1600    /// Clear the selected state for child views during styling.
1601    /// This should be used by parent views to clear selected state propagation to their children.
1602    /// Only requests a style update if the state actually changes.
1603    pub fn parent_clear_selected(&self) {
1604        let changed = {
1605            let state = self.state();
1606            let mut state = state.borrow_mut();
1607            if state.parent_set_style_interaction.selected {
1608                state.parent_set_style_interaction.selected = false;
1609                true
1610            } else {
1611                false
1612            }
1613        };
1614        if changed {
1615            self.request_style(StyleReason::with_selector(StyleSelector::Selected));
1616        }
1617    }
1618
1619    /// Set the disabled state for child views during styling.
1620    /// This should be used by parent views to propagate disabled state to their children.
1621    /// Only requests a style update if the state actually changes.
1622    pub fn parent_set_disabled(&self) {
1623        let changed = {
1624            let state = self.state();
1625            let mut state = state.borrow_mut();
1626            if !state.parent_set_style_interaction.disabled {
1627                state.parent_set_style_interaction.disabled = true;
1628                true
1629            } else {
1630                false
1631            }
1632        };
1633        if changed {
1634            self.request_style(StyleReason::with_selector(StyleSelector::Disabled));
1635        }
1636    }
1637
1638    /// Clear the disabled state for child views during styling.
1639    /// This should be used by parent views to clear disabled state propagation to their children.
1640    /// Only requests a style update if the state actually changes.
1641    pub fn parent_clear_disabled(&self) {
1642        let changed = {
1643            let state = self.state();
1644            let mut state = state.borrow_mut();
1645            if state.parent_set_style_interaction.disabled {
1646                state.parent_set_style_interaction.disabled = false;
1647                true
1648            } else {
1649                false
1650            }
1651        };
1652        if changed {
1653            self.request_style(StyleReason::with_selector(StyleSelector::Disabled));
1654        }
1655    }
1656
1657    /// Hide this view from layout. Sets the parent set visibility state directly.
1658    /// Skips the normal transition animation logic.
1659    /// This should be used by parent views to set hidden state propagation to their children.
1660    /// Only requests a style update if the state actually changes.
1661    pub fn set_hidden(&self) {
1662        use crate::view::state::VisibilityPhase;
1663        let changed = {
1664            let state = self.state();
1665            let mut state = state.borrow_mut();
1666            if !state.parent_set_style_interaction.hidden {
1667                state.parent_set_style_interaction.hidden = true;
1668                state.visibility.phase = VisibilityPhase::Hidden;
1669                true
1670            } else {
1671                false
1672            }
1673        };
1674        if changed {
1675            self.request_style(StyleReason::visibility());
1676        }
1677    }
1678
1679    /// Show this view in layout. Clears the parent set hidden state.
1680    /// This should be used by parent views to clear hidden state propagation to their children.
1681    /// Only requests a style update if the state actually changes.
1682    pub fn set_visible(&self) {
1683        use crate::view::state::VisibilityPhase;
1684        let changed = {
1685            let state = self.state();
1686            let mut state = state.borrow_mut();
1687            if state.parent_set_style_interaction.hidden {
1688                state.parent_set_style_interaction.hidden = false;
1689                // Reset phase to Initial so the normal transition logic can run
1690                state.visibility.phase = VisibilityPhase::Initial;
1691                true
1692            } else {
1693                false
1694            }
1695        };
1696        if changed {
1697            self.request_style(StyleReason::visibility());
1698        }
1699    }
1700}