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