zng_app/widget/info/
builder.rs

1use parking_lot::Mutex;
2use zng_layout::{
3    context::{InlineConstraints, InlineConstraintsLayout, InlineConstraintsMeasure, InlineSegment, InlineSegmentPos, LAYOUT, LayoutMask},
4    unit::{Factor, Px, PxBox, PxPoint, PxRect, PxSize, PxVector},
5};
6use zng_state_map::{OwnedStateMap, StateId, StateMapMut, StateValue};
7use zng_unique_id::{IdMap, IdSet};
8
9use crate::{
10    DInstant, INSTANT,
11    render::TransformStyle,
12    update::{InfoUpdates, LayoutUpdates, UpdateFlags},
13    widget::{WIDGET, WidgetId, WidgetUpdateMode, border::BORDER, node::UiNode},
14    window::{WINDOW, WindowId},
15};
16
17use super::{hit::ParallelSegmentOffsets, *};
18
19/// Tag for the [`WidgetInfo::meta`] state-map.
20pub enum WidgetInfoMeta {}
21
22/// Widget info tree builder.
23///
24/// See [`WidgetInfoTree`] for more details.
25pub struct WidgetInfoBuilder {
26    info_widgets: Arc<InfoUpdates>,
27    window_id: WindowId,
28    pub(super) access_enabled: access::AccessEnabled,
29    started_access: bool,
30
31    node: tree::NodeId,
32    widget_id: WidgetId,
33    meta: Arc<Mutex<OwnedStateMap<WidgetInfoMeta>>>,
34
35    tree: Tree<WidgetInfoData>,
36    interactivity_filters: InteractivityFilters,
37
38    scale_factor: Factor,
39
40    build_meta: Arc<Mutex<OwnedStateMap<WidgetInfoMeta>>>,
41
42    build_start: DInstant,
43    pushed_widgets: u32,
44}
45impl WidgetInfoBuilder {
46    /// Starts building a info tree with the root information.
47    pub fn new(
48        info_widgets: Arc<InfoUpdates>,
49        window_id: WindowId,
50        access_enabled: access::AccessEnabled,
51        root_id: WidgetId,
52        root_bounds_info: WidgetBoundsInfo,
53        root_border_info: WidgetBorderInfo,
54        scale_factor: Factor,
55    ) -> Self {
56        let tree = Tree::new(WidgetInfoData {
57            id: root_id,
58            is_reused: false,
59            bounds_info: root_bounds_info,
60            border_info: root_border_info,
61            meta: Arc::new(OwnedStateMap::new()),
62            interactivity_filters: vec![],
63            local_interactivity: Interactivity::ENABLED,
64            cache: Mutex::new(WidgetInfoCache { interactivity: None }),
65        });
66        let mut lookup = IdMap::default();
67        let root_node = tree.root().id();
68        lookup.insert(root_id, root_node);
69
70        let mut builder = WidgetInfoBuilder {
71            info_widgets,
72            window_id,
73            access_enabled,
74            started_access: access_enabled.is_enabled() && WINDOW.info().access_enabled().is_disabled(),
75            node: root_node,
76            tree,
77            interactivity_filters: vec![],
78            meta: Arc::default(),
79            widget_id: root_id,
80            scale_factor,
81            build_meta: Arc::default(),
82            build_start: INSTANT.now(),
83            pushed_widgets: 1, // root is always new.
84        };
85
86        if let Some(mut b) = builder.access() {
87            b.set_role(super::access::AccessRole::Application);
88        }
89
90        builder
91    }
92
93    fn node(&mut self, id: tree::NodeId) -> tree::NodeMut<'_, WidgetInfoData> {
94        self.tree.index_mut(id)
95    }
96
97    /// Current widget id.
98    pub fn widget_id(&self) -> WidgetId {
99        self.widget_id
100    }
101
102    /// Widget info tree build metadata.
103    ///
104    /// This metadata can be modified only by pushed widgets, **not** by the reused widgets.
105    pub fn with_build_meta<R>(&mut self, visitor: impl FnOnce(StateMapMut<WidgetInfoMeta>) -> R) -> R {
106        visitor(self.build_meta.lock().borrow_mut())
107    }
108    /// Set the info tree build metadata `id` to `value`.
109    pub fn set_build_meta<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) {
110        let id = id.into();
111        let value = value.into();
112        self.with_build_meta(|mut s| s.set(id, value));
113    }
114    /// Sets the info tree build metadata `id` without value.
115    pub fn flag_build_meta(&mut self, id: impl Into<StateId<()>>) {
116        let id = id.into();
117        self.with_build_meta(|mut s| s.flag(id));
118    }
119
120    /// Current widget info metadata.
121    pub fn with_meta<R>(&mut self, visitor: impl FnOnce(StateMapMut<WidgetInfoMeta>) -> R) -> R {
122        visitor(self.meta.lock().borrow_mut())
123    }
124    /// Set the widget info metadata `id` to `value`.
125    ///
126    /// Returns the previous set value.
127    pub fn set_meta<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) {
128        let id = id.into();
129        let value = value.into();
130        self.with_meta(|mut s| s.set(id, value));
131    }
132    /// Sets the widget info metadata `id` without value.
133    pub fn flag_meta(&mut self, id: impl Into<StateId<()>>) {
134        let id = id.into();
135        self.with_meta(|mut s| s.flag(id));
136    }
137
138    /// Calls `f` to build the context widget info.
139    ///
140    /// Note that `f` is only called if the widget info cannot be reused.
141    pub fn push_widget(&mut self, f: impl FnOnce(&mut Self)) {
142        let id = WIDGET.id();
143        if !WIDGET.take_update(UpdateFlags::INFO) && !self.info_widgets.delivery_list().enter_widget(id) && !self.started_access {
144            // reuse
145            let tree = WINDOW.info();
146            if let Some(wgt) = tree.get(id) {
147                self.tree.index_mut(self.node).push_reuse(wgt.node(), &mut |old_data| {
148                    let mut r = old_data.clone();
149                    r.is_reused = true;
150                    r.cache.get_mut().interactivity = None;
151                    for filter in &r.interactivity_filters {
152                        self.interactivity_filters.push(filter.clone());
153                    }
154                    r
155                });
156                return;
157            }
158        }
159
160        let parent_node = self.node;
161        let parent_widget_id = self.widget_id;
162        let parent_meta = mem::take(&mut self.meta);
163
164        let bounds_info = WIDGET.bounds();
165        let border_info = WIDGET.border();
166
167        self.widget_id = id;
168        self.node = self
169            .node(parent_node)
170            .push_child(WidgetInfoData {
171                id,
172                is_reused: false,
173                bounds_info,
174                border_info,
175                meta: Arc::new(OwnedStateMap::new()),
176                interactivity_filters: vec![],
177                local_interactivity: Interactivity::ENABLED,
178                cache: Mutex::new(WidgetInfoCache { interactivity: None }),
179            })
180            .id();
181
182        self.pushed_widgets += 1;
183
184        f(self);
185
186        let meta = mem::replace(&mut self.meta, parent_meta);
187        let mut node = self.node(self.node);
188        node.value().meta = Arc::new(Arc::try_unwrap(meta).unwrap().into_inner());
189        node.close();
190
191        self.node = parent_node;
192        self.widget_id = parent_widget_id;
193    }
194
195    /// Add the `interactivity` bits to the current widget's interactivity, it will affect the widget and all descendants.
196    ///
197    /// Also see [`push_interactivity_filter`] to affect the interactivity of widgets outside the current one.
198    ///
199    /// [`push_interactivity_filter`]: Self::push_interactivity_filter
200    pub fn push_interactivity(&mut self, interactivity: Interactivity) {
201        let mut node = self.node(self.node);
202        let v = node.value();
203        v.local_interactivity |= interactivity;
204    }
205
206    /// Register a closure that returns the [`Interactivity`] allowed for each widget.
207    ///
208    /// Widgets [`interactivity`] is computed from all interactivity filters and parents. Interactivity filters are global to the
209    /// widget tree, and are re-registered for the tree if the current widget is reused.
210    ///
211    /// Note that the filter can make the assumption that parent widgets affect all descendants and if the filter is intended to
212    /// affect only the current widget and descendants you can use [`push_interactivity`] instead.
213    ///
214    /// [`interactivity`]: WidgetInfo::interactivity
215    /// [`push_interactivity`]: Self::push_interactivity
216    pub fn push_interactivity_filter(&mut self, filter: impl Fn(&InteractivityFilterArgs) -> Interactivity + Send + Sync + 'static) {
217        let filter = Arc::new(filter);
218        self.interactivity_filters.push(filter.clone());
219        self.node(self.node).value().interactivity_filters.push(filter);
220    }
221
222    /// Calls the `info` closure and returns the range of children inserted by it.
223    pub fn with_children_range(&mut self, info: impl FnOnce(&mut Self)) -> ops::Range<usize> {
224        let before_count = self.tree.index(self.node).children_count();
225        info(self);
226        before_count..self.tree.index(self.node).children_count()
227    }
228
229    /// Create a new info builder that can be built in parallel and merged back onto this one using [`parallel_fold`].
230    ///
231    /// [`parallel_fold`]: Self::parallel_fold
232    /// [`push_widget`]: Self::push_widget
233    pub fn parallel_split(&self) -> ParallelBuilder<Self> {
234        let node = self.tree.index(self.node).value();
235        let tree = Tree::new(WidgetInfoData {
236            id: node.id,
237            is_reused: node.is_reused,
238            bounds_info: node.bounds_info.clone(),
239            border_info: node.border_info.clone(),
240            meta: node.meta.clone(),
241            interactivity_filters: vec![],
242            local_interactivity: node.local_interactivity,
243            cache: Mutex::new(WidgetInfoCache { interactivity: None }),
244        });
245        ParallelBuilder(Some(Self {
246            info_widgets: self.info_widgets.clone(),
247            window_id: self.window_id,
248            access_enabled: self.access_enabled,
249            started_access: self.started_access,
250            widget_id: self.widget_id,
251            meta: self.meta.clone(),
252            node: tree.root().id(),
253            tree,
254            interactivity_filters: vec![],
255            scale_factor: self.scale_factor,
256            build_meta: self.build_meta.clone(),
257            build_start: self.build_start,
258            pushed_widgets: 0,
259        }))
260    }
261
262    /// Collect info from `split` into `self`.
263    pub fn parallel_fold(&mut self, mut split: ParallelBuilder<Self>) {
264        let mut split = split.take();
265
266        self.interactivity_filters.append(&mut split.interactivity_filters);
267        self.pushed_widgets += split.pushed_widgets;
268        {
269            debug_assert!(Arc::ptr_eq(&self.meta, &split.meta));
270
271            let mut split_node = split.tree.root_mut();
272            let mut node = self.node(self.node);
273            let split_node = split_node.value();
274            let node = node.value();
275
276            node.interactivity_filters.append(&mut split_node.interactivity_filters);
277            node.local_interactivity |= split_node.local_interactivity;
278        }
279
280        self.tree.index_mut(self.node).parallel_fold(split.tree, &mut |d| WidgetInfoData {
281            id: d.id,
282            is_reused: d.is_reused,
283            bounds_info: d.bounds_info.clone(),
284            border_info: d.border_info.clone(),
285            meta: d.meta.clone(),
286            interactivity_filters: mem::take(&mut d.interactivity_filters),
287            local_interactivity: d.local_interactivity,
288            cache: Mutex::new(d.cache.get_mut().clone()),
289        });
290    }
291
292    /// Build the info tree.
293    ///
294    /// Also notifies [`WIDGET_INFO_CHANGED_EVENT`] and [`INTERACTIVITY_CHANGED_EVENT`] if `notify` is true.
295    pub fn finalize(mut self, previous_tree: Option<WidgetInfoTree>, notify: bool) -> WidgetInfoTree {
296        let mut node = self.tree.root_mut();
297        let meta = Arc::new(Arc::try_unwrap(self.meta).unwrap().into_inner());
298        node.value().meta = meta;
299        node.close();
300
301        let generation;
302        let widget_count_offsets;
303        let spatial_bounds;
304        let transform_changed_subs;
305        let visibility_changed_subs;
306
307        if let Some(t) = &previous_tree {
308            let t = t.0.frame.read();
309            generation = t.stats.generation.wrapping_add(1);
310            widget_count_offsets = t.widget_count_offsets.clone();
311            spatial_bounds = t.spatial_bounds;
312            transform_changed_subs = t.transform_changed_subs.clone();
313            visibility_changed_subs = t.visibility_changed_subs.clone();
314        } else {
315            generation = 0;
316            widget_count_offsets = ParallelSegmentOffsets::default();
317            spatial_bounds = PxBox::zero();
318            transform_changed_subs = IdMap::new();
319            visibility_changed_subs = IdMap::new();
320        }
321
322        let mut lookup = IdMap::new();
323        lookup.reserve(self.tree.len());
324        let mut out_of_bounds = vec![];
325
326        for (id, data) in self.tree.iter() {
327            if lookup.insert(data.id, id).is_some() {
328                tracing::error!("widget `{}` repeated in info tree", data.id);
329            }
330            if data.bounds_info.is_actually_out_of_bounds() {
331                out_of_bounds.push(id);
332            }
333        }
334        out_of_bounds.shrink_to_fit();
335
336        let tree = WidgetInfoTree(Arc::new(WidgetInfoTreeInner {
337            window_id: self.window_id,
338            access_enabled: self.access_enabled,
339            lookup,
340            interactivity_filters: self.interactivity_filters,
341            build_meta: Arc::new(mem::take(&mut self.build_meta.lock())),
342
343            frame: RwLock::new(WidgetInfoTreeFrame {
344                stats: WidgetInfoTreeStats::new(self.build_start, self.tree.len() as u32 - self.pushed_widgets, generation),
345                stats_update: Default::default(),
346                out_of_bounds: Arc::new(out_of_bounds),
347                out_of_bounds_update: Default::default(),
348                scale_factor: self.scale_factor,
349                spatial_bounds,
350                widget_count_offsets,
351                transform_changed_subs,
352                visibility_changed_subs,
353                view_process_gen: ViewProcessGen::INVALID,
354            }),
355
356            tree: self.tree,
357        }));
358
359        if notify {
360            let prev_tree = previous_tree.unwrap_or_else(|| WidgetInfoTree::wgt(tree.window_id(), tree.root().id()));
361            let args = WidgetInfoChangedArgs::now(tree.window_id(), prev_tree.clone(), tree.clone());
362            WIDGET_INFO_CHANGED_EVENT.notify(args);
363
364            let mut targets = IdSet::default();
365            INTERACTIVITY_CHANGED_EVENT.visit_subscribers::<()>(|wid| {
366                if let Some(wgt) = tree.get(wid) {
367                    let prev = prev_tree.get(wid).map(|w| w.interactivity());
368                    let new_int = wgt.interactivity();
369                    if prev != Some(new_int) {
370                        targets.insert(wid);
371                    }
372                }
373                ops::ControlFlow::Continue(())
374            });
375            if !targets.is_empty() {
376                let args = InteractivityChangedArgs::now(prev_tree, tree.clone(), targets);
377                INTERACTIVITY_CHANGED_EVENT.notify(args);
378            }
379        }
380
381        tree
382    }
383}
384
385crate::event::event! {
386    /// A window widget tree was rebuild.
387    pub static WIDGET_INFO_CHANGED_EVENT: WidgetInfoChangedArgs;
388
389    /// Widget interactivity has changed after an info update.
390    ///
391    /// All subscribers of this event are checked after info rebuild, if the interactivity changes from the previous tree
392    /// the event notifies.
393    ///
394    /// The event only notifies if the widget is present in the new info tree.
395    pub static INTERACTIVITY_CHANGED_EVENT: InteractivityChangedArgs;
396
397    /// Widget visibility has changed after render.
398    ///
399    /// All subscribers of this event are checked after render, if the previous visibility was recorded and
400    /// the new visibility is different an event is sent to the widget.
401    pub static VISIBILITY_CHANGED_EVENT: VisibilityChangedArgs;
402
403    /// A widget global inner transform has changed after render.
404    ///
405    /// All subscribers of this event are checked after render, if the previous inner transform was recorded and
406    /// the new inner transform is different an event is sent to the widget.
407    pub static TRANSFORM_CHANGED_EVENT: TransformChangedArgs;
408}
409
410crate::event::event_args! {
411    /// [`WIDGET_INFO_CHANGED_EVENT`] args.
412    pub struct WidgetInfoChangedArgs {
413        /// Window ID.
414        pub window_id: WindowId,
415
416        /// Previous widget tree.
417        ///
418        /// This is an empty tree before the first tree build.
419        pub prev_tree: WidgetInfoTree,
420
421        /// New widget tree.
422        pub tree: WidgetInfoTree,
423
424        ..
425
426        /// Broadcast to all widgets.
427        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
428            list.search_all()
429        }
430    }
431
432    /// [`TRANSFORM_CHANGED_EVENT`] args.
433    pub struct TransformChangedArgs {
434        /// Widget tree where some widgets have new inner transforms.
435        pub tree: WidgetInfoTree,
436
437        /// All event subscribers that changed inner-transform mapped to the previous inner-transform.
438        pub changed: IdMap<WidgetId, PxTransform>,
439
440        ..
441
442        /// Target the `changed` widgets.
443        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
444            for id in self.changed.keys() {
445                if let Some(wgt) = self.tree.get(*id) {
446                    list.insert_wgt(&wgt);
447                }
448            }
449        }
450    }
451
452    /// [`VISIBILITY_CHANGED_EVENT`] args.
453    pub struct VisibilityChangedArgs {
454        /// Widget tree where some widgets have new visibility.
455        pub tree: WidgetInfoTree,
456
457        /// All event subscribers that changed visibility mapped to the previous visibility.
458        pub changed: IdMap<WidgetId, Visibility>,
459
460        ..
461
462        /// Target the `changed` widgets.
463        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
464            for id in self.changed.keys() {
465                if let Some(wgt) = self.tree.get(*id) {
466                    list.insert_wgt(&wgt);
467                }
468            }
469        }
470    }
471
472    /// [`INTERACTIVITY_CHANGED_EVENT`] args.
473    pub struct InteractivityChangedArgs {
474        /// Previous tree with old interactivity values.
475        pub prev_tree: WidgetInfoTree,
476
477        /// New tree with new interactivity values.
478        pub tree: WidgetInfoTree,
479
480        /// All event subscribers that changed interactivity in this info update.
481        pub changed: IdSet<WidgetId>,
482
483        ..
484
485        /// Target the `changed` widgets.
486        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
487            for id in self.changed.iter() {
488                if let Some(wgt) = self.tree.get(*id) {
489                    list.insert_wgt(&wgt);
490                }
491            }
492        }
493    }
494}
495impl TransformChangedArgs {
496    /// Gets the previous and new inner transform of the widget.
497    pub fn change(&self, id: WidgetId) -> Option<(PxTransform, PxTransform)> {
498        let prev = *self.changed.get(&id)?;
499        let new = self.tree.get(id)?.inner_transform();
500        Some((prev, new))
501    }
502
503    /// Gets the movement between previous and new transformed top-left corner.
504    pub fn offset(&self, id: WidgetId) -> Option<PxVector> {
505        let (prev, new) = self.change(id)?;
506
507        let prev = prev.transform_point(PxPoint::zero()).unwrap_or_default();
508        let new = new.transform_point(PxPoint::zero()).unwrap_or_default();
509        Some(prev - new)
510    }
511}
512impl InteractivityChangedArgs {
513    /// Previous interactivity of this widget.
514    ///
515    /// Returns `None` if the widget was not in the previous info tree.
516    pub fn prev_interactivity(&self, widget_id: WidgetId) -> Option<Interactivity> {
517        self.prev_tree.get(widget_id).map(|w| w.interactivity())
518    }
519
520    /// New interactivity of the widget.
521    ///
522    /// # Panics
523    ///
524    /// Panics if `widget_id` is not in [`tree`]. This method must be called only for [`changed`].
525    ///
526    /// [`tree`]: Self::tree
527    /// [`changed`]: Self::changed
528    pub fn new_interactivity(&self, widget_id: WidgetId) -> Interactivity {
529        if let Some(w) = self.tree.get(widget_id) {
530            w.interactivity()
531        } else if self.changed.contains(&widget_id) {
532            panic!("widget {widget_id} was in targets and not in new tree, invalid args");
533        } else {
534            panic!("widget {widget_id} is not in targets");
535        }
536    }
537
538    /// Widget was disabled or did not exist, now is enabled.
539    pub fn is_enable(&self, widget_id: WidgetId) -> bool {
540        self.prev_interactivity(widget_id).unwrap_or(Interactivity::DISABLED).is_disabled()
541            && self.new_interactivity(widget_id).is_enabled()
542    }
543
544    /// Widget was enabled or did not exist, now is disabled.
545    pub fn is_disable(&self, widget_id: WidgetId) -> bool {
546        self.prev_interactivity(widget_id).unwrap_or(Interactivity::ENABLED).is_enabled() && self.new_interactivity(widget_id).is_disabled()
547    }
548
549    /// Widget was blocked or did not exist, now is unblocked.
550    pub fn is_unblock(&self, widget_id: WidgetId) -> bool {
551        self.prev_interactivity(widget_id).unwrap_or(Interactivity::BLOCKED).is_blocked() && !self.new_interactivity(widget_id).is_blocked()
552    }
553
554    /// Widget was unblocked or did not exist, now is blocked.
555    pub fn is_block(&self, widget_id: WidgetId) -> bool {
556        !self.prev_interactivity(widget_id).unwrap_or(Interactivity::BLOCKED).is_blocked() && self.new_interactivity(widget_id).is_blocked()
557    }
558
559    /// Widget was visually disabled or did not exist, now is visually enabled.
560    pub fn is_vis_enable(&self, widget_id: WidgetId) -> bool {
561        self.prev_interactivity(widget_id)
562            .unwrap_or(Interactivity::DISABLED)
563            .is_vis_disabled()
564            && self.new_interactivity(widget_id).is_vis_enabled()
565    }
566
567    /// Widget was visually enabled or did not exist, now is visually disabled.
568    pub fn is_vis_disable(&self, widget_id: WidgetId) -> bool {
569        self.prev_interactivity(widget_id)
570            .unwrap_or(Interactivity::ENABLED)
571            .is_vis_enabled()
572            && self.new_interactivity(widget_id).is_vis_disabled()
573    }
574
575    /// Returns the previous and new interactivity if the widget was enabled, disabled or is new.
576    pub fn enabled_change(&self, widget_id: WidgetId) -> Option<(Option<Interactivity>, Interactivity)> {
577        self.change_check(widget_id, Interactivity::is_enabled)
578    }
579
580    /// Returns the previous and new interactivity if the widget was visually enabled, visually disabled or is new.
581    pub fn vis_enabled_change(&self, widget_id: WidgetId) -> Option<(Option<Interactivity>, Interactivity)> {
582        self.change_check(widget_id, Interactivity::is_vis_enabled)
583    }
584
585    /// Returns the previous and new interactivity if the widget was blocked, unblocked or is new.
586    pub fn blocked_change(&self, widget_id: WidgetId) -> Option<(Option<Interactivity>, Interactivity)> {
587        self.change_check(widget_id, Interactivity::is_blocked)
588    }
589
590    fn change_check(&self, widget_id: WidgetId, mtd: impl Fn(Interactivity) -> bool) -> Option<(Option<Interactivity>, Interactivity)> {
591        let new = self.new_interactivity(widget_id);
592        let prev = self.prev_interactivity(widget_id);
593        if let Some(prev) = prev {
594            if mtd(prev) != mtd(new) { Some((Some(prev), new)) } else { None }
595        } else {
596            Some((prev, new))
597        }
598    }
599
600    /// Widget is new, no previous interactivity state is known, events that filter by interactivity change
601    /// update by default if the widget is new.
602    pub fn is_new(&self, widget_id: WidgetId) -> bool {
603        !self.prev_tree.contains(widget_id) && self.tree.contains(widget_id)
604    }
605}
606
607impl VisibilityChangedArgs {
608    /// Gets the previous and new visibility for the widget, if it has changed.
609    pub fn change(&self, widget_id: WidgetId) -> Option<(Visibility, Visibility)> {
610        let prev = *self.changed.get(&widget_id)?;
611        let new = self.tree.get(widget_id)?.visibility();
612        Some((prev, new))
613    }
614
615    /// Gets the previous visibility of the widget, if it has changed.
616    pub fn prev_vis(&self, widget_id: WidgetId) -> Option<Visibility> {
617        self.changed.get(&widget_id).copied()
618    }
619
620    /// Gets the new visibility of the widget, if it has changed.
621    pub fn new_vis(&self, widget_id: WidgetId) -> Option<Visibility> {
622        self.change(widget_id).map(|(_, n)| n)
623    }
624
625    /// Widget was visible or hidden, now is collapsed.
626    pub fn is_collapse(&self, widget_id: WidgetId) -> bool {
627        matches!(
628            self.change(widget_id),
629            Some((Visibility::Visible | Visibility::Hidden, Visibility::Collapsed))
630        )
631    }
632
633    /// Widget was visible or collapsed, now is hidden.
634    pub fn is_hide(&self, widget_id: WidgetId) -> bool {
635        matches!(
636            self.change(widget_id),
637            Some((Visibility::Visible | Visibility::Collapsed, Visibility::Hidden))
638        )
639    }
640
641    /// Widget was not hidden or collapsed, now is visible.
642    pub fn is_show(&self, widget_id: WidgetId) -> bool {
643        matches!(
644            self.change(widget_id),
645            Some((Visibility::Hidden | Visibility::Collapsed, Visibility::Visible))
646        )
647    }
648}
649
650/// Info about the input inline connecting rows of the widget.
651#[derive(Clone, Debug, Default, PartialEq)]
652#[non_exhaustive]
653pub struct WidgetInlineMeasure {
654    /// Preferred first size.
655    ///
656    /// In left-to-right direction the origin is `top_left`, in right-to-left direction the origin is `top_right - first.width`.
657    pub first: PxSize,
658
659    /// Indicates that `first` starts in the next row, not in the *current* row defined by the inline constraints.
660    pub first_wrapped: bool,
661
662    /// Inline segments in the first row.
663    ///
664    /// The sum of segment widths must be less or equal to the `first.width`.
665    pub first_segs: Arc<Vec<InlineSegment>>,
666
667    /// Preferred last size.
668    ///
669    /// In left-to-right direction the origin is `bottom_left - last.height`, in right-to-left direction
670    /// the origin is `bottom_right - last`.
671    ///
672    /// Must be equal to `first` if did not wrap.
673    ///
674    /// Must not be empty if first is not empty, that is, must not wrap if the last item can fit in the previous row.
675    pub last: PxSize,
676
677    /// Indicates that `last` starts in a next row, not in the same row as the first.
678    pub last_wrapped: bool,
679
680    /// Inline segments in the last row.
681    ///
682    /// The sum of segment widths must be less or equal to the `last.width`.
683    pub last_segs: Arc<Vec<InlineSegment>>,
684}
685impl WidgetInlineMeasure {
686    /// Visit a mutable reference to the new [`first_segs`] value, `f` is called with
687    /// an empty vec that can be reused or new.
688    ///
689    /// [`first_segs`]: Self::first_segs
690    pub fn with_first_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
691        Self::with_segs(&mut self.first_segs, f)
692    }
693
694    /// Visit a mutable reference to the new [`last_segs`] value, `f` is called with
695    /// an empty vec that can be reused or new.
696    ///
697    /// [`last_segs`]: Self::last_segs
698    pub fn with_last_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
699        Self::with_segs(&mut self.last_segs, f)
700    }
701
702    fn with_segs(items: &mut Arc<Vec<InlineSegment>>, f: impl FnOnce(&mut Vec<InlineSegment>)) {
703        match Arc::get_mut(items) {
704            Some(items) => {
705                items.clear();
706                f(items);
707            }
708            None => {
709                let mut new = vec![];
710                f(&mut new);
711                *items = Arc::new(new);
712            }
713        }
714    }
715
716    /// If all value are not different from initial.
717    ///
718    /// This indicates the widget has not handled the inline config yet.
719    pub fn is_default(&self) -> bool {
720        self.first.is_empty()
721            && !self.first_wrapped
722            && self.first_segs.is_empty()
723            && self.last.is_empty()
724            && !self.last_wrapped
725            && self.last_segs.is_empty()
726    }
727}
728
729/// Info about a segment in the first or last row of an inlined widget.
730///
731/// See [`WidgetInlineInfo::first_segs`] for more details.
732#[derive(Clone, Copy, Debug, PartialEq, Eq)]
733#[non_exhaustive]
734pub struct InlineSegmentInfo {
735    /// Segment offset from the row rectangle origin.
736    pub x: Px,
737    /// Segment width.
738    ///
739    /// Note that the segment height is the row rectangle height.
740    pub width: Px,
741}
742
743impl InlineSegmentInfo {
744    /// New from `x` and `width`.
745    pub fn new(x: Px, width: Px) -> Self {
746        Self { x, width }
747    }
748}
749
750/// Info about the inlined rows of the widget.
751#[derive(Debug, Default)]
752#[non_exhaustive]
753pub struct WidgetInlineInfo {
754    /// Last layout rows of the widget.
755    ///
756    /// The rectangles are in the widget's inner space, from top to bottom.
757    pub rows: Vec<PxRect>,
758
759    /// Segments of the first row.
760    ///
761    /// If this is empty the entire row width is a continuous segment, otherwise the row is segmented and
762    /// the widget can be interleaved with sibling widgets due to Unicode bidirectional text sorting algorithm.
763    ///
764    /// Note that the segment count may be less then [`WidgetInlineMeasure::first_segs`] as contiguous segments
765    /// may be merged.
766    ///
767    /// The segments are from left to right.
768    pub first_segs: Vec<InlineSegmentInfo>,
769
770    /// Segments of the last row.
771    pub last_segs: Vec<InlineSegmentInfo>,
772
773    /// Widget inner size when the rows where last updated.
774    pub inner_size: PxSize,
775
776    negative_space: Mutex<(Arc<Vec<PxRect>>, bool)>,
777}
778impl WidgetInlineInfo {
779    /// Replace the [`first_segs`] with `segs`.
780    ///
781    /// The segments are sorted when needed, but prefer inputs that are mostly sorted.
782    ///
783    /// The segments are merged when there is no gap or there is a small one pixel overlap to the previous segment.
784    ///
785    /// [`first_segs`]: Self::first_segs
786    pub fn set_first_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
787        Self::set_segs(&mut self.first_segs, segs);
788        self.invalidate_negative_space();
789    }
790
791    /// Replace the [`last_segs`] with `segs`.
792    ///
793    /// The segments are sorted when needed, but prefer inputs that are mostly sorted.
794    ///
795    /// The segments are merged when there is no gap or there is a small one pixel overlap to the previous segment.
796    ///
797    /// [`last_segs`]: Self::last_segs
798    pub fn set_last_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
799        Self::set_segs(&mut self.last_segs, segs);
800        self.invalidate_negative_space();
801    }
802
803    fn set_segs(vec: &mut Vec<InlineSegmentInfo>, segs: impl Iterator<Item = InlineSegmentInfo>) {
804        vec.clear();
805
806        let mut needs_sort = false;
807
808        for seg in segs {
809            if seg.width <= 0 {
810                continue;
811            }
812
813            if let Some(last) = vec.last_mut() {
814                let la = last.x;
815                let lb = last.x + last.width;
816
817                let a = seg.x;
818                let b = seg.x + seg.width;
819
820                if la.max(a) <= lb.min(b) {
821                    // merge overlap
822                    last.x = a.min(la);
823                    last.width = b.max(lb) - last.x;
824                    continue;
825                }
826
827                needs_sort |= a < la;
828            }
829            vec.push(seg);
830        }
831
832        if needs_sort {
833            vec.sort_unstable_by_key(|s| s.x);
834        }
835    }
836
837    /// Gets the union of all row rectangles.
838    pub fn union(&self) -> PxRect {
839        self.rows.iter().fold(PxRect::zero(), |union, row| union.union(row))
840    }
841
842    /// Gets or computes the negative space of the [`rows`] in the [`inner_size`] space, that is, all the areas that are
843    /// not covered by any row and not covered by the first and last row segments.
844    ///
845    /// This is computed on demand and cached.
846    ///
847    /// [`rows`]: Self::rows
848    /// [`inner_size`]: Self::inner_size
849    pub fn negative_space(&self) -> Arc<Vec<PxRect>> {
850        let mut space = self.negative_space.lock();
851        if space.1 {
852            return space.0.clone();
853        }
854
855        let mut vec = Arc::try_unwrap(mem::take(&mut space.0)).unwrap_or_default();
856        vec.clear();
857
858        self.negative_enveloped(&mut vec, PxRect::from_size(self.inner_size));
859
860        let r = Arc::new(vec);
861        *space = (r.clone(), true);
862        r
863    }
864
865    /// Invalidates the [`negative_space`] cache.
866    ///
867    /// [`negative_space`]: Self::negative_space
868    pub fn invalidate_negative_space(&mut self) {
869        self.negative_space.get_mut().1 = false;
870    }
871
872    fn negative_enveloped(&self, space: &mut Vec<PxRect>, bounds: PxRect) {
873        let bounds_max_x = bounds.max_x();
874        let mut last_max_y = bounds.origin.y;
875
876        for r in &self.rows {
877            let spacing_y = r.origin.y - last_max_y;
878            if spacing_y > Px(0) {
879                space.push(PxRect::new(
880                    PxPoint::new(bounds.origin.x, last_max_y),
881                    PxSize::new(bounds.size.width, spacing_y),
882                ));
883            }
884            last_max_y = r.max_y();
885
886            let left = r.origin.x - bounds.origin.x;
887            if left > Px(0) {
888                space.push(PxRect::new(
889                    PxPoint::new(bounds.origin.x, r.origin.y),
890                    PxSize::new(left, r.size.height),
891                ));
892            }
893            let max_x = r.max_x();
894            let right = bounds_max_x - max_x;
895            if right > Px(0) {
896                space.push(PxRect::new(PxPoint::new(max_x, r.origin.y), PxSize::new(right, r.size.height)));
897            }
898        }
899        let spacing_y = bounds.max_y() - last_max_y;
900        if spacing_y > Px(0) {
901            space.push(PxRect::new(
902                PxPoint::new(bounds.origin.x, last_max_y),
903                PxSize::new(bounds.size.width, spacing_y),
904            ));
905        }
906
907        if let Some(r) = self.rows.first()
908            && !self.first_segs.is_empty()
909        {
910            let mut x = r.origin.x;
911            for seg in self.first_segs.iter() {
912                let blank = seg.x - x;
913                if blank > Px(0) {
914                    space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
915                }
916                x = seg.x + seg.width;
917            }
918            let blank = r.max_x() - x;
919            if blank > Px(0) {
920                space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
921            }
922        }
923        if let Some(r) = self.rows.last()
924            && !self.last_segs.is_empty()
925        {
926            let mut x = r.origin.x;
927            for seg in self.last_segs.iter() {
928                let blank = seg.x - x;
929                if blank > Px(0) {
930                    space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
931                }
932                x = seg.x + seg.width;
933            }
934            let blank = r.max_x() - x;
935            if blank > Px(0) {
936                space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
937            }
938        }
939    }
940
941    ///Return info to default state, but retain memory for reuse.
942    pub fn clear(&mut self) {
943        self.first_segs.clear();
944        self.last_segs.clear();
945        self.rows.clear();
946        self.inner_size = PxSize::zero();
947        self.invalidate_negative_space();
948    }
949
950    /// If all value are not different from initial.
951    ///
952    /// This indicates the widget has not handled the inline config yet.
953    pub fn is_default(&self) -> bool {
954        self.rows.is_empty() && self.first_segs.is_empty() && self.last_segs.is_empty() && self.inner_size.is_empty()
955    }
956}
957impl Clone for WidgetInlineInfo {
958    fn clone(&self) -> Self {
959        Self {
960            rows: self.rows.clone(),
961            first_segs: self.first_segs.clone(),
962            last_segs: self.last_segs.clone(),
963            inner_size: self.inner_size,
964            negative_space: Mutex::new((Arc::new(vec![]), false)),
965        }
966    }
967
968    fn clone_from(&mut self, source: &Self) {
969        self.clear();
970        self.rows.extend_from_slice(&source.rows);
971        self.first_segs.extend_from_slice(&source.first_segs);
972        self.last_segs.extend_from_slice(&source.last_segs);
973        self.inner_size = source.inner_size;
974    }
975}
976impl PartialEq for WidgetInlineInfo {
977    fn eq(&self, other: &Self) -> bool {
978        self.rows == other.rows
979            && self.first_segs == other.first_segs
980            && self.last_segs == other.last_segs
981            && self.inner_size == other.inner_size
982    }
983}
984
985/// Represents the in-progress measure pass for a widget tree.
986///
987/// Use [`WidgetLayout::to_measure`] to instantiate.
988pub struct WidgetMeasure {
989    layout_widgets: Arc<LayoutUpdates>,
990    inline: Option<WidgetInlineMeasure>,
991    inline_locked: bool,
992}
993impl WidgetMeasure {
994    pub(crate) fn new(layout_widgets: Arc<LayoutUpdates>) -> Self {
995        Self {
996            layout_widgets,
997            inline: None,
998            inline_locked: false,
999        }
1000    }
1001
1002    /// New with no widget layouts invalidated.
1003    ///
1004    /// Prefer [`WidgetLayout::to_measure`] instead of this.
1005    pub fn new_reuse(inline: Option<WidgetInlineMeasure>) -> Self {
1006        let mut r = Self::new(Arc::default());
1007        r.inline = inline;
1008        r
1009    }
1010
1011    /// If the parent widget is doing inline flow layout.
1012    pub fn is_inline(&self) -> bool {
1013        self.inline.is_some()
1014    }
1015
1016    /// Mutable reference to the current widget's inline info.
1017    ///
1018    /// The widget must configure this to be inlined in parent layout. This is only `Some(_)` if inline is enabled.
1019    ///
1020    /// See [`WidgetInlineMeasure`] for more details.
1021    pub fn inline(&mut self) -> Option<&mut WidgetInlineMeasure> {
1022        self.inline.as_mut()
1023    }
1024
1025    /// Sets [`is_inline`] to `false`.
1026    ///
1027    /// Must be called before child delegation, otherwise children that inline may render expecting to fit in
1028    /// the inline flow.
1029    ///
1030    /// Note that this disables inline for the calling widget's next layout too, every property that affects layout and does
1031    /// not support inline layout must propagate measure using this method to correctly configure the widget.
1032    ///
1033    /// Prefer [`measure_block`] as if also clears the layout constraints.
1034    ///
1035    /// [`is_inline`]: Self::is_inline
1036    /// [`measure_block`]: Self::measure_block
1037    pub fn disable_inline(&mut self) {
1038        if !self.inline_locked {
1039            self.inline = None;
1040        }
1041    }
1042
1043    /// Disable inline and measure child with no inline constraints.
1044    pub fn measure_block(&mut self, child: &mut UiNode) -> PxSize {
1045        self.disable_inline();
1046        LAYOUT.with_no_inline(|| child.measure(self))
1047    }
1048
1049    /// Measure the child node with inline enabled for the `child` node context.
1050    ///
1051    /// The `first_max` and `mid_clear_min` parameters match the [`InlineConstraintsMeasure`] members, and will be set in
1052    /// the `child` context.
1053    ///
1054    /// Note that this does not enabled inline in the calling widget if inlining was disabled by the parent nodes, it creates
1055    /// a new inlining context.
1056    ///
1057    /// Returns the inline requirements of the child and its desired bounds size, returns `None` requirements if the child
1058    /// disables inline or is not a full widget.
1059    ///
1060    /// [`InlineConstraintsMeasure`]: zng_layout::context::InlineConstraintsMeasure
1061    pub fn measure_inline(&mut self, first_max: Px, mid_clear_min: Px, child: &mut UiNode) -> (Option<WidgetInlineMeasure>, PxSize) {
1062        let constraints = InlineConstraints::Measure(InlineConstraintsMeasure::new(first_max, mid_clear_min));
1063        let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1064        let size = LAYOUT.with_context(metrics, || child.measure(self));
1065        let inline = child
1066            .as_widget()
1067            .and_then(|mut w| w.with_context(WidgetUpdateMode::Ignore, || WIDGET.bounds().measure_inline()));
1068        (inline, size)
1069    }
1070
1071    /// Measure a widget.
1072    pub fn with_widget(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1073        let metrics = LAYOUT.metrics();
1074        let bounds = WIDGET.bounds();
1075
1076        let snap = metrics.snapshot();
1077        if !WIDGET.layout_is_pending(&self.layout_widgets) {
1078            let measure_uses = bounds.measure_metrics_used();
1079            if bounds.measure_metrics().map(|m| m.masked_eq(&snap, measure_uses)).unwrap_or(false) {
1080                let mut reused = false;
1081                if let Some(inline) = self.inline() {
1082                    if let Some(prev) = bounds.measure_inline() {
1083                        *inline = prev;
1084                        reused = true;
1085                    }
1086                } else {
1087                    reused = bounds.measure_inline().is_none();
1088                }
1089
1090                if reused {
1091                    // LAYOUT.register_metrics_use(measure_uses); // measure does not propagate uses.
1092                    return bounds.measure_outer_size();
1093                }
1094            }
1095        }
1096
1097        let parent_inline = self.inline.take();
1098        if LAYOUT.inline_constraints().is_some() {
1099            self.inline = Some(Default::default());
1100        }
1101
1102        let (measure_uses, size) = LAYOUT.capture_metrics_use(|| measure(self));
1103
1104        bounds.set_measure_metrics(Some(snap), measure_uses);
1105        bounds.set_measure_outer_size(size);
1106
1107        if let Some(inline) = self.inline.take() {
1108            if inline.is_default() && !size.is_empty() {
1109                // widget did not handle inline
1110                bounds.set_measure_inline(None);
1111            } else {
1112                #[cfg(debug_assertions)]
1113                if !inline.last_wrapped && inline.first != inline.last {
1114                    tracing::error!(
1115                        "widget {:?} invalid inline measure, last {:?} != first {:?} but last did not wrap",
1116                        WIDGET.id(),
1117                        inline.last,
1118                        inline.first
1119                    );
1120                }
1121
1122                bounds.set_measure_inline(Some(inline));
1123            }
1124        } else {
1125            bounds.set_measure_inline(None);
1126        }
1127        self.inline = parent_inline;
1128
1129        size
1130    }
1131
1132    /// Calls `measure` with inline force enabled on the widget.
1133    ///
1134    /// The widget will be inlining even if the parent widget is not inlining, if properties request [`disable_inline`]
1135    /// these requests are ignored.
1136    ///
1137    /// [`disable_inline`]: crate::widget::info::WidgetMeasure::disable_inline
1138    pub fn with_inline_visual(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1139        self.inline_locked = true;
1140        if self.inline.is_none() {
1141            self.inline = Some(Default::default());
1142        }
1143        let metrics = LAYOUT.metrics();
1144        let size = if metrics.inline_constraints().is_none() {
1145            let constraints = InlineConstraints::Measure(InlineConstraintsMeasure::new(metrics.constraints().x.max_or(Px::MAX), Px(0)));
1146            let metrics = metrics.with_inline_constraints(Some(constraints));
1147            LAYOUT.with_context(metrics, || measure(self))
1148        } else {
1149            measure(self)
1150        };
1151        self.inline_locked = false;
1152
1153        let inline = self.inline.clone().unwrap();
1154        let bounds = WIDGET.bounds();
1155        if inline.is_default() && !size.is_empty() {
1156            // widget did not handle inline
1157            bounds.set_measure_inline(None);
1158        } else {
1159            bounds.set_measure_inline(Some(inline));
1160        }
1161        bounds.set_measure_outer_size(size);
1162
1163        size
1164    }
1165
1166    /// Start a parallel measure.
1167    ///
1168    /// Returns an instance that can be used to acquire multiple mutable [`WidgetMeasure`] during measure.
1169    /// The [`parallel_fold`] method must be called after the parallel processing is done.
1170    ///
1171    /// [`parallel_fold`]: Self::parallel_fold
1172    pub fn parallel_split(&self) -> ParallelBuilder<WidgetMeasure> {
1173        ParallelBuilder(Some(Self {
1174            layout_widgets: self.layout_widgets.clone(),
1175            inline: self.inline.clone(),
1176            inline_locked: self.inline_locked,
1177        }))
1178    }
1179
1180    /// Collect the parallel changes back.
1181    pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetMeasure>) {
1182        let _ = split.take();
1183    }
1184}
1185
1186/// Represents the in-progress layout pass for a widget tree.
1187pub struct WidgetLayout {
1188    layout_widgets: Arc<LayoutUpdates>,
1189    bounds: WidgetBoundsInfo,
1190    nest_group: LayoutNestGroup,
1191    inline: Option<WidgetInlineInfo>,
1192    needs_ref_count: Option<u32>,
1193}
1194impl WidgetLayout {
1195    /// Defines the root widget outer-bounds scope.
1196    ///
1197    /// The default window implementation calls this inside the root widget context.
1198    pub fn with_root_widget(layout_widgets: Arc<LayoutUpdates>, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1199        Self {
1200            layout_widgets,
1201            bounds: WIDGET.bounds(),
1202            nest_group: LayoutNestGroup::Inner,
1203            inline: None,
1204            needs_ref_count: None,
1205        }
1206        .with_widget(layout)
1207    }
1208
1209    /// Start a parallel layout.
1210    ///
1211    /// Returns an instance that can be used to acquire multiple mutable [`WidgetLayout`] during layout.
1212    /// The [`parallel_fold`] method must be called after the parallel processing is done.
1213    ///
1214    /// Must be called outside of the [child] scope.
1215    ///
1216    /// [child]: Self::with_child
1217    /// [`parallel_fold`]: Self::parallel_fold
1218    pub fn parallel_split(&self) -> ParallelBuilder<WidgetLayout> {
1219        if self.nest_group != LayoutNestGroup::Child && WIDGET.parent_id().is_some() {
1220            tracing::error!("called `parallel_split` outside child scope");
1221        }
1222        ParallelBuilder(Some(WidgetLayout {
1223            layout_widgets: self.layout_widgets.clone(),
1224            bounds: self.bounds.clone(),
1225            nest_group: LayoutNestGroup::Child,
1226            inline: None,
1227            needs_ref_count: None,
1228        }))
1229    }
1230
1231    /// Collect the parallel changes back.
1232    pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetLayout>) {
1233        let folded = split.take();
1234        assert_eq!(self.bounds, folded.bounds);
1235
1236        let count = self.needs_ref_count.unwrap_or(0) + folded.needs_ref_count.unwrap_or(0);
1237        self.needs_ref_count = Some(count);
1238    }
1239
1240    /// Defines a widget scope, translations inside `layout` target the widget's inner offset.
1241    ///
1242    /// If the widget layout is not invalidated and none of the used metrics have changed skips calling
1243    /// `layout` and returns the current outer-size, the outer transform is still updated.
1244    ///
1245    /// The default widget constructor calls this, see [`base::node::widget`].
1246    ///
1247    /// [`base::node::widget`]: crate::widget::base::node::widget
1248    pub fn with_widget(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1249        let metrics = LAYOUT.metrics();
1250        let bounds = WIDGET.bounds();
1251
1252        let snap = metrics.snapshot();
1253        if let Some(c) = &mut self.needs_ref_count {
1254            *c += 1;
1255        }
1256
1257        if !WIDGET.take_update(UpdateFlags::LAYOUT) && !self.layout_widgets.delivery_list().enter_widget(WIDGET.id()) {
1258            // layout not invalidated by request
1259            let uses = bounds.metrics_used();
1260            if bounds.metrics().map(|m| m.masked_eq(&snap, uses)).unwrap_or(false) {
1261                // layout not invalidated by used metrics
1262                LAYOUT.register_metrics_use(uses); // propagate to parent
1263                return bounds.outer_size();
1264            }
1265        }
1266
1267        let parent_needs_ref_count = self.needs_ref_count.take();
1268        let parent_inline = self.inline.take();
1269        if LAYOUT.inline_constraints().is_some() && bounds.measure_inline().is_some() {
1270            // inline enabled by parent and widget
1271            self.inline = bounds.take_inline();
1272            if let Some(inline) = self.inline.as_mut() {
1273                inline.clear();
1274            } else {
1275                self.inline = Some(Default::default());
1276            }
1277        }
1278        let parent_bounds = mem::replace(&mut self.bounds, bounds);
1279        self.nest_group = LayoutNestGroup::Inner;
1280        let prev_inner_offset = self.bounds.inner_offset();
1281        let prev_child_offset = self.bounds.child_offset();
1282        let prev_baseline = self.bounds.baseline();
1283        let prev_inner_offset_baseline = self.bounds.inner_offset_baseline();
1284        let prev_can_auto_hide = self.bounds.can_auto_hide();
1285        let prev_transform_style = self.bounds.transform_style();
1286        let prev_perspective = self.bounds.raw_perspective();
1287        let prev_perspective_origin = self.bounds.raw_perspective_origin();
1288        self.bounds.set_inner_offset(PxVector::zero());
1289        self.bounds.set_child_offset(PxVector::zero());
1290        self.bounds.set_baseline(Px(0));
1291        self.bounds.set_inner_offset_baseline(false);
1292        self.bounds.set_can_auto_hide(true);
1293        self.bounds.set_transform_style(TransformStyle::Flat);
1294        self.bounds.set_perspective(f32::INFINITY);
1295        self.bounds.set_perspective_origin(None);
1296
1297        // layout
1298        let (uses, size) = LAYOUT.capture_metrics_use(|| layout(self));
1299
1300        LAYOUT.register_metrics_use(uses);
1301        self.bounds.set_outer_size(size);
1302        self.bounds.set_metrics(Some(snap), uses);
1303        if let Some(inline) = &mut self.inline {
1304            inline.inner_size = self.bounds.inner_size();
1305            inline.invalidate_negative_space();
1306        }
1307        self.bounds.set_inline(self.inline.take());
1308
1309        if prev_can_auto_hide != self.bounds.can_auto_hide() || prev_transform_style != self.bounds.transform_style() {
1310            WIDGET.render();
1311        } else if prev_inner_offset != self.bounds.inner_offset()
1312            || prev_child_offset != self.bounds.child_offset()
1313            || prev_inner_offset_baseline != self.bounds.inner_offset_baseline()
1314            || prev_perspective != self.bounds.raw_perspective()
1315            || prev_perspective_origin != self.bounds.raw_perspective_origin()
1316            || (self.bounds.inner_offset_baseline() && prev_baseline != self.bounds.baseline())
1317        {
1318            WIDGET.render_update();
1319        }
1320
1321        self.needs_ref_count = parent_needs_ref_count;
1322        self.inline = parent_inline;
1323        self.bounds = parent_bounds;
1324        self.nest_group = LayoutNestGroup::Child;
1325
1326        size
1327    }
1328
1329    /// Calls `layout` with inline force enabled on the widget.
1330    ///
1331    /// The widget will use the inline visual even if the parent did not inline it, but it will not
1332    /// inline if it has properties that disable inlining.
1333    pub fn with_inline_visual(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1334        if self.is_inline() {
1335            let size = layout(self);
1336            WIDGET.bounds().set_inline(self.inline.clone());
1337            size
1338        } else {
1339            let bounds = WIDGET.bounds();
1340            if let Some(measure) = bounds.measure_inline() {
1341                let constraints = InlineConstraintsLayout::new(
1342                    PxRect::from_size(measure.first),
1343                    Px(0),
1344                    {
1345                        let mut r = PxRect::from_size(measure.last);
1346                        r.origin.y = bounds.measure_outer_size().height - measure.last.height;
1347                        r
1348                    },
1349                    Arc::new(vec![]),
1350                    Arc::new(vec![]),
1351                );
1352
1353                self.inline = Some(Default::default());
1354
1355                let metrics = LAYOUT
1356                    .metrics()
1357                    .with_inline_constraints(Some(InlineConstraints::Layout(constraints)));
1358                let size = LAYOUT.with_context(metrics, || layout(self));
1359
1360                bounds.set_inline(self.inline.clone());
1361                size
1362            } else {
1363                layout(self)
1364            }
1365        }
1366    }
1367
1368    /// Defines the widget's inner scope, translations inside `layout` target the widget's child offset.
1369    ///
1370    /// This method also updates the border info.
1371    ///
1372    /// The default widget borders constructor calls this, see [`base::node::widget_inner`].
1373    ///
1374    /// [`base::node::widget_inner`]: crate::widget::base::node::widget_inner
1375    pub fn with_inner(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1376        self.nest_group = LayoutNestGroup::Child;
1377        let size = BORDER.with_inner(|| layout(self));
1378        WIDGET.bounds().set_inner_size(size);
1379        self.nest_group = LayoutNestGroup::Inner;
1380        size
1381    }
1382
1383    /// Defines the widget's child scope, translations inside `layout` target the widget's child offset.
1384    ///
1385    /// Returns the child size and if a reference frame is required to offset the child.
1386    ///
1387    /// The default widget child layout constructor implements this, see [`base::node::widget_child`].
1388    ///
1389    /// [`base::node::widget_child`]: crate::widget::base::node::widget_child
1390    /// [`child_offset`]: WidgetBoundsInfo::child_offset
1391    /// [`with_branch_child`]: Self::with_branch_child
1392    pub fn with_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, bool) {
1393        let parent_needs_ref_count = self.needs_ref_count.replace(0);
1394
1395        self.nest_group = LayoutNestGroup::Child;
1396        let child_size = layout(self);
1397        self.nest_group = LayoutNestGroup::Child;
1398
1399        let need_ref_frame = self.needs_ref_count != Some(1);
1400        self.needs_ref_count = parent_needs_ref_count;
1401        (child_size, need_ref_frame)
1402    }
1403
1404    /// Ensure that the parent [`with_child`] will receive a reference frame request.
1405    ///
1406    /// Nodes that branch out children inside the widget's child scope must call this to ensure that the offsets
1407    /// are not given to the only widget child among other nodes.
1408    ///
1409    /// [`with_child`]: Self::with_child
1410    pub fn require_child_ref_frame(&mut self) {
1411        if let Some(c) = &mut self.needs_ref_count {
1412            *c += 2;
1413        }
1414    }
1415
1416    /// Defines a custom scope that does not affect the widget's offsets, only any widget inside `layout`.
1417    ///
1418    /// Nodes that branch out children outside widget's child scope must use this method.
1419    ///
1420    /// Returns the output of `layout` and a translate vector if any translations inside `layout` where not handled
1421    /// by child widgets.
1422    pub fn with_branch_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, PxVector) {
1423        let parent_needs_ref_count = self.needs_ref_count;
1424        let parent_translate = self.bounds.child_offset();
1425        let parent_inner_offset_baseline = self.bounds.inner_offset_baseline();
1426        self.bounds.set_child_offset(PxVector::zero());
1427        let parent_group = self.nest_group;
1428
1429        self.nest_group = LayoutNestGroup::Child;
1430        let child_size = layout(self);
1431
1432        let translate = self.bounds.child_offset();
1433        self.bounds.set_child_offset(parent_translate);
1434        self.bounds.set_inner_offset_baseline(parent_inner_offset_baseline);
1435        self.nest_group = parent_group;
1436        self.needs_ref_count = parent_needs_ref_count;
1437
1438        (child_size, translate)
1439    }
1440
1441    /// Adds the `offset` to the closest *inner* bounds offset.
1442    ///
1443    /// This affects the inner offset if called from a node inside the widget and before the `BORDER` group, or it affects
1444    /// the child offset if called inside the widget and inside the `BORDER` group.
1445    pub fn translate(&mut self, offset: PxVector) {
1446        match self.nest_group {
1447            LayoutNestGroup::Inner => {
1448                let mut o = self.bounds.inner_offset();
1449                o += offset;
1450                self.bounds.set_inner_offset(o);
1451            }
1452            LayoutNestGroup::Child => {
1453                let mut o = self.bounds.child_offset();
1454                o += offset;
1455                self.bounds.set_child_offset(o);
1456            }
1457        }
1458    }
1459
1460    /// Set the baseline offset of the widget. The value is up from the bottom of the inner bounds.
1461    pub fn set_baseline(&mut self, baseline: Px) {
1462        self.bounds.set_baseline(baseline);
1463    }
1464
1465    /// Set if the baseline is added to the inner offset *y* axis.
1466    pub fn translate_baseline(&mut self, enabled: bool) {
1467        self.bounds.set_inner_offset_baseline(enabled);
1468    }
1469
1470    /// Set if the widget preserved 3D perspective form the parent.
1471    pub fn set_transform_style(&mut self, style: TransformStyle) {
1472        self.bounds.set_transform_style(style);
1473    }
1474
1475    /// Set the 3D perspective that defines the children 3D space.
1476    ///
1477    /// This is the distance from the Z-plane to the viewer.
1478    pub fn set_perspective(&mut self, d: f32) {
1479        self.bounds.set_perspective(d)
1480    }
1481
1482    /// Sets the vanishing point of the children 3D space as a point in the inner bounds of this widget.
1483    pub fn set_perspective_origin(&mut self, origin: PxPoint) {
1484        self.bounds.set_perspective_origin(Some(origin))
1485    }
1486
1487    /// Sets if the widget only renders if [`outer_bounds`] intersects with the [`FrameBuilder::auto_hide_rect`].
1488    ///
1489    /// This is `true` by default.
1490    ///
1491    /// [`outer_bounds`]: WidgetBoundsInfo::outer_bounds
1492    /// [`FrameBuilder::auto_hide_rect`]: crate::render::FrameBuilder::auto_hide_rect
1493    pub fn allow_auto_hide(&mut self, enabled: bool) {
1494        self.bounds.set_can_auto_hide(enabled);
1495    }
1496
1497    /// Collapse the layout of `self` and descendants, the size and offsets are set to zero.
1498    ///
1499    /// Nodes that set the visibility to the equivalent of [`Collapsed`] must skip layout and return `PxSize::zero` as
1500    /// the size, ignoring the min-size constraints, and call this method to update all the descendant
1501    /// bounds information to be a zero-sized point.
1502    ///
1503    /// Note that the widget will automatically not be rendered when collapsed.
1504    ///
1505    /// [`Collapsed`]: Visibility::Collapsed
1506    pub fn collapse(&mut self) {
1507        WIDGET.take_update(UpdateFlags::LAYOUT);
1508        let tree = WINDOW.info();
1509        let id = WIDGET.id();
1510        if let Some(w) = tree.get(id) {
1511            for w in w.self_and_descendants() {
1512                let info = w.info();
1513                info.bounds_info.set_outer_size(PxSize::zero());
1514                info.bounds_info.set_inner_size(PxSize::zero());
1515                info.bounds_info.set_baseline(Px(0));
1516                info.bounds_info.set_inner_offset_baseline(false);
1517                info.bounds_info.set_can_auto_hide(true);
1518                info.bounds_info.set_inner_offset(PxVector::zero());
1519                info.bounds_info.set_child_offset(PxVector::zero());
1520                info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1521                info.bounds_info.set_metrics(None, LayoutMask::empty());
1522                info.bounds_info.set_is_collapsed(true);
1523                info.bounds_info.set_rendered(None, &tree);
1524            }
1525        } else {
1526            tracing::error!("collapse did not find `{}` in the info tree", id)
1527        }
1528    }
1529
1530    /// Collapse layout of all descendants, the size and offsets are set to zero.
1531    ///
1532    /// Widgets that control the visibility of their children can use this method and then, in the same layout pass, layout
1533    /// the children that should be visible.
1534    ///
1535    /// Note that the widgets will automatically not be rendered when collapsed.
1536    ///
1537    /// [`Collapsed`]: Visibility::Collapsed
1538    pub fn collapse_descendants(&mut self) {
1539        let tree = WINDOW.info();
1540        let id = WIDGET.id();
1541        if let Some(w) = tree.get(id) {
1542            for w in w.descendants() {
1543                let info = w.info();
1544                info.bounds_info.set_outer_size(PxSize::zero());
1545                info.bounds_info.set_inner_size(PxSize::zero());
1546                info.bounds_info.set_baseline(Px(0));
1547                info.bounds_info.set_inner_offset_baseline(false);
1548                info.bounds_info.set_can_auto_hide(true);
1549                info.bounds_info.set_inner_offset(PxVector::zero());
1550                info.bounds_info.set_child_offset(PxVector::zero());
1551                info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1552                info.bounds_info.set_metrics(None, LayoutMask::empty());
1553                info.bounds_info.set_is_collapsed(true);
1554            }
1555        } else {
1556            tracing::error!("collapse_descendants did not find `{}` in the info tree", id)
1557        }
1558    }
1559
1560    /// Collapse layout of the child and all its descendants, the size and offsets are set to zero.
1561    ///
1562    /// Widgets that control the visibility of their children can use this method and then, in the same layout pass, layout
1563    /// the children that should be visible.
1564    ///
1565    /// Note that the widgets will automatically not be rendered when collapsed.
1566    ///
1567    /// [`Collapsed`]: Visibility::Collapsed
1568    pub fn collapse_child(&mut self, index: usize) {
1569        let tree = WINDOW.info();
1570        let id = WIDGET.id();
1571        if let Some(w) = tree.get(id) {
1572            if let Some(w) = w.children().nth(index) {
1573                for w in w.self_and_descendants() {
1574                    let info = w.info();
1575                    info.bounds_info.set_outer_size(PxSize::zero());
1576                    info.bounds_info.set_inner_size(PxSize::zero());
1577                    info.bounds_info.set_baseline(Px(0));
1578                    info.bounds_info.set_inner_offset_baseline(false);
1579                    info.bounds_info.set_can_auto_hide(true);
1580                    info.bounds_info.set_inner_offset(PxVector::zero());
1581                    info.bounds_info.set_child_offset(PxVector::zero());
1582                    info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1583                    info.bounds_info.set_metrics(None, LayoutMask::empty());
1584                    info.bounds_info.set_is_collapsed(true);
1585                }
1586            } else {
1587                tracing::error!(
1588                    "collapse_child out-of-bounds for `{}` in the children of `{}` in the info tree",
1589                    index,
1590                    id
1591                )
1592            }
1593        } else {
1594            tracing::error!("collapse_child did not find `{}` in the info tree", id)
1595        }
1596    }
1597
1598    /// If the parent widget is doing inline layout and this widget signaled that it can support this
1599    /// during measure.
1600    ///
1601    /// See [`WidgetMeasure::inline`] for more details.
1602    pub fn is_inline(&self) -> bool {
1603        self.inline.is_some()
1604    }
1605
1606    /// Mutable reference to the current widget's inline info.
1607    ///
1608    /// This is `Some(_)` if the parent widget is doing inline layout and this widget signaled that it can be inlined
1609    /// in the previous measure pass. You can use [`WidgetMeasure::disable_inline`] in the measure pass to disable
1610    /// inline in both passes, measure and layout.
1611    ///
1612    /// The rows and negative space are already reset when widget layout started, and the inner size will be updated when
1613    /// the widget layout ends, the inline layout node only needs to push rows.
1614    ///
1615    /// When this is `Some(_)` the [`LayoutMetrics::inline_constraints`] is also `Some(_)`.
1616    ///
1617    /// See [`WidgetInlineInfo`] for more details.
1618    ///
1619    /// [`LayoutMetrics::inline_constraints`]: zng_layout::context::LayoutMetrics::inline_constraints
1620    pub fn inline(&mut self) -> Option<&mut WidgetInlineInfo> {
1621        self.inline.as_mut()
1622    }
1623
1624    /// Create an [`WidgetMeasure`] for an [`UiNode::measure`] call.
1625    ///
1626    /// [`UiNode::measure`]: crate::widget::node::UiNode::measure
1627    pub fn to_measure(&self, inline: Option<WidgetInlineMeasure>) -> WidgetMeasure {
1628        WidgetMeasure {
1629            layout_widgets: self.layout_widgets.clone(),
1630            inline,
1631            inline_locked: false,
1632        }
1633    }
1634
1635    /// Layout the child node in a context without inline constraints.
1636    ///
1637    /// This must be called inside inlining widgets to layout block child nodes, otherwise the inline constraints from
1638    /// the calling widget propagate to the child.
1639    pub fn layout_block(&mut self, child: &mut UiNode) -> PxSize {
1640        LAYOUT.with_no_inline(|| child.layout(self))
1641    }
1642
1643    /// Layout the child node with inline enabled in the `child` node context.
1644    ///
1645    /// The `mid_clear`, `last`, `first_segs` and `last_segs` parameters match the [`InlineConstraintsLayout`] members, and will be set in
1646    /// the `child` context.
1647    ///
1648    /// Returns the child final size.
1649    ///
1650    /// [`InlineConstraintsLayout`]: zng_layout::context::InlineConstraintsLayout
1651    pub fn layout_inline(
1652        &mut self,
1653        first: PxRect,
1654        mid_clear: Px,
1655        last: PxRect,
1656        first_segs: Arc<Vec<InlineSegmentPos>>,
1657        last_segs: Arc<Vec<InlineSegmentPos>>,
1658        child: &mut UiNode,
1659    ) -> PxSize {
1660        let constraints = InlineConstraints::Layout(InlineConstraintsLayout::new(first, mid_clear, last, first_segs, last_segs));
1661        let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1662        LAYOUT.with_context(metrics, || child.layout(self))
1663    }
1664
1665    /// Call `layout` with a different set of `layout_updates`.
1666    ///
1667    /// This is usually managed by the window implementer, nested windows can use this to override the updates.
1668    pub fn with_layout_updates(&mut self, layout_updates: Arc<LayoutUpdates>, layout: impl FnOnce(&mut WidgetLayout) -> PxSize) -> PxSize {
1669        let parent_layout_widgets = mem::replace(&mut self.layout_widgets, layout_updates);
1670        let r = layout(self);
1671        self.layout_widgets = parent_layout_widgets;
1672        r
1673    }
1674}
1675
1676#[derive(Debug, Clone, Copy, PartialEq)]
1677enum LayoutNestGroup {
1678    /// Inside widget, outside `BORDER`.
1679    Inner,
1680    /// Inside `BORDER`.
1681    Child,
1682}
1683
1684/// Represents a builder split from the main builder that can be used in parallel and then folded
1685/// back onto the main builder.
1686///
1687/// # Error
1688///
1689/// Logs an error on drop if it was not moved to the `B::parallel_fold` method.
1690#[must_use = "use in parallel task, then move it to `B::parallel_fold`"]
1691pub struct ParallelBuilder<B>(pub(crate) Option<B>);
1692impl<B> ParallelBuilder<B> {
1693    pub(crate) fn take(&mut self) -> B {
1694        self.0.take().expect("parallel builder finished")
1695    }
1696}
1697impl<B> ops::Deref for ParallelBuilder<B> {
1698    type Target = B;
1699
1700    fn deref(&self) -> &Self::Target {
1701        self.0.as_ref().expect("parallel builder finished")
1702    }
1703}
1704impl<B> ops::DerefMut for ParallelBuilder<B> {
1705    fn deref_mut(&mut self) -> &mut Self::Target {
1706        self.0.as_mut().expect("parallel builder finished")
1707    }
1708}
1709impl<B> Drop for ParallelBuilder<B> {
1710    fn drop(&mut self) {
1711        if self.0.is_some() && !std::thread::panicking() {
1712            tracing::error!("builder dropped without calling `{}::parallel_fold`", std::any::type_name::<B>())
1713        }
1714    }
1715}