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