zng_app/widget/
info.rs

1//! Widget info tree.
2
3use std::{borrow::Cow, fmt, mem, ops, sync::Arc, time::Duration};
4
5pub mod access;
6
7mod tree;
8use parking_lot::{MappedMutexGuard, Mutex, MutexGuard, RwLock};
9use tree::Tree;
10
11mod path;
12pub use path::*;
13
14mod builder;
15pub use builder::*;
16
17pub mod iter;
18pub use iter::TreeFilter;
19
20mod hit;
21pub(crate) use hit::{HitTestClips, ParallelSegmentOffsets};
22use zng_clone_move::clmv;
23use zng_layout::{
24    context::{LayoutMask, LayoutMetricsSnapshot},
25    unit::{
26        DistanceKey, Factor, FactorUnits, Orientation2D, Px, PxBox, PxCornerRadius, PxPoint, PxRect, PxSideOffsets, PxSize, PxTransform,
27        PxVector, euclid,
28    },
29};
30use zng_state_map::{OwnedStateMap, StateMapRef};
31use zng_txt::{Txt, formatx};
32use zng_unique_id::IdMap;
33use zng_var::impl_from_and_into_var;
34use zng_view_api::{ViewProcessGen, display_list::FrameValueUpdate, window::FrameId};
35
36use crate::{DInstant, render::TransformStyle, window::WindowId};
37
38pub use self::hit::RelativeHitZ;
39use self::{access::AccessEnabled, hit::ParallelSegmentId, iter::TreeIterator};
40
41use super::{WidgetId, node::ZIndex};
42
43/// Stats over the lifetime of a widget info tree.
44///
45/// The stats for a tree are available in [`WidgetInfoTree::stats`].
46#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
47#[non_exhaustive]
48pub struct WidgetInfoTreeStats {
49    /// Number of times info was rebuild for the window.
50    pub generation: u32,
51
52    /// Duration of the [`UiNode::info`] call for the window content.
53    ///
54    /// [`UiNode::info`]: crate::widget::node::UiNode::info
55    pub build_time: Duration,
56
57    /// Count of widgets that where reused from a previous tree.
58    pub reused_widgets: u32,
59
60    /// Last window frame that rendered this tree.
61    ///
62    /// Before the first render this is `FrameId::INVALID`.
63    pub last_frame: FrameId,
64
65    /// Last window frame that moved or resized the inner bounds of at least one widget.
66    pub bounds_updated_frame: FrameId,
67
68    /// Count of moved or resized widgets in the last `bounds_updated_frame`.
69    pub bounds_updated: u32,
70
71    /// Last window frame that changed visibility of at least one widget.
72    pub vis_updated_frame: FrameId,
73}
74impl WidgetInfoTreeStats {
75    fn new(build_start: DInstant, reused_widgets: u32, generation: u32) -> Self {
76        Self {
77            generation,
78            build_time: build_start.elapsed(),
79            reused_widgets,
80            last_frame: FrameId::INVALID,
81            bounds_updated_frame: FrameId::INVALID,
82            bounds_updated: 0,
83            vis_updated_frame: FrameId::INVALID,
84        }
85    }
86
87    fn update(&mut self, frame: FrameId, update: WidgetInfoTreeStatsUpdate) {
88        self.last_frame = frame;
89
90        if update.bounds_updated > 0 {
91            self.bounds_updated = update.bounds_updated;
92            self.bounds_updated_frame = frame;
93        } else if self.bounds_updated_frame == FrameId::INVALID {
94            self.bounds_updated_frame = frame;
95        }
96
97        // we don't show `vis_updated` because if can be counted twice when visibility changes from collapsed.
98        if update.vis_updated > 0 || self.vis_updated_frame == FrameId::INVALID {
99            self.vis_updated_frame = frame;
100        }
101    }
102}
103#[derive(Default)]
104struct WidgetInfoTreeStatsUpdate {
105    bounds_updated: u32,
106    vis_updated: u32,
107}
108impl WidgetInfoTreeStatsUpdate {
109    fn take(&mut self) -> Self {
110        mem::take(self)
111    }
112}
113
114/// Weak reference to a [`WidgetInfoTree`].
115#[derive(Clone, Debug, Default)]
116pub struct WeakWidgetInfoTree(std::sync::Weak<WidgetInfoTreeInner>);
117impl WeakWidgetInfoTree {
118    /// New without allocating any memory.
119    pub const fn new() -> Self {
120        Self(std::sync::Weak::new())
121    }
122
123    /// Attempt to upgrade to a strong reference to the widget tree.
124    pub fn upgrade(&self) -> Option<WidgetInfoTree> {
125        self.0.upgrade().map(WidgetInfoTree)
126    }
127}
128impl PartialEq for WeakWidgetInfoTree {
129    fn eq(&self, other: &Self) -> bool {
130        self.0.ptr_eq(&other.0)
131    }
132}
133impl Eq for WeakWidgetInfoTree {}
134
135/// A tree of [`WidgetInfo`].
136///
137/// The tree is behind an `Arc` pointer so cloning and storing this type is very cheap.
138///
139/// Instantiated using [`WidgetInfoBuilder`].
140#[derive(Clone)]
141pub struct WidgetInfoTree(Arc<WidgetInfoTreeInner>);
142struct WidgetInfoTreeInner {
143    window_id: WindowId,
144    access_enabled: AccessEnabled,
145    tree: Tree<WidgetInfoData>,
146    lookup: IdMap<WidgetId, tree::NodeId>,
147    interactivity_filters: InteractivityFilters,
148    build_meta: Arc<OwnedStateMap<WidgetInfoMeta>>,
149    frame: RwLock<WidgetInfoTreeFrame>,
150}
151// info that updates every frame
152struct WidgetInfoTreeFrame {
153    stats: WidgetInfoTreeStats,
154    stats_update: WidgetInfoTreeStatsUpdate,
155    out_of_bounds_update: Vec<(tree::NodeId, bool)>,
156    scale_factor: Factor,
157    view_process_gen: ViewProcessGen,
158
159    out_of_bounds: Arc<Vec<tree::NodeId>>,
160    spatial_bounds: PxBox,
161
162    widget_count_offsets: ParallelSegmentOffsets,
163
164    transform_changed_subs: IdMap<WidgetId, PxTransform>,
165    visibility_changed_subs: IdMap<WidgetId, Visibility>,
166}
167impl PartialEq for WidgetInfoTree {
168    fn eq(&self, other: &Self) -> bool {
169        Arc::ptr_eq(&self.0, &other.0)
170    }
171}
172impl Eq for WidgetInfoTree {}
173impl WidgetInfoTree {
174    /// Blank window that contains only the root widget taking no space.
175    pub fn wgt(window_id: WindowId, root_id: WidgetId) -> Self {
176        WidgetInfoBuilder::new(
177            Arc::default(),
178            window_id,
179            AccessEnabled::empty(),
180            root_id,
181            WidgetBoundsInfo::new(),
182            WidgetBorderInfo::new(),
183            1.fct(),
184        )
185        .finalize(None, false)
186    }
187
188    /// Statistics abound the info tree.
189    pub fn stats(&self) -> WidgetInfoTreeStats {
190        self.0.frame.read().stats.clone()
191    }
192
193    /// Scale factor of the last rendered frame.
194    pub fn scale_factor(&self) -> Factor {
195        self.0.frame.read().scale_factor
196    }
197
198    /// View-process generation.
199    ///
200    /// Is [`ViewProcessGen::INVALID`] before first render and in headless apps.
201    ///
202    /// [`ViewProcessGen::INVALID`]: zng_view_api::ViewProcessGen::INVALID
203    pub fn view_process_gen(&self) -> ViewProcessGen {
204        self.0.frame.read().view_process_gen
205    }
206
207    /// Custom metadata associated with the tree during info build.
208    ///
209    /// Any widget (that was not reused) can have inserted metadata.
210    pub fn build_meta(&self) -> StateMapRef<'_, WidgetInfoMeta> {
211        self.0.build_meta.borrow()
212    }
213
214    /// Reference to the root widget in the tree.
215    pub fn root(&self) -> WidgetInfo {
216        WidgetInfo::new(self.clone(), self.0.tree.root().id())
217    }
218
219    /// All widgets including `root`.
220    pub fn all_widgets(&self) -> iter::TreeIter {
221        self.root().self_and_descendants()
222    }
223
224    /// Id of the window that owns all widgets represented in the tree.
225    pub fn window_id(&self) -> WindowId {
226        self.0.window_id
227    }
228
229    /// Reference to the widget in the tree, if it is present.
230    pub fn get(&self, widget_id: impl Into<WidgetId>) -> Option<WidgetInfo> {
231        self.0.lookup.get(&widget_id.into()).map(|i| WidgetInfo::new(self.clone(), *i))
232    }
233
234    /// If the tree contains the widget.
235    pub fn contains(&self, widget_id: impl Into<WidgetId>) -> bool {
236        self.0.lookup.contains_key(&widget_id.into())
237    }
238
239    /// Reference to the widget or first parent that is present.
240    pub fn get_or_parent(&self, path: &WidgetPath) -> Option<WidgetInfo> {
241        self.get(path.widget_id())
242            .or_else(|| path.ancestors().iter().rev().find_map(|&id| self.get(id)))
243    }
244
245    /// If the widgets in this tree have been rendered at least once, after the first render the widget bounds info are always up-to-date
246    /// and spatial queries can be made on the widgets.
247    pub fn is_rendered(&self) -> bool {
248        self.0.frame.read().stats.last_frame != FrameId::INVALID
249    }
250
251    /// Iterator over all widgets with inner-bounds not fully contained by their parent inner bounds.
252    pub fn out_of_bounds(&self) -> impl std::iter::ExactSizeIterator<Item = WidgetInfo> + 'static + use<> {
253        let out = self.0.frame.read().out_of_bounds.clone();
254        let me = self.clone();
255        (0..out.len()).map(move |i| WidgetInfo::new(me.clone(), out[i]))
256    }
257
258    /// Gets the bounds box that envelops all widgets, including the out-of-bounds widgets.
259    pub fn spatial_bounds(&self) -> PxRect {
260        self.0.frame.read().spatial_bounds.to_rect()
261    }
262
263    /// Total number of widgets in the tree.
264    ///
265    /// Is never zero, every tree has at least the root widget.
266    #[expect(clippy::len_without_is_empty)]
267    pub fn len(&self) -> usize {
268        self.0.lookup.len()
269    }
270
271    fn bounds_changed(&self) {
272        self.0.frame.write().stats_update.bounds_updated += 1;
273    }
274
275    fn in_bounds_changed(&self, widget_id: WidgetId, in_bounds: bool) {
276        let id = *self.0.lookup.get(&widget_id).unwrap();
277        self.0.frame.write().out_of_bounds_update.push((id, in_bounds));
278    }
279
280    fn visibility_changed(&self) {
281        self.0.frame.write().stats_update.vis_updated += 1;
282    }
283
284    pub(crate) fn after_render(
285        &self,
286        frame_id: FrameId,
287        scale_factor: Factor,
288        view_process_gen: Option<ViewProcessGen>,
289        widget_count_offsets: Option<ParallelSegmentOffsets>,
290        notify: bool,
291    ) {
292        let mut frame = self.0.frame.write();
293        let stats_update = frame.stats_update.take();
294
295        let mut any_update = stats_update.bounds_updated > 0 || stats_update.vis_updated > 0;
296
297        frame.stats.update(frame_id, stats_update);
298
299        if !frame.out_of_bounds_update.is_empty() {
300            any_update = true;
301
302            // update out-of-bounds list, reuses the same vec most of the time,
303            // unless a spatial iter was generated and not dropped before render.
304
305            let mut out_of_bounds = Arc::try_unwrap(mem::take(&mut frame.out_of_bounds)).unwrap_or_else(|rc| (*rc).clone());
306
307            for (id, remove) in frame.out_of_bounds_update.drain(..) {
308                if remove {
309                    if let Some(i) = out_of_bounds.iter().position(|i| *i == id) {
310                        out_of_bounds.swap_remove(i);
311                    }
312                } else {
313                    out_of_bounds.push(id);
314                }
315            }
316            frame.out_of_bounds = Arc::new(out_of_bounds);
317        }
318
319        let mut spatial_bounds = self.root().outer_bounds().to_box2d();
320        for out in frame.out_of_bounds.iter() {
321            let b = WidgetInfo::new(self.clone(), *out).inner_bounds().to_box2d();
322            spatial_bounds = spatial_bounds.union(&b);
323        }
324        any_update = any_update || frame.spatial_bounds != spatial_bounds;
325        frame.spatial_bounds = spatial_bounds;
326
327        any_update = any_update || frame.scale_factor != scale_factor;
328        frame.scale_factor = scale_factor;
329
330        if let Some(vp_gen) = view_process_gen {
331            any_update = any_update || frame.view_process_gen != vp_gen;
332
333            frame.view_process_gen = vp_gen;
334        }
335        if let Some(w) = widget_count_offsets {
336            any_update = any_update || frame.widget_count_offsets != w;
337
338            frame.widget_count_offsets = w;
339        }
340
341        if notify && any_update {
342            WIDGET_TREE_CHANGED_EVENT.notify(WidgetTreeChangedArgs::now(self.downgrade(), self.clone(), true));
343        }
344    }
345
346    pub(crate) fn after_render_update(&self, frame_id: FrameId, notify: bool) {
347        let scale_factor = self.0.frame.read().scale_factor;
348        self.after_render(frame_id, scale_factor, None, None, notify);
349    }
350
351    /// Create a weak reference to this tree.
352    pub fn downgrade(&self) -> WeakWidgetInfoTree {
353        WeakWidgetInfoTree(Arc::downgrade(&self.0))
354    }
355}
356impl fmt::Debug for WidgetInfoTree {
357    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358        f.debug_struct("WidgetInfoTree")
359            .field("len()", &self.len())
360            .field("spatial_bounds()", &self.spatial_bounds())
361            .field("stats()", &self.stats())
362            .finish_non_exhaustive()
363    }
364}
365
366#[derive(Debug, Default)]
367struct WidgetBoundsData {
368    inner_offset: PxVector,
369    child_offset: PxVector,
370    parent_child_offset: PxVector,
371
372    inline: Option<WidgetInlineInfo>,
373    measure_inline: Option<WidgetInlineMeasure>,
374
375    measure_outer_size: PxSize,
376    outer_size: PxSize,
377    inner_size: PxSize,
378    baseline: Px,
379    inner_offset_baseline: bool,
380
381    transform_style: TransformStyle,
382    perspective: f32,
383    perspective_origin: Option<PxPoint>,
384
385    measure_metrics: Option<LayoutMetricsSnapshot>,
386    measure_metrics_used: LayoutMask,
387    metrics: Option<LayoutMetricsSnapshot>,
388    metrics_used: LayoutMask,
389
390    outer_transform: PxTransform,
391    inner_transform: PxTransform,
392    rendered: Option<WidgetRenderInfo>,
393
394    outer_bounds: PxRect,
395    inner_bounds: PxRect,
396
397    hit_clips: HitTestClips,
398    hit_index: hit::HitChildIndex,
399
400    is_in_bounds: Option<bool>,
401    is_partially_culled: bool,
402    cannot_auto_hide: bool,
403    is_collapsed: bool,
404}
405
406/// Widget render data.
407#[derive(Debug, Clone, Copy)]
408pub(crate) struct WidgetRenderInfo {
409    // Visible/hidden.
410    pub visible: bool,
411
412    pub parent_perspective: Option<(f32, PxPoint)>,
413
414    // raw z-index in widget_count units.
415    pub seg_id: ParallelSegmentId,
416    pub back: usize,
417    pub front: usize,
418}
419
420/// Shared reference to layout size, offsets, rendered transforms and bounds of a widget.
421///
422/// Can be retrieved in the [`WIDGET`] and [`WidgetInfo`].
423///
424/// [`WIDGET`]: crate::widget::WIDGET
425#[derive(Default, Clone, Debug)]
426pub struct WidgetBoundsInfo(Arc<Mutex<WidgetBoundsData>>);
427impl PartialEq for WidgetBoundsInfo {
428    fn eq(&self, other: &Self) -> bool {
429        Arc::ptr_eq(&self.0, &other.0)
430    }
431}
432impl Eq for WidgetBoundsInfo {}
433impl WidgetBoundsInfo {
434    /// New default.
435    pub fn new() -> Self {
436        Self::default()
437    }
438
439    /// New info with bound sizes known.
440    pub fn new_size(outer: PxSize, inner: PxSize) -> Self {
441        let me = Self::new();
442        me.set_outer_size(outer);
443        me.set_inner_size(inner);
444        me
445    }
446
447    /// Gets the widget's last measured outer bounds size.
448    ///
449    /// This size is expected to be the same if the widget is layout using the same exact parameters it was measured.
450    pub fn measure_outer_size(&self) -> PxSize {
451        self.0.lock().measure_outer_size
452    }
453
454    /// Gets the widget's last layout outer bounds size.
455    pub fn outer_size(&self) -> PxSize {
456        self.0.lock().outer_size
457    }
458
459    /// Gets the widget's inner bounds offset inside the outer bounds.
460    ///
461    /// If [`inner_offset_baseline`] is `true` the [`baseline`] is added from this value.
462    ///
463    /// [`inner_offset_baseline`]: Self::baseline
464    /// [`baseline`]: Self::baseline
465    pub fn inner_offset(&self) -> PxVector {
466        let mut r = self.0.lock().inner_offset;
467        if self.inner_offset_baseline() {
468            r.y += self.baseline();
469        }
470        r
471    }
472
473    /// If the [`baseline`] is added from the [`inner_offset`].
474    ///
475    /// [`baseline`]: Self::baseline
476    /// [`inner_offset`]: Self::inner_offset
477    pub fn inner_offset_baseline(&self) -> bool {
478        self.0.lock().inner_offset_baseline
479    }
480
481    /// Gets the widget's child offset inside the inner bounds.
482    ///
483    /// If the widget's child is another widget this is zero and the offset is set on that child's [`parent_child_offset`] instead.
484    ///
485    /// [`parent_child_offset`]: Self::parent_child_offset
486    pub fn child_offset(&self) -> PxVector {
487        self.0.lock().child_offset
488    }
489
490    /// Gets the widget's inner bounds size.
491    pub fn inner_size(&self) -> PxSize {
492        self.0.lock().inner_size
493    }
494
495    /// The baseline offset up from the inner bounds bottom line.
496    ///
497    /// Note that if [`inner_offset_baseline`] is `true` the [`inner_offset`] is already added by the baseline. Parent
498    /// panel widgets implementing baseline offset must use the [`final_baseline`] value to avoid offsetting more then once.
499    ///
500    /// [`inner_offset_baseline`]: Self::inner_offset_baseline
501    /// [`inner_offset`]: Self::inner_offset
502    /// [`final_baseline`]: Self::final_baseline
503    pub fn baseline(&self) -> Px {
504        self.0.lock().baseline
505    }
506
507    /// Gets the baseline offset of the widget after [`inner_offset`] is applied.
508    ///
509    /// Returns `Px(0)` if [`inner_offset_baseline`], otherwise returns [`baseline`].
510    ///
511    /// [`inner_offset`]: Self::inner_offset
512    /// [`inner_offset_baseline`]: Self::inner_offset_baseline
513    /// [`baseline`]: Self::baseline
514    pub fn final_baseline(&self) -> Px {
515        let s = self.0.lock();
516        if s.inner_offset_baseline { Px(0) } else { s.baseline }
517    }
518
519    /// Gets the global transform of the widget's outer bounds during the last render or render update.
520    pub fn outer_transform(&self) -> PxTransform {
521        self.0.lock().outer_transform
522    }
523
524    /// Offset rendered in the widget inner set by the parent widget.
525    ///
526    /// Note that this offset is applied to the [`outer_transform`](Self::outer_transform) already.
527    pub fn parent_child_offset(&self) -> PxVector {
528        self.0.lock().parent_child_offset
529    }
530
531    /// Gets the global transform of the widget's inner bounds during the last render or render update.
532    pub fn inner_transform(&self) -> PxTransform {
533        self.0.lock().inner_transform
534    }
535
536    /// Gets the latest inline measure info.
537    ///
538    /// Note that this info may not be the same that was used to update the [`inline`] layout info.
539    /// This value is only useful for panels implementing inline, just after the widget was measured.
540    ///
541    /// Returns `None` if the latest widget measure was not in an inlining context.
542    ///
543    /// [`inline`]: Self::inline
544    pub fn measure_inline(&self) -> Option<WidgetInlineMeasure> {
545        self.0.lock().measure_inline.clone()
546    }
547
548    /// Exclusive read the latest inline layout info.
549    ///
550    /// Returns `None` if the latest widget layout was not in an inlining context.
551    pub fn inline(&self) -> Option<MappedMutexGuard<'_, WidgetInlineInfo>> {
552        let me = self.0.lock();
553        if me.inline.is_some() {
554            Some(MutexGuard::map(me, |m| m.inline.as_mut().unwrap()))
555        } else {
556            None
557        }
558    }
559
560    /// Gets the widget's latest render info, if it was rendered visible or hidden. Returns `None` if the widget was collapsed.
561    pub fn rendered(&self) -> Option<bool> {
562        self.0.lock().rendered.map(|i| i.visible)
563    }
564
565    pub(crate) fn render_info(&self) -> Option<WidgetRenderInfo> {
566        self.0.lock().rendered
567    }
568
569    /// Gets if the [`inner_bounds`] are fully inside the parent inner bounds.
570    ///
571    /// [`inner_bounds`]: Self::inner_bounds
572    pub fn is_in_bounds(&self) -> bool {
573        self.0.lock().is_in_bounds.unwrap_or(false)
574    }
575
576    /// Gets if the widget only renders if [`outer_bounds`] intersects with the [`FrameBuilder::auto_hide_rect`].
577    ///
578    /// This is `true` by default and can be disabled using [`allow_auto_hide`]. If set to `false`
579    /// the widget is always rendered, but descendant widgets can still auto-hide.
580    ///
581    /// [`outer_bounds`]: Self::outer_bounds
582    /// [`FrameBuilder::auto_hide_rect`]: crate::render::FrameBuilder::auto_hide_rect
583    /// [`allow_auto_hide`]: WidgetLayout::allow_auto_hide
584    pub fn can_auto_hide(&self) -> bool {
585        !self.0.lock().cannot_auto_hide
586    }
587
588    fn set_can_auto_hide(&self, enabled: bool) {
589        self.0.lock().cannot_auto_hide = !enabled;
590    }
591
592    pub(crate) fn is_actually_out_of_bounds(&self) -> bool {
593        self.0.lock().is_in_bounds.map(|is| !is).unwrap_or(false)
594    }
595
596    pub(crate) fn set_rendered(&self, rendered: Option<WidgetRenderInfo>, info: &WidgetInfoTree) {
597        let mut m = self.0.lock();
598        if m.rendered.map(|i| i.visible) != rendered.map(|i| i.visible) {
599            info.visibility_changed();
600        }
601        m.rendered = rendered;
602    }
603
604    pub(crate) fn set_outer_transform(&self, transform: PxTransform, info: &WidgetInfoTree) {
605        let bounds = transform
606            .outer_transformed(PxBox::from_size(self.outer_size()))
607            .unwrap_or_default()
608            .to_rect();
609
610        let mut m = self.0.lock();
611
612        if m.outer_bounds.size.is_empty() != bounds.size.is_empty() {
613            info.visibility_changed();
614        }
615
616        m.outer_bounds = bounds;
617        m.outer_transform = transform;
618    }
619
620    pub(crate) fn set_parent_child_offset(&self, offset: PxVector) {
621        self.0.lock().parent_child_offset = offset;
622    }
623
624    pub(crate) fn set_inner_transform(
625        &self,
626        transform: PxTransform,
627        info: &WidgetInfoTree,
628        widget_id: WidgetId,
629        parent_inner: Option<PxRect>,
630    ) {
631        let bounds = transform
632            .outer_transformed(PxBox::from_size(self.inner_size()))
633            .unwrap_or_default()
634            .to_rect();
635
636        let mut m = self.0.lock();
637
638        if m.inner_bounds != bounds {
639            m.inner_bounds = bounds;
640            info.bounds_changed();
641        }
642        let in_bounds = parent_inner.map(|r| r.contains_rect(&bounds)).unwrap_or(true);
643        if let Some(prev) = m.is_in_bounds {
644            if prev != in_bounds {
645                m.is_in_bounds = Some(in_bounds);
646                info.in_bounds_changed(widget_id, in_bounds);
647            }
648        } else {
649            m.is_in_bounds = Some(in_bounds);
650            if !in_bounds {
651                info.in_bounds_changed(widget_id, in_bounds);
652            }
653        }
654
655        m.inner_transform = transform;
656    }
657
658    /// Outer bounding box, updated after every render.
659    pub fn outer_bounds(&self) -> PxRect {
660        self.0.lock().outer_bounds
661    }
662
663    /// Calculate the bounding box that envelops the actual size and position of the inner bounds last rendered.
664    pub fn inner_bounds(&self) -> PxRect {
665        self.0.lock().inner_bounds
666    }
667
668    /// Gets the inline rows for inline widgets or inner bounds for block widgets.
669    ///
670    /// The rectangles are in the root space.
671    pub fn inner_rects(&self) -> Vec<PxRect> {
672        let m = self.0.lock();
673        if let Some(i) = &m.inline {
674            let offset = m.inner_bounds.origin.to_vector();
675            let mut rows = i.rows.clone();
676            for r in &mut rows {
677                r.origin += offset;
678            }
679            rows
680        } else {
681            vec![m.inner_bounds]
682        }
683    }
684
685    /// Call `visitor` for each [`inner_rects`] without allocating or locking.
686    ///
687    // The visitor parameters are the rect, inline row index and rows length. If the widget
688    /// is not inline both index and len are zero.
689    ///
690    /// [`inner_rects`]: Self::inner_rects
691    pub fn visit_inner_rects<B>(&self, mut visitor: impl FnMut(PxRect, usize, usize) -> ops::ControlFlow<B>) -> Option<B> {
692        let m = self.0.lock();
693        let inner_bounds = m.inner_bounds;
694        let inline_range = m.inline.as_ref().map(|i| 0..i.rows.len());
695        drop(m);
696
697        if let Some(inline_range) = inline_range {
698            let offset = inner_bounds.origin.to_vector();
699            let len = inline_range.len();
700
701            for i in inline_range {
702                let mut r = match self.0.lock().inline.as_ref().and_then(|inl| inl.rows.get(i).copied()) {
703                    Some(r) => r,
704                    None => break, // changed mid visit
705                };
706                r.origin += offset;
707                match visitor(r, i, len) {
708                    ops::ControlFlow::Continue(()) => continue,
709                    ops::ControlFlow::Break(r) => return Some(r),
710                }
711            }
712            None
713        } else {
714            match visitor(inner_bounds, 0, 0) {
715                ops::ControlFlow::Continue(()) => None,
716                ops::ControlFlow::Break(r) => Some(r),
717            }
718        }
719    }
720
721    /// If the widget and descendants was collapsed during layout.
722    pub fn is_collapsed(&self) -> bool {
723        self.0.lock().is_collapsed
724    }
725
726    /// Gets if the widget preserves 3D perspective.
727    pub fn transform_style(&self) -> TransformStyle {
728        self.0.lock().transform_style
729    }
730
731    /// Gets the widget perspective and perspective origin (in the inner bounds).
732    pub fn perspective(&self) -> Option<(f32, PxPoint)> {
733        let p = self.0.lock();
734        if p.perspective.is_finite() {
735            let s = p.inner_size;
736            let o = p.perspective_origin.unwrap_or_else(|| PxPoint::new(s.width / 2.0, s.height / 2.0));
737            Some((p.perspective, o))
738        } else {
739            None
740        }
741    }
742
743    /// Snapshot of the [`LayoutMetrics`] on the last layout.
744    ///
745    /// The [`metrics_used`] value indicates what fields where actually used in the last layout.
746    ///
747    /// Is `None` if the widget is collapsed.
748    ///
749    /// [`LayoutMetrics`]: zng_layout::context::LayoutMetrics
750    /// [`metrics_used`]: Self::metrics_used
751    pub fn metrics(&self) -> Option<LayoutMetricsSnapshot> {
752        self.0.lock().metrics.clone()
753    }
754
755    /// All [`metrics`] fields used by the widget or descendants on the last layout.
756    ///
757    /// [`metrics`]: Self::metrics
758    pub fn metrics_used(&self) -> LayoutMask {
759        self.0.lock().metrics_used
760    }
761
762    /// Gets the relative hit-test Z for `window_point` against the hit-test shapes rendered for the widget.
763    pub fn hit_test_z(&self, window_point: PxPoint) -> RelativeHitZ {
764        let m = self.0.lock();
765        if m.hit_clips.is_hit_testable() {
766            m.hit_clips.hit_test_z(&m.inner_transform, window_point)
767        } else {
768            RelativeHitZ::NoHit
769        }
770    }
771
772    /// Index of this widget in the parent hit-test items.
773    fn hit_test_index(&self) -> hit::HitChildIndex {
774        self.0.lock().hit_index
775    }
776
777    /// Returns `true` if a hit-test clip that affects the `child` removes the `window_point` hit on the child.
778    pub fn hit_test_clip_child(&self, child: &WidgetInfo, window_point: PxPoint) -> bool {
779        let m = self.0.lock();
780        if m.hit_clips.is_hit_testable() {
781            m.hit_clips
782                .clip_child(child.bounds_info().hit_test_index(), &m.inner_transform, window_point)
783        } else {
784            false
785        }
786    }
787
788    pub(crate) fn update_hit_test_transform(&self, value: FrameValueUpdate<PxTransform>) {
789        self.0.lock().hit_clips.update_transform(value);
790    }
791
792    pub(crate) fn measure_metrics(&self) -> Option<LayoutMetricsSnapshot> {
793        self.0.lock().measure_metrics.clone()
794    }
795    pub(crate) fn measure_metrics_used(&self) -> LayoutMask {
796        self.0.lock().measure_metrics_used
797    }
798
799    fn set_outer_size(&self, size: PxSize) {
800        let mut s = self.0.lock();
801        if !size.is_empty() {
802            s.is_collapsed = false;
803        }
804        s.outer_size = size;
805    }
806
807    fn set_is_collapsed(&self, collapsed: bool) {
808        self.0.lock().is_collapsed = collapsed;
809    }
810
811    fn take_inline(&self) -> Option<WidgetInlineInfo> {
812        self.0.lock().inline.take()
813    }
814
815    fn set_inline(&self, inline: Option<WidgetInlineInfo>) {
816        self.0.lock().inline = inline;
817    }
818
819    pub(super) fn set_measure_inline(&self, inline: Option<WidgetInlineMeasure>) {
820        self.0.lock().measure_inline = inline;
821    }
822
823    pub(crate) fn set_measure_outer_size(&self, size: PxSize) {
824        self.0.lock().measure_outer_size = size;
825    }
826
827    fn set_inner_offset(&self, offset: PxVector) {
828        self.0.lock().inner_offset = offset;
829    }
830
831    fn set_child_offset(&self, offset: PxVector) {
832        self.0.lock().child_offset = offset;
833    }
834
835    fn set_inner_size(&self, size: PxSize) {
836        self.0.lock().inner_size = size;
837    }
838
839    fn set_baseline(&self, baseline: Px) {
840        self.0.lock().baseline = baseline;
841    }
842
843    fn set_inner_offset_baseline(&self, enabled: bool) {
844        self.0.lock().inner_offset_baseline = enabled;
845    }
846
847    fn set_transform_style(&self, style: TransformStyle) {
848        self.0.lock().transform_style = style;
849    }
850
851    fn raw_perspective(&self) -> f32 {
852        self.0.lock().perspective
853    }
854
855    fn raw_perspective_origin(&self) -> Option<PxPoint> {
856        self.0.lock().perspective_origin
857    }
858
859    fn set_perspective(&self, d: f32) {
860        self.0.lock().perspective = d;
861    }
862
863    fn set_perspective_origin(&self, o: Option<PxPoint>) {
864        self.0.lock().perspective_origin = o;
865    }
866
867    fn set_metrics(&self, metrics: Option<LayoutMetricsSnapshot>, used: LayoutMask) {
868        self.0.lock().metrics = metrics;
869        self.0.lock().metrics_used = used;
870    }
871
872    pub(crate) fn set_measure_metrics(&self, metrics: Option<LayoutMetricsSnapshot>, used: LayoutMask) {
873        self.0.lock().measure_metrics = metrics;
874        self.0.lock().measure_metrics_used = used;
875    }
876
877    pub(crate) fn set_hit_clips(&self, clips: HitTestClips) {
878        self.0.lock().hit_clips = clips;
879    }
880
881    pub(crate) fn set_hit_index(&self, index: hit::HitChildIndex) {
882        self.0.lock().hit_index = index;
883    }
884
885    pub(crate) fn is_partially_culled(&self) -> bool {
886        self.0.lock().is_partially_culled
887    }
888
889    pub(crate) fn set_is_partially_culled(&self, is: bool) {
890        self.0.lock().is_partially_culled = is;
891    }
892}
893
894#[derive(Default, Debug)]
895struct WidgetBorderData {
896    offsets: PxSideOffsets,
897    corner_radius: PxCornerRadius,
898}
899
900/// Shared reference to the combined *border* and corner radius of a [`WidgetInfo`].
901#[derive(Default, Clone, Debug)]
902pub struct WidgetBorderInfo(Arc<Mutex<WidgetBorderData>>);
903impl WidgetBorderInfo {
904    /// New default.
905    pub fn new() -> Self {
906        Self::default()
907    }
908
909    /// Constructor for tests.
910    #[cfg(test)]
911    pub fn new_test(offsets: PxSideOffsets, corner_radius: PxCornerRadius) -> Self {
912        let r = Self::default();
913        r.set_offsets(offsets);
914        r.set_corner_radius(corner_radius);
915        r
916    }
917
918    /// Sum of the widths of all borders set on the widget.
919    pub fn offsets(&self) -> PxSideOffsets {
920        self.0.lock().offsets
921    }
922
923    /// Corner radius set on the widget, this is the *outer* curve of border corners.
924    pub fn corner_radius(&self) -> PxCornerRadius {
925        self.0.lock().corner_radius
926    }
927
928    /// Computes the [`corner_radius`] deflated by [`offsets`], this is the *inner* curve of border corners.
929    ///
930    /// [`corner_radius`]: Self::corner_radius
931    /// [`offsets`]: Self::offsets
932    pub fn inner_corner_radius(&self) -> PxCornerRadius {
933        self.corner_radius().deflate(self.offsets())
934    }
935
936    /// Compute the inner offset plus [`offsets`] left, top.
937    ///
938    /// [`offsets`]: Self::offsets
939    pub fn inner_offset(&self, bounds: &WidgetBoundsInfo) -> PxVector {
940        let o = self.offsets();
941        let o = PxVector::new(o.left, o.top);
942        bounds.inner_offset() + o
943    }
944
945    /// Compute the inner size offset by [`offsets`].
946    ///
947    /// [`offsets`]: Self::offsets
948    pub fn inner_size(&self, bounds: &WidgetBoundsInfo) -> PxSize {
949        let o = self.offsets();
950        bounds.inner_size() - PxSize::new(o.horizontal(), o.vertical())
951    }
952
953    /// Compute the inner transform offset by the [`offsets`].
954    ///
955    /// [`offsets`]: Self::offsets
956    pub fn inner_transform(&self, bounds: &WidgetBoundsInfo) -> PxTransform {
957        let o = self.offsets();
958        let o = PxVector::new(o.left, o.top);
959        bounds.inner_transform().pre_translate(o.cast())
960    }
961
962    pub(super) fn set_offsets(&self, widths: PxSideOffsets) {
963        self.0.lock().offsets = widths;
964    }
965
966    pub(super) fn set_corner_radius(&self, radius: PxCornerRadius) {
967        self.0.lock().corner_radius = radius;
968    }
969}
970
971struct WidgetInfoData {
972    id: WidgetId,
973    bounds_info: WidgetBoundsInfo,
974    border_info: WidgetBorderInfo,
975    meta: Arc<OwnedStateMap<WidgetInfoMeta>>,
976    interactivity_filters: InteractivityFilters,
977    local_interactivity: Interactivity,
978    is_reused: bool,
979    cache: Mutex<WidgetInfoCache>,
980}
981impl Clone for WidgetInfoData {
982    fn clone(&self) -> Self {
983        Self {
984            id: self.id,
985            bounds_info: self.bounds_info.clone(),
986            border_info: self.border_info.clone(),
987            meta: self.meta.clone(),
988            interactivity_filters: self.interactivity_filters.clone(),
989            local_interactivity: self.local_interactivity,
990            is_reused: self.is_reused,
991            cache: Mutex::new(match self.cache.try_lock() {
992                Some(c) => c.clone(),
993                None => WidgetInfoCache { interactivity: None },
994            }),
995        }
996    }
997}
998impl fmt::Debug for WidgetInfoData {
999    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1000        f.debug_struct("WidgetInfoData").field("id", &self.id).finish_non_exhaustive()
1001    }
1002}
1003#[derive(Clone)]
1004struct WidgetInfoCache {
1005    interactivity: Option<Interactivity>,
1006}
1007
1008/// Reference to a widget info in a [`WidgetInfoTree`].
1009#[derive(Clone)]
1010pub struct WidgetInfo {
1011    tree: WidgetInfoTree,
1012    node_id: tree::NodeId,
1013}
1014impl PartialEq for WidgetInfo {
1015    fn eq(&self, other: &Self) -> bool {
1016        self.node_id == other.node_id && self.tree == other.tree
1017    }
1018}
1019impl Eq for WidgetInfo {}
1020impl std::hash::Hash for WidgetInfo {
1021    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1022        std::hash::Hash::hash(&self.node_id, state)
1023    }
1024}
1025impl std::fmt::Debug for WidgetInfo {
1026    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1027        f.debug_struct("WidgetInfo")
1028            .field("trace_path()", &self.trace_path())
1029            .field("inner_bounds()", &self.inner_bounds())
1030            .finish_non_exhaustive()
1031    }
1032}
1033
1034impl WidgetInfo {
1035    fn new(tree: WidgetInfoTree, node_id: tree::NodeId) -> Self {
1036        Self { tree, node_id }
1037    }
1038
1039    fn node(&self) -> tree::NodeRef<'_, WidgetInfoData> {
1040        self.tree.0.tree.index(self.node_id)
1041    }
1042
1043    fn info(&self) -> &WidgetInfoData {
1044        self.node().value()
1045    }
1046
1047    /// Widget id.
1048    pub fn id(&self) -> WidgetId {
1049        self.info().id
1050    }
1051
1052    /// Full path to this widget.
1053    pub fn path(&self) -> WidgetPath {
1054        let mut path: Vec<_> = self.ancestors().map(|a| a.id()).collect();
1055        path.reverse();
1056        path.push(self.id());
1057        path.shrink_to_fit();
1058
1059        WidgetPath::new(self.tree.0.window_id, path.into())
1060    }
1061
1062    /// Path details to help finding the widget during debug.
1063    ///
1064    /// If the inspector metadata is present the widget type is included.
1065    pub fn trace_path(&self) -> Txt {
1066        let mut ws: Vec<_> = self.self_and_ancestors().collect();
1067        ws.reverse();
1068
1069        use std::fmt::*;
1070
1071        let mut s = String::new();
1072
1073        let _ = write!(&mut s, "{:?}/", self.tree.window_id());
1074        for w in ws {
1075            #[cfg(feature = "inspector")]
1076            {
1077                use crate::widget::inspector::*;
1078                if let Some(info) = w.inspector_info() {
1079                    let mod_path = info.builder.widget_type().path;
1080                    let mod_ident = if let Some((_, ident)) = mod_path.rsplit_once(':') {
1081                        ident
1082                    } else {
1083                        mod_path
1084                    };
1085
1086                    let id = w.id();
1087                    let name = id.name();
1088                    if !name.is_empty() {
1089                        let _ = write!(&mut s, "/{mod_ident}!({name:?})");
1090                    } else {
1091                        let _ = write!(&mut s, "/{mod_ident}!({})", id.sequential());
1092                    }
1093                } else {
1094                    let _ = write!(&mut s, "/{}", w.id());
1095                }
1096            }
1097
1098            #[cfg(not(feature = "inspector"))]
1099            {
1100                let _ = write!(&mut s, "/{}", w.id());
1101            }
1102        }
1103
1104        s.into()
1105    }
1106
1107    /// Detailed id text.
1108    ///
1109    /// If the inspector metadata is present the widget type is included.
1110    pub fn trace_id(&self) -> Txt {
1111        #[cfg(feature = "inspector")]
1112        {
1113            use crate::widget::inspector::*;
1114            if let Some(info) = self.inspector_info() {
1115                let mod_path = info.builder.widget_type().path;
1116                let mod_ident = if let Some((_, ident)) = mod_path.rsplit_once(':') {
1117                    ident
1118                } else {
1119                    mod_path
1120                };
1121
1122                let id = self.id();
1123                let name = id.name();
1124                if !name.is_empty() {
1125                    return formatx!("{mod_ident}!({name:?})");
1126                } else {
1127                    return formatx!("{mod_ident}!({})", id.sequential());
1128                }
1129            }
1130        }
1131        formatx!("{}", self.id())
1132    }
1133
1134    /// Full path to this widget with [`interactivity`] values.
1135    ///
1136    /// [`interactivity`]: Self::interactivity
1137    pub fn interaction_path(&self) -> InteractionPath {
1138        let mut path = vec![];
1139
1140        let mut blocked = None;
1141        let mut disabled = None;
1142
1143        for w in self.self_and_ancestors() {
1144            let interactivity = w.interactivity();
1145            if interactivity.contains(Interactivity::BLOCKED) {
1146                blocked = Some(path.len());
1147            }
1148            if interactivity.contains(Interactivity::DISABLED) {
1149                disabled = Some(path.len());
1150            }
1151
1152            path.push(w.id());
1153        }
1154        path.reverse();
1155        path.shrink_to_fit();
1156
1157        let len = path.len();
1158
1159        let path = WidgetPath::new(self.tree.0.window_id, path.into());
1160        InteractionPath::new_internal(
1161            path,
1162            blocked.map(|i| len - i - 1).unwrap_or(len),
1163            disabled.map(|i| len - i - 1).unwrap_or(len),
1164        )
1165    }
1166
1167    /// Gets the [`path`] if it is different from `old_path`.
1168    ///
1169    /// Only allocates a new path if needed.
1170    ///
1171    /// # Panics
1172    ///
1173    /// If `old_path` does not point to the same widget id as `self`.
1174    ///
1175    /// [`path`]: Self::path
1176    pub fn new_path(&self, old_path: &WidgetPath) -> Option<WidgetPath> {
1177        assert_eq!(old_path.widget_id(), self.id());
1178        if self
1179            .ancestors()
1180            .zip(old_path.ancestors().iter().rev())
1181            .any(|(ancestor, id)| ancestor.id() != *id)
1182        {
1183            Some(self.path())
1184        } else {
1185            None
1186        }
1187    }
1188
1189    /// Gets the [`interaction_path`] if it is different from `old_path`.
1190    ///
1191    /// Only allocates a new path if needed.
1192    ///
1193    /// # Panics
1194    ///
1195    /// If `old_path` does not point to the same widget id as `self`.
1196    ///
1197    /// [`interaction_path`]: Self::interaction_path
1198    pub fn new_interaction_path(&self, old_path: &InteractionPath) -> Option<InteractionPath> {
1199        assert_eq!(old_path.widget_id(), self.id());
1200
1201        if self.interactivity() != old_path.interactivity()
1202            || self
1203                .ancestors()
1204                .zip(old_path.zip().rev().skip(1))
1205                .any(|(anc, (id, int))| anc.id() != id || anc.interactivity() != int)
1206        {
1207            Some(self.interaction_path())
1208        } else {
1209            None
1210        }
1211    }
1212
1213    /// Get the z-index of the widget in the latest frame if it was rendered.
1214    ///
1215    /// Note that widgets can render in the back and front of each descendant, these indexes are the *back-most* index, the moment
1216    /// the widget starts rendering and the *front-most* index at the moment the widget and all contents finishes rendering.
1217    ///
1218    /// This value is updated every [`render`] without causing a tree rebuild.
1219    ///
1220    /// [`render`]: crate::widget::node::UiNode::render
1221    pub fn z_index(&self) -> Option<(ZIndex, ZIndex)> {
1222        self.info().bounds_info.render_info().map(|i| {
1223            let offset = self.tree.0.frame.read().widget_count_offsets.offset(i.seg_id);
1224            (ZIndex::from((i.back + offset) as u32), ZIndex::from((i.front + offset) as u32))
1225        })
1226    }
1227
1228    /// Gets the visibility of the widget or the widget's descendants in the last rendered frame.
1229    ///
1230    /// A widget is [`Visible`] if it rendered at least one display item, [`Hidden`] if it rendered only space and
1231    /// hit-test items, [`Collapsed`] if it did not render. All widgets are [`Visible`] if no frame was ever rendered.
1232    ///
1233    /// [`Visible`]: Visibility::Visible
1234    /// [`Hidden`]: Visibility::Hidden
1235    /// [`Collapsed`]: Visibility::Collapsed
1236    pub fn visibility(&self) -> Visibility {
1237        match self.info().bounds_info.rendered() {
1238            Some(vis) => {
1239                if vis {
1240                    Visibility::Visible
1241                } else {
1242                    Visibility::Hidden
1243                }
1244            }
1245            None => {
1246                if self.tree.is_rendered() {
1247                    Visibility::Collapsed
1248                } else {
1249                    Visibility::Visible
1250                }
1251            }
1252        }
1253    }
1254
1255    /// Get or compute the interactivity of the widget.
1256    ///
1257    /// The interactivity of a widget is the combined result of all interactivity filters applied to it and its ancestors.
1258    /// If a parent is blocked this is blocked, same for disabled.
1259    pub fn interactivity(&self) -> Interactivity {
1260        let cached = self.info().cache.lock().interactivity;
1261        if let Some(cache) = cached {
1262            cache
1263        } else {
1264            let mut cache = self.info().cache.lock();
1265            let mut interactivity = self.info().local_interactivity;
1266
1267            if interactivity != Interactivity::BLOCKED_DISABLED {
1268                interactivity |= self.parent().map(|n| n.interactivity()).unwrap_or(Interactivity::ENABLED);
1269                if interactivity != Interactivity::BLOCKED_DISABLED {
1270                    let args = InteractivityFilterArgs { info: self.clone() };
1271                    for filter in &self.tree.0.interactivity_filters {
1272                        interactivity |= filter(&args);
1273                        if interactivity == Interactivity::BLOCKED_DISABLED {
1274                            break;
1275                        }
1276                    }
1277                }
1278            }
1279
1280            cache.interactivity = Some(interactivity);
1281            interactivity
1282        }
1283    }
1284
1285    /// All the transforms introduced by this widget, starting from the outer info.
1286    ///
1287    /// This information is up-to-date, it is updated every layout and render without causing a tree rebuild.
1288    pub fn bounds_info(&self) -> WidgetBoundsInfo {
1289        self.info().bounds_info.clone()
1290    }
1291
1292    /// Clone a reference to the widget border and corner radius information.
1293    ///
1294    /// This information is up-to-date, it is updated every layout without causing a tree rebuild.
1295    pub fn border_info(&self) -> WidgetBorderInfo {
1296        self.info().border_info.clone()
1297    }
1298
1299    /// Gets the 3D perspective for this widget.
1300    ///
1301    /// The `f32` is a distance from the Z-plane to the viewer, the point is the vanishing center in the parent widget inner bounds.
1302    pub fn perspective(&self) -> Option<(f32, PxPoint)> {
1303        self.parent()?.bounds_info().perspective()
1304    }
1305
1306    /// Gets the transform style for this widget.
1307    ///
1308    /// Is `Flat` unless it or the parent widget sets `Preserve3D`.
1309    pub fn transform_style(&self) -> TransformStyle {
1310        if let TransformStyle::Flat = self.bounds_info().transform_style() {
1311            if let Some(p) = self.parent() {
1312                p.bounds_info().transform_style()
1313            } else {
1314                TransformStyle::Flat
1315            }
1316        } else {
1317            TransformStyle::Preserve3D
1318        }
1319    }
1320
1321    /// Size of the widget outer area, not transformed.
1322    ///
1323    /// Returns an up-to-date size, the size is updated every layout without causing a tree rebuild.
1324    pub fn outer_size(&self) -> PxSize {
1325        self.info().bounds_info.outer_size()
1326    }
1327
1328    /// Size of the widget inner area, not transformed.
1329    ///
1330    /// Returns an up-to-date size, the size is updated every layout without causing a tree rebuild.
1331    pub fn inner_size(&self) -> PxSize {
1332        self.info().bounds_info.inner_size()
1333    }
1334
1335    /// Size of the widget child area, not transformed.
1336    ///
1337    /// Returns an up-to-date size, the size is updated every layout without causing a tree rebuild.
1338    pub fn inner_border_size(&self) -> PxSize {
1339        let info = self.info();
1340        info.border_info.inner_size(&info.bounds_info)
1341    }
1342
1343    /// Gets the baseline offset up from the inner bounds bottom line.
1344    pub fn baseline(&self) -> Px {
1345        self.info().bounds_info.baseline()
1346    }
1347
1348    /// Widget outer transform in window space.
1349    ///
1350    /// Returns an up-to-date transform, the transform is updated every render or render update without causing a tree rebuild.
1351    pub fn outer_transform(&self) -> PxTransform {
1352        self.info().bounds_info.outer_transform()
1353    }
1354
1355    /// Widget inner transform in the window space.
1356    ///
1357    /// Returns an up-to-date transform, the transform is updated every render or render update without causing a tree rebuild.
1358    pub fn inner_transform(&self) -> PxTransform {
1359        self.info().bounds_info.inner_transform()
1360    }
1361
1362    /// Widget outer rectangle in the window space.
1363    ///
1364    /// Returns an up-to-date rect, the bounds are updated every render or render update without causing a tree rebuild.
1365    pub fn outer_bounds(&self) -> PxRect {
1366        let info = self.info();
1367        info.bounds_info.outer_bounds()
1368    }
1369
1370    /// Widget inner rectangle in the window space.
1371    ///
1372    /// Returns an up-to-date rect, the bounds are updated every render or render update without causing a tree rebuild.
1373    pub fn inner_bounds(&self) -> PxRect {
1374        let info = self.info();
1375        info.bounds_info.inner_bounds()
1376    }
1377
1378    /// Compute the bounding box that envelops self and descendants inner bounds.
1379    pub fn spatial_bounds(&self) -> PxBox {
1380        self.out_of_bounds()
1381            .fold(self.inner_bounds().to_box2d(), |acc, w| acc.union(&w.inner_bounds().to_box2d()))
1382    }
1383
1384    /// Widget inner bounds center in the window space.
1385    pub fn center(&self) -> PxPoint {
1386        self.inner_bounds().center()
1387    }
1388
1389    /// Custom metadata associated with the widget during info build.
1390    pub fn meta(&self) -> StateMapRef<'_, WidgetInfoMeta> {
1391        self.info().meta.borrow()
1392    }
1393
1394    /// Reference the [`WidgetInfoTree`] that owns `self`.
1395    pub fn tree(&self) -> &WidgetInfoTree {
1396        &self.tree
1397    }
1398
1399    /// If the widget info and all descendants did not change in the last rebuild.
1400    pub fn is_reused(&self) -> bool {
1401        self.info().is_reused
1402    }
1403
1404    /// Reference to the root widget.
1405    pub fn root(&self) -> Self {
1406        self.tree.root()
1407    }
1408
1409    /// Reference to the widget that contains this widget.
1410    ///
1411    /// Is `None` only for [`root`](WidgetInfoTree::root).
1412    pub fn parent(&self) -> Option<Self> {
1413        self.node().parent().map(move |n| WidgetInfo::new(self.tree.clone(), n.id()))
1414    }
1415
1416    /// Reference to the previous widget within the same parent.
1417    pub fn prev_sibling(&self) -> Option<Self> {
1418        self.node().prev_sibling().map(move |n| WidgetInfo::new(self.tree.clone(), n.id()))
1419    }
1420
1421    /// Reference to the next widget within the same parent.
1422    pub fn next_sibling(&self) -> Option<Self> {
1423        self.node().next_sibling().map(move |n| WidgetInfo::new(self.tree.clone(), n.id()))
1424    }
1425
1426    /// Reference to the first widget within this widget.
1427    pub fn first_child(&self) -> Option<Self> {
1428        self.node().first_child().map(move |n| WidgetInfo::new(self.tree.clone(), n.id()))
1429    }
1430
1431    /// Reference to the last widget within this widget.
1432    pub fn last_child(&self) -> Option<Self> {
1433        self.node().last_child().map(move |n| WidgetInfo::new(self.tree.clone(), n.id()))
1434    }
1435
1436    /// If the parent widget has multiple children.
1437    pub fn has_siblings(&self) -> bool {
1438        self.node().has_siblings()
1439    }
1440
1441    /// If the widget has at least one child.
1442    pub fn has_children(&self) -> bool {
1443        self.node().has_children()
1444    }
1445
1446    /// All parent children except this widget.
1447    pub fn siblings(&self) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1448        self.prev_siblings().chain(self.next_siblings())
1449    }
1450
1451    /// Iterator over the direct descendants of the widget.
1452    pub fn children(&self) -> iter::Children {
1453        let mut r = self.self_and_children();
1454        r.next();
1455        r.next_back();
1456        r
1457    }
1458
1459    /// Count of [`children`].
1460    ///
1461    /// [`children`]: Self::children
1462    pub fn children_count(&self) -> usize {
1463        self.node().children_count()
1464    }
1465
1466    /// Iterator over the widget and the direct descendants of the widget.
1467    pub fn self_and_children(&self) -> iter::Children {
1468        iter::Children::new(self.clone())
1469    }
1470
1471    /// Iterator over all widgets contained by this widget.
1472    pub fn descendants(&self) -> iter::TreeIter {
1473        let mut d = self.self_and_descendants();
1474        d.next();
1475        d
1476    }
1477
1478    /// Total number of [`descendants`].
1479    ///
1480    /// [`descendants`]: Self::descendants
1481    pub fn descendants_len(&self) -> usize {
1482        self.node().descendants_range().len()
1483    }
1484
1485    /// Iterator over the widget and all widgets contained by it.
1486    pub fn self_and_descendants(&self) -> iter::TreeIter {
1487        iter::TreeIter::self_and_descendants(self.clone())
1488    }
1489
1490    /// Iterator over parent -> grandparent -> .. -> root.
1491    pub fn ancestors(&self) -> iter::Ancestors {
1492        let mut r = self.self_and_ancestors();
1493        r.next();
1494        r
1495    }
1496
1497    /// Gets a value that can check if widgets are descendant of `self` in O(1) time.
1498    pub fn descendants_range(&self) -> WidgetDescendantsRange {
1499        WidgetDescendantsRange {
1500            tree: Some(self.tree.clone()),
1501            range: self.node().descendants_range(),
1502        }
1503    }
1504
1505    /// Compare the position of `self` and `sibling` in the `ancestor` [`descendants`].
1506    ///
1507    /// [`descendants`]: Self::descendants
1508    pub fn cmp_sibling_in(&self, sibling: &WidgetInfo, ancestor: &WidgetInfo) -> Option<std::cmp::Ordering> {
1509        let range = ancestor.node().descendants_range();
1510        let index = self.node_id.get();
1511        let sibling_index = sibling.node_id.get();
1512        if range.contains(&index) && self.tree == sibling.tree && self.tree == ancestor.tree {
1513            return Some(index.cmp(&sibling_index));
1514        }
1515        None
1516    }
1517
1518    /// If `self` is an ancestor of `maybe_descendant`.
1519    pub fn is_ancestor(&self, maybe_descendant: &WidgetInfo) -> bool {
1520        self.descendants_range().contains(maybe_descendant)
1521    }
1522
1523    /// If `self` is inside `maybe_ancestor`.
1524    pub fn is_descendant(&self, maybe_ancestor: &WidgetInfo) -> bool {
1525        maybe_ancestor.descendants_range().contains(self)
1526    }
1527
1528    /// Iterator over self -> parent -> grandparent -> .. -> root.
1529    pub fn self_and_ancestors(&self) -> iter::Ancestors {
1530        iter::Ancestors::new(self.clone())
1531    }
1532
1533    /// Iterator over all previous widgets within the same parent.
1534    pub fn prev_siblings(&self) -> iter::PrevSiblings {
1535        let mut r = self.self_and_prev_siblings();
1536        r.next();
1537        r
1538    }
1539
1540    /// Iterator over self and all previous widgets within the same parent.
1541    pub fn self_and_prev_siblings(&self) -> iter::PrevSiblings {
1542        iter::PrevSiblings::new(self.clone())
1543    }
1544
1545    /// Iterator over all next widgets within the same parent.
1546    pub fn next_siblings(&self) -> iter::NextSiblings {
1547        let mut r = self.self_and_next_siblings();
1548        r.next();
1549        r
1550    }
1551
1552    /// Iterator over self and all next widgets within the same parent.
1553    pub fn self_and_next_siblings(&self) -> iter::NextSiblings {
1554        iter::NextSiblings::new(self.clone())
1555    }
1556
1557    /// Iterator over all previous widgets within the same `ancestor`, including descendants of siblings.
1558    ///
1559    /// If `ancestor` is not actually an ancestor iterates to the root.
1560    pub fn prev_siblings_in(&self, ancestor: &WidgetInfo) -> iter::RevTreeIter {
1561        iter::TreeIter::prev_siblings_in(self.clone(), ancestor.clone())
1562    }
1563
1564    /// Iterator over self, descendants and all previous widgets within the same `ancestor`.
1565    ///
1566    /// If `ancestor` is not actually an ancestor iterates to the root.
1567    pub fn self_and_prev_siblings_in(&self, ancestor: &WidgetInfo) -> iter::RevTreeIter {
1568        iter::TreeIter::self_and_prev_siblings_in(self.clone(), ancestor.clone())
1569    }
1570
1571    /// Iterator over all next widgets within the same `ancestor`, including descendants of siblings.
1572    ///
1573    /// If `ancestor` is not actually an ancestor iterates to the root.
1574    pub fn next_siblings_in(&self, ancestor: &WidgetInfo) -> iter::TreeIter {
1575        iter::TreeIter::next_siblings_in(self.clone(), ancestor.clone())
1576    }
1577
1578    /// Iterator over self, descendants and all next widgets within the same `ancestor`.
1579    ///
1580    /// If `ancestor` is not actually an ancestor iterates to the root.
1581    pub fn self_and_next_siblings_in(&self, ancestor: &WidgetInfo) -> iter::TreeIter {
1582        iter::TreeIter::self_and_next_siblings_in(self.clone(), ancestor.clone())
1583    }
1584
1585    /// The [`center`] orientation in relation to an `origin`.
1586    ///
1587    /// Returns `None` if the `origin` is the center.
1588    ///
1589    /// [`center`]: Self::center
1590    pub fn orientation_from(&self, origin: PxPoint) -> Option<Orientation2D> {
1591        let o = self.center();
1592        [
1593            Orientation2D::Above,
1594            Orientation2D::Right,
1595            Orientation2D::Below,
1596            Orientation2D::Left,
1597        ]
1598        .iter()
1599        .find(|&&d| d.point_is(origin, o))
1600        .copied()
1601    }
1602
1603    /// Value that indicates the distance between this widget center and `origin`.
1604    pub fn distance_key(&self, origin: PxPoint) -> DistanceKey {
1605        DistanceKey::from_points(origin, self.center())
1606    }
1607
1608    /// Value that indicates the distance between the nearest point inside this widgets rectangles and `origin`.
1609    ///
1610    /// The widgets rectangles is the inner bounds for block widgets or the row rectangles for inline widgets.
1611    pub fn rect_distance_key(&self, origin: PxPoint) -> DistanceKey {
1612        self.rect_distance_key_filtered(origin, |_, _, _| true)
1613    }
1614
1615    /// Like [`rect_distance_key`], but only consider rectangles approved by `filter`.
1616    ///
1617    /// The filter parameters are the rectangle, the inline row index and the total inline rows length. If the widget
1618    /// is not inlined both the index and len are zero.
1619    ///
1620    /// [`rect_distance_key`]: Self::rect_distance_key
1621    pub fn rect_distance_key_filtered(&self, origin: PxPoint, mut filter: impl FnMut(PxRect, usize, usize) -> bool) -> DistanceKey {
1622        let mut d = DistanceKey::NONE_MAX;
1623        self.info().bounds_info.visit_inner_rects::<()>(|r, i, len| {
1624            if !filter(r, i, len) {
1625                return ops::ControlFlow::Continue(());
1626            }
1627            let dd = DistanceKey::from_rect_to_point(r, origin);
1628            d = d.min(dd);
1629            if d == DistanceKey::MIN {
1630                ops::ControlFlow::Break(())
1631            } else {
1632                ops::ControlFlow::Continue(())
1633            }
1634        });
1635        d
1636    }
1637
1638    /// Count of ancestors.
1639    pub fn depth(&self) -> usize {
1640        self.ancestors().count()
1641    }
1642
1643    /// First ancestor of `self` and `other`.
1644    ///
1645    /// Returns `None` if `other` is not from the same tree.
1646    pub fn shared_ancestor(&self, other: &Self) -> Option<WidgetInfo> {
1647        if self.tree == other.tree {
1648            let a = self.path();
1649            let b = other.path();
1650            let shared = a.shared_ancestor(&b).unwrap();
1651            self.tree.get(shared.widget_id())
1652        } else {
1653            None
1654        }
1655    }
1656
1657    /// Gets Z-index a hit-test of `point` against the hit-test shapes rendered for this widget and hit-test clips of parent widgets.
1658    ///
1659    /// A hit happens if the point is inside [`inner_bounds`] and at least one hit-test shape rendered for the widget contains the point.
1660    ///
1661    /// [`inner_bounds`]: WidgetInfo::inner_bounds
1662    fn hit_test_z(&self, point: PxPoint) -> Option<ZIndex> {
1663        let bounds = &self.info().bounds_info;
1664        if bounds.inner_bounds().contains(point) {
1665            let z = match bounds.hit_test_z(point) {
1666                RelativeHitZ::NoHit => None,
1667                RelativeHitZ::Back => bounds.render_info().map(|i| (i.seg_id, i.back)),
1668                RelativeHitZ::Over(w) => self
1669                    .tree
1670                    .get(w)
1671                    .and_then(|w| w.info().bounds_info.render_info())
1672                    .map(|i| (i.seg_id, i.front)),
1673                RelativeHitZ::Front => bounds.render_info().map(|i| (i.seg_id, i.front)),
1674            };
1675
1676            match z {
1677                Some((seg_id, z)) => {
1678                    let mut parent = self.parent();
1679                    let mut child = self.clone();
1680
1681                    while let Some(p) = parent {
1682                        if p.info().bounds_info.hit_test_clip_child(&child, point) {
1683                            return None;
1684                        }
1685
1686                        parent = p.parent();
1687                        child = p;
1688                    }
1689
1690                    Some(ZIndex::from(
1691                        (z + self.tree.0.frame.read().widget_count_offsets.offset(seg_id)) as u32,
1692                    ))
1693                }
1694                None => None,
1695            }
1696        } else {
1697            None
1698        }
1699    }
1700
1701    /// Returns `true` if this widget's inner bounds are fully contained by the parent inner bounds.
1702    pub fn is_in_bounds(&self) -> bool {
1703        self.info().bounds_info.is_in_bounds()
1704    }
1705
1706    /// Iterator over all descendants with inner bounds not fully contained by their parent inner bounds.
1707    pub fn out_of_bounds(&self) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1708        let range = self.descendants_range();
1709        self.tree.out_of_bounds().filter(move |w| range.contains(w))
1710    }
1711
1712    /// Iterator over self and descendants, first self, then all in-bounds descendants, then all out-of-bounds descendants.
1713    ///
1714    /// If the `filter` returns `false` the widget and all it's in-bounds descendants are skipped, otherwise they are yielded. After
1715    /// all in-bounds descendants reachable from `self` and filtered the iterator changes to each out-of-bounds descendants and their
1716    /// in-bounds descendants that are also filtered.
1717    pub fn spatial_iter<F>(&self, filter: F) -> impl Iterator<Item = WidgetInfo> + use<F>
1718    where
1719        F: Fn(&WidgetInfo) -> bool + Clone,
1720    {
1721        let self_id = self.id();
1722        self.self_and_descendants()
1723            .tree_filter(clmv!(filter, |w| {
1724                if (w.is_in_bounds() || w.id() == self_id) && filter(w) {
1725                    TreeFilter::Include
1726                } else {
1727                    TreeFilter::SkipAll
1728                }
1729            }))
1730            .chain(self.out_of_bounds().flat_map(clmv!(filter, |w| {
1731                let out_of_bound_root_id = w.id();
1732                w.self_and_descendants().tree_filter(clmv!(filter, |w| {
1733                    if (w.is_in_bounds() || w.id() == out_of_bound_root_id) && filter(w) {
1734                        TreeFilter::Include
1735                    } else {
1736                        TreeFilter::SkipAll
1737                    }
1738                }))
1739            })))
1740    }
1741
1742    /// Iterator over self and all descendants with inner bounds that contain the `point`.
1743    pub fn inner_contains(&self, point: PxPoint) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1744        self.spatial_iter(move |w| w.inner_bounds().contains(point))
1745    }
1746
1747    /// Spatial iterator over self and descendants with inner bounds that intersects the `rect`.
1748    pub fn inner_intersects(&self, rect: PxRect) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1749        let rect = rect.to_box2d();
1750        self.spatial_iter(move |w| w.inner_bounds().to_box2d().intersects(&rect))
1751    }
1752
1753    /// Spatial iterator over self and descendants with inner bounds that fully envelops the `rect`.
1754    pub fn inner_contains_rect(&self, rect: PxRect) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1755        let rect = rect.to_box2d();
1756        self.spatial_iter(move |w| w.inner_bounds().to_box2d().contains_box(&rect))
1757    }
1758
1759    /// Spatial iterator over self and descendants with inner bounds that are fully inside the `rect`.
1760    pub fn inner_contained(&self, rect: PxRect) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1761        let rect = rect.to_box2d();
1762        self.spatial_iter(move |w| rect.contains_box(&w.inner_bounds().to_box2d()))
1763    }
1764
1765    /// Spatial iterator over self and descendants with center point inside the `area`.
1766    pub fn center_contained(&self, area: PxRect) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1767        let area = area.to_box2d();
1768        self.spatial_iter(move |w| w.inner_bounds().to_box2d().intersects(&area))
1769            .filter(move |w| area.contains(w.center()))
1770    }
1771
1772    /// Spatial iterator over self and descendants with center point within the `max_radius` of the `origin`.
1773    pub fn center_in_distance(&self, origin: PxPoint, max_radius: Px) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1774        let area = PxRect::new(origin, PxSize::splat(max_radius))
1775            .inflate(max_radius, max_radius)
1776            .to_box2d();
1777
1778        let distance_key = DistanceKey::from_distance(max_radius);
1779
1780        self.spatial_iter(move |w| w.inner_bounds().to_box2d().intersects(&area))
1781            .filter(move |w| w.distance_key(origin) <= distance_key)
1782    }
1783
1784    /// Gets all widgets of self and descendants hit by a `point`, sorted by z-index of the hit, front to back.
1785    pub fn hit_test(&self, point: PxPoint) -> HitTestInfo {
1786        let _span = tracing::trace_span!("hit_test").entered();
1787
1788        let mut hits: Vec<_> = self
1789            .inner_contains(point)
1790            .filter_map(|w| {
1791                w.hit_test_z(point).map(|z| HitInfo {
1792                    widget_id: w.id(),
1793                    z_index: z,
1794                })
1795            })
1796            .collect();
1797
1798        hits.sort_by(|a, b| b.z_index.cmp(&a.z_index));
1799
1800        HitTestInfo {
1801            window_id: self.tree.0.window_id,
1802            frame_id: self.tree.0.frame.read().stats.last_frame,
1803            point,
1804            hits,
1805        }
1806    }
1807
1808    /// Find the descendant with center point nearest of `origin` within the `max_radius`.
1809    ///
1810    /// This method is faster than sorting the result of [`center_in_distance`], but is slower if any point in distance is acceptable.
1811    ///
1812    /// [`center_in_distance`]: Self::center_in_distance
1813    pub fn nearest(&self, origin: PxPoint, max_radius: Px) -> Option<WidgetInfo> {
1814        self.nearest_filtered(origin, max_radius, |_| true)
1815    }
1816
1817    /// Find the widget, self or descendant, with center point nearest of `origin` within the `max_radius` and approved by the `filter` closure.
1818    pub fn nearest_filtered(&self, origin: PxPoint, max_radius: Px, filter: impl FnMut(&WidgetInfo) -> bool) -> Option<WidgetInfo> {
1819        self.nearest_bounded_filtered(origin, max_radius, self.tree.spatial_bounds(), filter)
1820    }
1821
1822    /// Find the widget, self or descendant, with center point nearest of `origin` within the `max_radius` and inside `bounds`;
1823    /// and approved by the `filter` closure.
1824    pub fn nearest_bounded_filtered(
1825        &self,
1826        origin: PxPoint,
1827        max_radius: Px,
1828        bounds: PxRect,
1829        mut filter: impl FnMut(&WidgetInfo) -> bool,
1830    ) -> Option<WidgetInfo> {
1831        // search quadrants of `128` -> `256` -> .. until one quadrant finds at least a widget centered in it,
1832        // the nearest widget centered in the smallest quadrant is selected.
1833        let max_quad = self.tree.spatial_bounds().intersection(&bounds)?;
1834
1835        let mut source_quad = PxRect::new(origin - PxVector::splat(Px(64)), PxSize::splat(Px(128)));
1836        let mut search_quad = source_quad.intersection(&max_quad)?;
1837
1838        let max_diameter = max_radius * Px(2);
1839
1840        let mut dist = if max_radius != Px::MAX {
1841            DistanceKey::from_distance(max_radius + Px(1))
1842        } else {
1843            DistanceKey::NONE_MAX
1844        };
1845
1846        let mut nearest = None;
1847        loop {
1848            for w in self.center_contained(search_quad) {
1849                let w_dist = w.distance_key(origin);
1850                if w_dist < dist && filter(&w) {
1851                    dist = w_dist;
1852                    nearest = Some(w);
1853                }
1854            }
1855
1856            let source_width = source_quad.width();
1857            if nearest.is_some() || source_width >= max_diameter {
1858                break;
1859            } else {
1860                source_quad = source_quad.inflate(source_width, source_width);
1861                let new_search = match source_quad.intersection(&max_quad) {
1862                    Some(b) if b != search_quad => b,
1863                    _ => break, // filled bounds
1864                };
1865                search_quad = new_search;
1866            }
1867        }
1868
1869        if nearest.is_some() {
1870            // ensure that we are not skipping a closer widget because the nearest was in a corner of the search quad.
1871            let distance = PxVector::splat(Px(2) * dist.distance().unwrap_or(Px(0)));
1872
1873            let quad = euclid::Box2D::new(origin - distance, origin + distance).intersection_unchecked(&max_quad.to_box2d());
1874
1875            for w in self.center_contained(quad.to_rect()) {
1876                let w_dist = w.distance_key(origin);
1877                if w_dist < dist && filter(&w) {
1878                    dist = w_dist;
1879                    nearest = Some(w);
1880                }
1881            }
1882        }
1883
1884        nearest
1885    }
1886
1887    /// Find the descendant that has inner bounds or inline rows nearest to `origin` and are within `max_radius`.
1888    ///
1889    /// The distance is from any given point inside the bounds or inline rows rectangle to the origin. If origin is inside
1890    /// the rectangle the distance is zero. If multiple widgets have the same distance the nearest center point widget is used.
1891    pub fn nearest_rect(&self, origin: PxPoint, max_radius: Px) -> Option<WidgetInfo> {
1892        self.nearest_rect_filtered(origin, max_radius, |_, _, _, _| true)
1893    }
1894
1895    /// Find the descendant that has inner bounds or inline rows nearest to `origin` and are within `max_radius` and are
1896    /// approved by the `filter` closure.
1897    ///
1898    /// The filter parameters are the widget, the rect, the rect row index and the widget inline rows length. If the widget is not inlined
1899    /// both index and len are zero.
1900    pub fn nearest_rect_filtered(
1901        &self,
1902        origin: PxPoint,
1903        max_radius: Px,
1904        filter: impl FnMut(&WidgetInfo, PxRect, usize, usize) -> bool,
1905    ) -> Option<WidgetInfo> {
1906        self.nearest_rect_bounded_filtered(origin, max_radius, self.tree.spatial_bounds(), filter)
1907    }
1908
1909    /// Find the widget, self or descendant, with inner bounds or inline rows nearest of `origin` within the `max_radius` and inside `bounds`;
1910    /// and approved by the `filter` closure.
1911    ///
1912    /// The filter parameters are the widget, the rect, the rect row index and the widget inline rows length. If the widget is not inlined
1913    /// both index and len are zero.
1914    pub fn nearest_rect_bounded_filtered(
1915        &self,
1916        origin: PxPoint,
1917        max_radius: Px,
1918        bounds: PxRect,
1919        mut filter: impl FnMut(&WidgetInfo, PxRect, usize, usize) -> bool,
1920    ) -> Option<WidgetInfo> {
1921        // search quadrants of `128` -> `256` -> .. until one quadrant finds at least a widget centered in it,
1922        // the nearest widget centered in the smallest quadrant is selected.
1923        let max_quad = self.tree.spatial_bounds().intersection(&bounds)?;
1924
1925        let mut source_quad = PxRect::new(origin - PxVector::splat(Px(64)), PxSize::splat(Px(128)));
1926        let mut search_quad = source_quad.intersection(&max_quad)?;
1927
1928        let max_diameter = max_radius * Px(2);
1929
1930        let mut dist = if max_radius != Px::MAX {
1931            DistanceKey::from_distance(max_radius + Px(1))
1932        } else {
1933            DistanceKey::NONE_MAX
1934        };
1935
1936        let mut nearest = None;
1937        loop {
1938            for w in self.inner_intersects(search_quad) {
1939                let w_dist = w.rect_distance_key_filtered(origin, |rect, i, len| filter(&w, rect, i, len));
1940                if w_dist < dist {
1941                    dist = w_dist;
1942                    nearest = Some(w);
1943                } else if w_dist == DistanceKey::MIN {
1944                    let w_center_dist = w.distance_key(origin);
1945                    let center_dist = nearest.as_ref().unwrap().distance_key(origin);
1946                    if w_center_dist < center_dist {
1947                        nearest = Some(w);
1948                    }
1949                }
1950            }
1951
1952            let source_width = source_quad.width();
1953            if nearest.is_some() || source_width >= max_diameter {
1954                break;
1955            } else {
1956                source_quad = source_quad.inflate(source_width, source_width);
1957                let new_search = match source_quad.intersection(&max_quad) {
1958                    Some(b) if b != search_quad => b,
1959                    _ => break, // filled bounds
1960                };
1961                search_quad = new_search;
1962            }
1963        }
1964
1965        nearest
1966    }
1967
1968    /// Spatial iterator over all widgets, self and descendants, with [`center`] in the direction defined by `orientation` and
1969    /// within `max_distance` of the `origin`, widgets are only visited once and the distance is clipped by the [`spatial_bounds`].
1970    ///
1971    /// Use `Px::MAX` on the distance to visit all widgets in the direction.
1972    ///
1973    /// The direction is defined by a 45ยบ frustum cast from the `origin`, see [`Orientation2D::point_is`] for more details.
1974    ///
1975    /// [`spatial_bounds`]: WidgetInfoTree::spatial_bounds
1976    /// [`center`]: WidgetInfo::center
1977    /// [`Orientation2D::point_is`]: zng_layout::unit::Orientation2D::point_is
1978    pub fn oriented(
1979        &self,
1980        origin: PxPoint,
1981        max_distance: Px,
1982        orientation: Orientation2D,
1983    ) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
1984        let distance_bounded = max_distance != Px::MAX;
1985        let distance_key = if distance_bounded {
1986            DistanceKey::from_distance(max_distance)
1987        } else {
1988            DistanceKey::NONE_MAX
1989        };
1990        let me = self.clone();
1991        orientation
1992            .search_bounds(origin, max_distance, self.tree.spatial_bounds().to_box2d())
1993            .flat_map(move |sq| me.inner_intersects(sq.to_rect()).map(move |w| (sq, w)))
1994            .filter_map(move |(sq, w)| {
1995                let center = w.center();
1996                if sq.contains(center)
1997                    && orientation.point_is(origin, center)
1998                    && (!distance_bounded || DistanceKey::from_points(origin, center) <= distance_key)
1999                {
2000                    Some(w)
2001                } else {
2002                    None
2003                }
2004            })
2005    }
2006
2007    /// Spatial iterator over all widgets, self and descendants, with [`inner_bounds`] in the direction defined by `orientation`
2008    /// in relation to `origin` and with [`center`] within `max_distance` of the `origin` center. Widgets are only visited once and
2009    /// the distance is clipped by the [`spatial_bounds`].
2010    ///
2011    /// Use `Px::MAX` on the distance to visit all widgets in the direction.
2012    ///
2013    /// The direction is a collision check between inner-bounds and origin, see [`Orientation2D::box_is`] for more details.
2014    ///
2015    /// [`spatial_bounds`]: WidgetInfoTree::spatial_bounds
2016    /// [`inner_bounds`]: WidgetInfo::inner_bounds
2017    /// [`center`]: WidgetInfo::center
2018    /// [`Orientation2D::box_is`]: zng_layout::unit::Orientation2D::box_is
2019    pub fn oriented_box(
2020        &self,
2021        origin: PxBox,
2022        max_distance: Px,
2023        orientation: Orientation2D,
2024    ) -> impl Iterator<Item = WidgetInfo> + 'static + use<> {
2025        let distance_bounded = max_distance != Px::MAX;
2026        let distance_key = if distance_bounded {
2027            DistanceKey::from_distance(max_distance)
2028        } else {
2029            DistanceKey::NONE_MAX
2030        };
2031        let me = self.clone();
2032        let origin_center = origin.center();
2033        orientation
2034            .search_bounds(origin_center, max_distance, self.tree.spatial_bounds().to_box2d())
2035            .flat_map(move |sq| me.inner_intersects(sq.to_rect()).map(move |w| (sq, w)))
2036            .filter_map(move |(sq, w)| {
2037                let bounds = w.inner_bounds().to_box2d();
2038                if sq.intersects(&bounds)
2039                    && orientation.box_is(origin, bounds)
2040                    && (!distance_bounded || DistanceKey::from_points(origin_center, bounds.center()) <= distance_key)
2041                {
2042                    Some(w)
2043                } else {
2044                    None
2045                }
2046            })
2047    }
2048
2049    /// Find the widget with center point nearest of `origin` within the `max_distance` and with `orientation` to origin.
2050    ///
2051    /// This method is faster than searching the result of [`oriented`].
2052    ///
2053    /// [`oriented`]: Self::oriented
2054    pub fn nearest_oriented(&self, origin: PxPoint, max_distance: Px, orientation: Orientation2D) -> Option<WidgetInfo> {
2055        self.nearest_oriented_filtered(origin, max_distance, orientation, |_| true)
2056    }
2057
2058    /// Find the widget with center point nearest of `origin` within the `max_distance` and with `orientation` to origin,
2059    /// and approved by the `filter` closure.
2060    ///
2061    /// This method is faster than searching the result of [`oriented`].
2062    ///
2063    /// [`oriented`]: Self::oriented
2064    pub fn nearest_oriented_filtered(
2065        &self,
2066        origin: PxPoint,
2067        max_distance: Px,
2068        orientation: Orientation2D,
2069        filter: impl FnMut(&WidgetInfo) -> bool,
2070    ) -> Option<WidgetInfo> {
2071        self.nearest_oriented_filtered_impl(origin, max_distance, orientation, filter, |w| {
2072            orientation.point_is(origin, w.center())
2073        })
2074    }
2075
2076    /// Find the widget with center point nearest to `origin` center within the `max_distance` and with box `orientation` to origin.
2077    ///
2078    /// This method is faster than searching the result of [`oriented_box`].
2079    ///
2080    /// [`oriented_box`]: Self::oriented_box
2081    pub fn nearest_box_oriented(&self, origin: PxBox, max_distance: Px, orientation: Orientation2D) -> Option<WidgetInfo> {
2082        self.nearest_box_oriented_filtered(origin, max_distance, orientation, |_| true)
2083    }
2084
2085    /// Find the widget with center point nearest to `origin` center within the `max_distance` and with box `orientation` to origin,
2086    /// and approved by the `filter` closure.
2087    ///
2088    /// This method is faster than searching the result of [`oriented_box`].
2089    ///
2090    /// [`oriented_box`]: Self::oriented_box
2091    pub fn nearest_box_oriented_filtered(
2092        &self,
2093        origin: PxBox,
2094        max_distance: Px,
2095        orientation: Orientation2D,
2096        filter: impl FnMut(&WidgetInfo) -> bool,
2097    ) -> Option<WidgetInfo> {
2098        self.nearest_oriented_filtered_impl(origin.center(), max_distance, orientation, filter, |w| {
2099            orientation.box_is(origin, w.inner_bounds().to_box2d())
2100        })
2101    }
2102
2103    fn nearest_oriented_filtered_impl(
2104        &self,
2105        origin: PxPoint,
2106        max_distance: Px,
2107        orientation: Orientation2D,
2108        mut filter: impl FnMut(&WidgetInfo) -> bool,
2109        intersect: impl Fn(&WidgetInfo) -> bool,
2110    ) -> Option<WidgetInfo> {
2111        let mut dist = DistanceKey::from_distance(max_distance + Px(1));
2112        let mut nearest = None;
2113        let mut last_quad = euclid::Box2D::zero();
2114
2115        for search_quad in orientation.search_bounds(origin, max_distance, self.tree.spatial_bounds().to_box2d()) {
2116            for w in self.center_contained(search_quad.to_rect()) {
2117                if intersect(&w) {
2118                    let w_dist = w.distance_key(origin);
2119                    if w_dist < dist && filter(&w) {
2120                        dist = w_dist;
2121                        nearest = Some(w);
2122                    }
2123                }
2124            }
2125
2126            if nearest.is_some() {
2127                last_quad = search_quad;
2128                break;
2129            }
2130        }
2131
2132        if nearest.is_some() {
2133            // ensure that we are not skipping a closer widget because the nearest was in a corner of the search quad.
2134
2135            match orientation {
2136                Orientation2D::Above => {
2137                    let extra = last_quad.height() / Px(2);
2138                    last_quad.max.y = last_quad.min.y;
2139                    last_quad.min.y -= extra;
2140                }
2141                Orientation2D::Right => {
2142                    let extra = last_quad.width() / Px(2);
2143                    last_quad.min.x = last_quad.max.x;
2144                    last_quad.max.x += extra;
2145                }
2146                Orientation2D::Below => {
2147                    let extra = last_quad.height() / Px(2);
2148                    last_quad.min.y = last_quad.max.y;
2149                    last_quad.max.y += extra;
2150                }
2151                Orientation2D::Left => {
2152                    let extra = last_quad.width() / Px(2);
2153                    last_quad.max.x = last_quad.min.x;
2154                    last_quad.min.x -= extra;
2155                }
2156            }
2157
2158            for w in self.center_contained(last_quad.to_rect()) {
2159                let w_dist = w.distance_key(origin);
2160                if w_dist < dist && filter(&w) {
2161                    dist = w_dist;
2162                    nearest = Some(w);
2163                }
2164            }
2165        }
2166
2167        nearest
2168    }
2169
2170    /// Custom [`fmt::Debug`] formatter.
2171    ///
2172    /// The `fmt` closure must include relevant fields for printing and return `true` to include widget children
2173    /// or `false` to skip children.
2174    ///
2175    /// Note that the [`trace_id`] is used as the [`fmt::DebugStruct`].
2176    ///
2177    /// [`trace_id`]: Self::trace_id
2178    pub fn fmt_debug(&self, fmt: &dyn Fn(&Self, &mut fmt::DebugStruct) -> bool) -> impl fmt::Debug {
2179        struct FmtDebug<'a> {
2180            wgt: WidgetInfo,
2181            fmt: &'a dyn Fn(&WidgetInfo, &mut fmt::DebugStruct) -> bool,
2182        }
2183        impl<'a> fmt::Debug for FmtDebug<'a> {
2184            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2185                let mut s = f.debug_struct(&self.wgt.trace_id());
2186                let enter = (self.fmt)(&self.wgt, &mut s);
2187                if enter {
2188                    s.field(
2189                        "children",
2190                        &FmtDebugChildren {
2191                            wgt: self.wgt.clone(),
2192                            fmt: self.fmt,
2193                        },
2194                    );
2195                    s.finish()
2196                } else if self.wgt.descendants_len() > 0 {
2197                    s.finish_non_exhaustive()
2198                } else {
2199                    s.finish()
2200                }
2201            }
2202        }
2203        struct FmtDebugChildren<'a> {
2204            wgt: WidgetInfo,
2205            fmt: &'a dyn Fn(&WidgetInfo, &mut fmt::DebugStruct) -> bool,
2206        }
2207        impl<'a> fmt::Debug for FmtDebugChildren<'a> {
2208            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2209                let mut c = f.debug_list();
2210                for child in self.wgt.children() {
2211                    c.entry(&FmtDebug { wgt: child, fmt: self.fmt });
2212                }
2213                c.finish()
2214            }
2215        }
2216        FmtDebug { wgt: self.clone(), fmt }
2217    }
2218}
2219
2220/// Argument for a interactivity filter function.
2221///
2222/// See [`WidgetInfoBuilder::push_interactivity_filter`] for more details.
2223#[derive(Debug)]
2224#[non_exhaustive]
2225pub struct InteractivityFilterArgs {
2226    /// Widget being filtered.
2227    pub info: WidgetInfo,
2228}
2229impl InteractivityFilterArgs {
2230    /// New from `info`.
2231    pub fn new(info: WidgetInfo) -> Self {
2232        Self { info }
2233    }
2234}
2235
2236type InteractivityFilters = Vec<Arc<dyn Fn(&InteractivityFilterArgs) -> Interactivity + Send + Sync>>;
2237
2238bitflags::bitflags! {
2239    /// Represents the level of interaction allowed for a widget.
2240    #[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
2241    #[serde(transparent)]
2242    pub struct Interactivity: u8 {
2243        /// Normal interactions allowed.
2244        ///
2245        /// This is the default value.
2246        const ENABLED = 0b00;
2247
2248        /// Only "disabled" interactions allowed and disabled visuals.
2249        ///
2250        /// An example of disabled interaction is a tooltip that explains why a disabled button cannot be clicked.
2251        const DISABLED = 0b01;
2252
2253        /// No interaction allowed, the widget must behave like a background visual.
2254        ///
2255        /// Note that widgets with blocked interaction are still hit-testable, so they can still be "clicked"
2256        /// as a visual part of an interactive parent.
2257        const BLOCKED = 0b10;
2258
2259        /// `BLOCKED` with `DISABLED` visuals.
2260        const BLOCKED_DISABLED = Self::DISABLED.bits() | Self::BLOCKED.bits();
2261    }
2262}
2263impl Interactivity {
2264    /// Normal interactions allowed.
2265    pub fn is_enabled(self) -> bool {
2266        self == Self::ENABLED
2267    }
2268
2269    /// Enabled visuals, may still be blocked.
2270    pub fn is_vis_enabled(self) -> bool {
2271        !self.contains(Self::DISABLED)
2272    }
2273
2274    /// Only "disabled" interactions allowed and disabled visuals.
2275    pub fn is_disabled(self) -> bool {
2276        self == Self::DISABLED
2277    }
2278
2279    /// Disabled visuals, maybe also blocked.
2280    pub fn is_vis_disabled(self) -> bool {
2281        self.contains(Self::DISABLED)
2282    }
2283
2284    /// No interaction allowed, may still be visually enabled.
2285    pub fn is_blocked(self) -> bool {
2286        self.contains(Self::BLOCKED)
2287    }
2288}
2289impl Default for Interactivity {
2290    /// `ENABLED`.
2291    fn default() -> Self {
2292        Interactivity::ENABLED
2293    }
2294}
2295impl_from_and_into_var! {
2296    /// * `true` -> `ENABLED`
2297    /// * `false` -> `DISABLED`
2298    fn from(enabled: bool) -> Interactivity {
2299        if enabled { Interactivity::ENABLED } else { Interactivity::DISABLED }
2300    }
2301}
2302impl fmt::Debug for Interactivity {
2303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2304        if self.is_enabled() {
2305            return write!(f, "ENABLED");
2306        }
2307        if *self == Self::BLOCKED_DISABLED {
2308            return write!(f, "BLOCKED_DISABLED");
2309        }
2310        if *self == Self::DISABLED {
2311            return write!(f, "DISABLED");
2312        }
2313        if *self == Self::BLOCKED {
2314            return write!(f, "BLOCKED");
2315        }
2316        write!(f, "Interactivity({:x})", self.bits())
2317    }
2318}
2319
2320/// Widget visibility.
2321///
2322/// The visibility state of a widget is computed from its bounds in the last layout and if it rendered anything,
2323/// the visibility of a parent widget affects all descendant widgets, you can inspect the visibility using the
2324/// [`WidgetInfo::visibility`] method.
2325///
2326/// You can also explicitly hide or collapse a widget using the `visibility` property.
2327///
2328/// [`WidgetInfo::visibility`]: crate::widget::info::WidgetInfo::visibility
2329#[derive(Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
2330pub enum Visibility {
2331    /// The widget is visible.
2332    ///
2333    /// This is also the default state, before the first layout and render.
2334    Visible,
2335    /// The widget is not visible, but still affects layout.
2336    ///
2337    /// Hidden widgets reserve space in their parent but do not render.
2338    Hidden,
2339    /// The widget is not visible and does not affect layout.
2340    ///
2341    /// Collapsed widgets always measure to zero and do not render.
2342    Collapsed,
2343}
2344impl Visibility {
2345    /// Is visible.
2346    pub fn is_visible(self) -> bool {
2347        matches!(self, Self::Visible)
2348    }
2349
2350    /// Is hidden.
2351    pub fn is_hidden(self) -> bool {
2352        matches!(self, Self::Hidden)
2353    }
2354
2355    /// Is collapsed.
2356    pub fn is_collapsed(self) -> bool {
2357        matches!(self, Self::Collapsed)
2358    }
2359}
2360impl fmt::Debug for Visibility {
2361    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2362        if f.alternate() {
2363            write!(f, "Visibility::")?;
2364        }
2365        match self {
2366            Visibility::Visible => write!(f, "Visible"),
2367            Visibility::Hidden => write!(f, "Hidden"),
2368            Visibility::Collapsed => write!(f, "Collapsed"),
2369        }
2370    }
2371}
2372impl Default for Visibility {
2373    /// [` Visibility::Visible`]
2374    fn default() -> Self {
2375        Visibility::Visible
2376    }
2377}
2378impl ops::BitOr for Visibility {
2379    type Output = Self;
2380
2381    /// `Collapsed` | `Hidden` | `Visible` short circuit from left to right.
2382    fn bitor(self, rhs: Self) -> Self::Output {
2383        use Visibility::*;
2384        match (self, rhs) {
2385            (Collapsed, _) | (_, Collapsed) => Collapsed,
2386            (Hidden, _) | (_, Hidden) => Hidden,
2387            _ => Visible,
2388        }
2389    }
2390}
2391impl ops::BitOrAssign for Visibility {
2392    fn bitor_assign(&mut self, rhs: Self) {
2393        *self = *self | rhs;
2394    }
2395}
2396impl_from_and_into_var! {
2397    /// * `true` -> `Visible`
2398    /// * `false` -> `Collapsed`
2399    fn from(visible: bool) -> Visibility {
2400        if visible { Visibility::Visible } else { Visibility::Collapsed }
2401    }
2402}
2403
2404/// Represents the descendants of a widget, allows checking if widgets are descendant with O(1) time.
2405#[derive(Clone, PartialEq, Eq, Default)]
2406pub struct WidgetDescendantsRange {
2407    tree: Option<WidgetInfoTree>,
2408    range: std::ops::Range<usize>,
2409}
2410impl WidgetDescendantsRange {
2411    /// If the widget is a descendant.
2412    pub fn contains(&self, wgt: &WidgetInfo) -> bool {
2413        self.range.contains(&wgt.node_id.get()) && self.tree.as_ref() == Some(&wgt.tree)
2414    }
2415}
2416
2417/// A hit-test hit.
2418#[derive(Clone, Debug, PartialEq)]
2419#[non_exhaustive]
2420pub struct HitInfo {
2421    /// ID of widget hit.
2422    pub widget_id: WidgetId,
2423
2424    /// Z-index of the hit.
2425    pub z_index: ZIndex,
2426}
2427
2428/// A hit-test result.
2429#[derive(Clone, Debug, PartialEq)]
2430pub struct HitTestInfo {
2431    window_id: WindowId,
2432    frame_id: FrameId,
2433    point: PxPoint,
2434    hits: Vec<HitInfo>,
2435}
2436impl HitTestInfo {
2437    /// No hits info
2438    pub fn no_hits(window_id: WindowId) -> Self {
2439        HitTestInfo {
2440            window_id,
2441            frame_id: FrameId::INVALID,
2442            point: PxPoint::new(Px(-1), Px(-1)),
2443            hits: vec![],
2444        }
2445    }
2446
2447    /// The window that was hit-tested.
2448    pub fn window_id(&self) -> WindowId {
2449        self.window_id
2450    }
2451
2452    /// The window frame that was hit-tested.
2453    pub fn frame_id(&self) -> FrameId {
2454        self.frame_id
2455    }
2456
2457    /// The point in the window that was hit-tested.
2458    pub fn point(&self) -> PxPoint {
2459        self.point
2460    }
2461
2462    /// All hits, from top-most.
2463    pub fn hits(&self) -> &[HitInfo] {
2464        &self.hits
2465    }
2466
2467    /// The top hit.
2468    pub fn target(&self) -> Option<&HitInfo> {
2469        self.hits.first()
2470    }
2471
2472    /// Search the widget in the hit-test result.
2473    pub fn find(&self, widget_id: WidgetId) -> Option<&HitInfo> {
2474        self.hits.iter().find(|h| h.widget_id == widget_id)
2475    }
2476
2477    /// If the widget was hit.
2478    pub fn contains(&self, widget_id: WidgetId) -> bool {
2479        self.hits.iter().any(|h| h.widget_id == widget_id)
2480    }
2481
2482    /// Gets a clone of `self` that only contains the hits that also happen in `other`.
2483    pub fn intersection(&self, other: &HitTestInfo) -> HitTestInfo {
2484        let mut hits: Vec<_> = self.hits.iter().filter(|h| other.contains(h.widget_id)).cloned().collect();
2485        hits.shrink_to_fit();
2486
2487        HitTestInfo {
2488            window_id: self.window_id,
2489            frame_id: self.frame_id,
2490            point: self.point,
2491            hits,
2492        }
2493    }
2494}