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