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)]
652pub struct WidgetInlineMeasure {
653    /// Preferred first size.
654    ///
655    /// In left-to-right direction the origin is `top_left`, in right-to-left direction the origin is `top_right - first.width`.
656    pub first: PxSize,
657
658    /// Indicates that `first` starts in the next row, not in the *current* row defined by the inline constraints.
659    pub first_wrapped: bool,
660
661    /// Inline segments in the first row.
662    ///
663    /// The sum of segment widths must be less or equal to the `first.width`.
664    pub first_segs: Arc<Vec<InlineSegment>>,
665
666    /// Preferred last size.
667    ///
668    /// In left-to-right direction the origin is `bottom_left - last.height`, in right-to-left direction
669    /// the origin is `bottom_right - last`.
670    ///
671    /// Must be equal to `first` if did not wrap.
672    ///
673    /// Must not be empty if first is not empty, that is, must not wrap if the last item can fit in the previous row.
674    pub last: PxSize,
675
676    /// Indicates that `last` starts in a next row, not in the same row as the first.
677    pub last_wrapped: bool,
678
679    /// Inline segments in the last row.
680    ///
681    /// The sum of segment widths must be less or equal to the `last.width`.
682    pub last_segs: Arc<Vec<InlineSegment>>,
683}
684impl WidgetInlineMeasure {
685    /// Visit a mutable reference to the new [`first_segs`] value, `f` is called with
686    /// an empty vec that can be reused or new.
687    ///
688    /// [`first_segs`]: Self::first_segs
689    pub fn with_first_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
690        Self::with_segs(&mut self.first_segs, f)
691    }
692
693    /// Visit a mutable reference to the new [`last_segs`] value, `f` is called with
694    /// an empty vec that can be reused or new.
695    ///
696    /// [`last_segs`]: Self::last_segs
697    pub fn with_last_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
698        Self::with_segs(&mut self.last_segs, f)
699    }
700
701    fn with_segs(items: &mut Arc<Vec<InlineSegment>>, f: impl FnOnce(&mut Vec<InlineSegment>)) {
702        match Arc::get_mut(items) {
703            Some(items) => {
704                items.clear();
705                f(items);
706            }
707            None => {
708                let mut new = vec![];
709                f(&mut new);
710                *items = Arc::new(new);
711            }
712        }
713    }
714
715    /// If all value are not different from initial.
716    ///
717    /// This indicates the widget has not handled the inline config yet.
718    pub fn is_default(&self) -> bool {
719        self.first.is_empty()
720            && !self.first_wrapped
721            && self.first_segs.is_empty()
722            && self.last.is_empty()
723            && !self.last_wrapped
724            && self.last_segs.is_empty()
725    }
726}
727
728/// Info about a segment in the first or last row of an inlined widget.
729///
730/// See [`WidgetInlineInfo::first_segs`] for more details.
731#[derive(Clone, Copy, Debug, PartialEq, Eq)]
732pub struct InlineSegmentInfo {
733    /// Segment offset from the row rectangle origin.
734    pub x: Px,
735    /// Segment width.
736    ///
737    /// Note that the segment height is the row rectangle height.
738    pub width: Px,
739}
740
741/// Info about the inlined rows of the widget.
742#[derive(Debug, Default)]
743pub struct WidgetInlineInfo {
744    /// Last layout rows of the widget.
745    ///
746    /// The rectangles are in the widget's inner space, from top to bottom.
747    pub rows: Vec<PxRect>,
748
749    /// Segments of the first row.
750    ///
751    /// If this is empty the entire row width is a continuous segment, otherwise the row is segmented and
752    /// the widget can be interleaved with sibling widgets due to Unicode bidirectional text sorting algorithm.
753    ///
754    /// Note that the segment count may be less then [`WidgetInlineMeasure::first_segs`] as contiguous segments
755    /// may be merged.
756    ///
757    /// The segments are from left to right.
758    pub first_segs: Vec<InlineSegmentInfo>,
759
760    /// Segments of the last row.
761    pub last_segs: Vec<InlineSegmentInfo>,
762
763    /// Widget inner size when the rows where last updated.
764    pub inner_size: PxSize,
765
766    negative_space: Mutex<(Arc<Vec<PxRect>>, bool)>,
767}
768impl WidgetInlineInfo {
769    /// Replace the [`first_segs`] with `segs`.
770    ///
771    /// The segments are sorted when needed, but prefer inputs that are mostly sorted.
772    ///
773    /// The segments are merged when there is no gap or there is a small one pixel overlap to the previous segment.
774    ///
775    /// [`first_segs`]: Self::first_segs
776    pub fn set_first_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
777        Self::set_segs(&mut self.first_segs, segs);
778        self.invalidate_negative_space();
779    }
780
781    /// Replace the [`last_segs`] with `segs`.
782    ///
783    /// The segments are sorted when needed, but prefer inputs that are mostly sorted.
784    ///
785    /// The segments are merged when there is no gap or there is a small one pixel overlap to the previous segment.
786    ///
787    /// [`last_segs`]: Self::last_segs
788    pub fn set_last_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
789        Self::set_segs(&mut self.last_segs, segs);
790        self.invalidate_negative_space();
791    }
792
793    fn set_segs(vec: &mut Vec<InlineSegmentInfo>, segs: impl Iterator<Item = InlineSegmentInfo>) {
794        vec.clear();
795
796        let mut needs_sort = false;
797
798        for seg in segs {
799            if seg.width <= 0 {
800                continue;
801            }
802
803            if let Some(last) = vec.last_mut() {
804                let la = last.x;
805                let lb = last.x + last.width;
806
807                let a = seg.x;
808                let b = seg.x + seg.width;
809
810                if la.max(a) <= lb.min(b) {
811                    // merge overlap
812                    last.x = a.min(la);
813                    last.width = b.max(lb) - last.x;
814                    continue;
815                }
816
817                needs_sort |= a < la;
818            }
819            vec.push(seg);
820        }
821
822        if needs_sort {
823            vec.sort_unstable_by_key(|s| s.x);
824        }
825    }
826
827    /// Gets the union of all row rectangles.
828    pub fn union(&self) -> PxRect {
829        self.rows.iter().fold(PxRect::zero(), |union, row| union.union(row))
830    }
831
832    /// Gets or computes the negative space of the [`rows`] in the [`inner_size`] space, that is, all the areas that are
833    /// not covered by any row and not covered by the first and last row segments.
834    ///
835    /// This is computed on demand and cached.
836    ///
837    /// [`rows`]: Self::rows
838    /// [`inner_size`]: Self::inner_size
839    pub fn negative_space(&self) -> Arc<Vec<PxRect>> {
840        let mut space = self.negative_space.lock();
841        if space.1 {
842            return space.0.clone();
843        }
844
845        let mut vec = Arc::try_unwrap(mem::take(&mut space.0)).unwrap_or_default();
846        vec.clear();
847
848        self.negative_enveloped(&mut vec, PxRect::from_size(self.inner_size));
849
850        let r = Arc::new(vec);
851        *space = (r.clone(), true);
852        r
853    }
854
855    /// Invalidates the [`negative_space`] cache.
856    ///
857    /// [`negative_space`]: Self::negative_space
858    pub fn invalidate_negative_space(&mut self) {
859        self.negative_space.get_mut().1 = false;
860    }
861
862    fn negative_enveloped(&self, space: &mut Vec<PxRect>, bounds: PxRect) {
863        let bounds_max_x = bounds.max_x();
864        let mut last_max_y = bounds.origin.y;
865
866        for r in &self.rows {
867            let spacing_y = r.origin.y - last_max_y;
868            if spacing_y > Px(0) {
869                space.push(PxRect::new(
870                    PxPoint::new(bounds.origin.x, last_max_y),
871                    PxSize::new(bounds.size.width, spacing_y),
872                ));
873            }
874            last_max_y = r.max_y();
875
876            let left = r.origin.x - bounds.origin.x;
877            if left > Px(0) {
878                space.push(PxRect::new(
879                    PxPoint::new(bounds.origin.x, r.origin.y),
880                    PxSize::new(left, r.size.height),
881                ));
882            }
883            let max_x = r.max_x();
884            let right = bounds_max_x - max_x;
885            if right > Px(0) {
886                space.push(PxRect::new(PxPoint::new(max_x, r.origin.y), PxSize::new(right, r.size.height)));
887            }
888        }
889        let spacing_y = bounds.max_y() - last_max_y;
890        if spacing_y > Px(0) {
891            space.push(PxRect::new(
892                PxPoint::new(bounds.origin.x, last_max_y),
893                PxSize::new(bounds.size.width, spacing_y),
894            ));
895        }
896
897        if let Some(r) = self.rows.first() {
898            if !self.first_segs.is_empty() {
899                let mut x = r.origin.x;
900                for seg in self.first_segs.iter() {
901                    let blank = seg.x - x;
902                    if blank > Px(0) {
903                        space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
904                    }
905                    x = seg.x + seg.width;
906                }
907                let blank = r.max_x() - x;
908                if blank > Px(0) {
909                    space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
910                }
911            }
912        }
913        if let Some(r) = self.rows.last() {
914            if !self.last_segs.is_empty() {
915                let mut x = r.origin.x;
916                for seg in self.last_segs.iter() {
917                    let blank = seg.x - x;
918                    if blank > Px(0) {
919                        space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
920                    }
921                    x = seg.x + seg.width;
922                }
923                let blank = r.max_x() - x;
924                if blank > Px(0) {
925                    space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
926                }
927            }
928        }
929    }
930
931    ///Return info to default state, but retain memory for reuse.
932    pub fn clear(&mut self) {
933        self.first_segs.clear();
934        self.last_segs.clear();
935        self.rows.clear();
936        self.inner_size = PxSize::zero();
937        self.invalidate_negative_space();
938    }
939
940    /// If all value are not different from initial.
941    ///
942    /// This indicates the widget has not handled the inline config yet.
943    pub fn is_default(&self) -> bool {
944        self.rows.is_empty() && self.first_segs.is_empty() && self.last_segs.is_empty() && self.inner_size.is_empty()
945    }
946}
947impl Clone for WidgetInlineInfo {
948    fn clone(&self) -> Self {
949        Self {
950            rows: self.rows.clone(),
951            first_segs: self.first_segs.clone(),
952            last_segs: self.last_segs.clone(),
953            inner_size: self.inner_size,
954            negative_space: Mutex::new((Arc::new(vec![]), false)),
955        }
956    }
957
958    fn clone_from(&mut self, source: &Self) {
959        self.clear();
960        self.rows.extend_from_slice(&source.rows);
961        self.first_segs.extend_from_slice(&source.first_segs);
962        self.last_segs.extend_from_slice(&source.last_segs);
963        self.inner_size = source.inner_size;
964    }
965}
966impl PartialEq for WidgetInlineInfo {
967    fn eq(&self, other: &Self) -> bool {
968        self.rows == other.rows
969            && self.first_segs == other.first_segs
970            && self.last_segs == other.last_segs
971            && self.inner_size == other.inner_size
972    }
973}
974
975/// Represents the in-progress measure pass for a widget tree.
976///
977/// Use [`WidgetLayout::to_measure`] to instantiate.
978pub struct WidgetMeasure {
979    layout_widgets: Arc<LayoutUpdates>,
980    inline: Option<WidgetInlineMeasure>,
981    inline_locked: bool,
982}
983impl WidgetMeasure {
984    pub(crate) fn new(layout_widgets: Arc<LayoutUpdates>) -> Self {
985        Self {
986            layout_widgets,
987            inline: None,
988            inline_locked: false,
989        }
990    }
991
992    /// New with no widget layouts invalidated.
993    ///
994    /// Prefer [`WidgetLayout::to_measure`] instead of this.
995    pub fn new_reuse(inline: Option<WidgetInlineMeasure>) -> Self {
996        let mut r = Self::new(Arc::default());
997        r.inline = inline;
998        r
999    }
1000
1001    /// If the parent widget is doing inline flow layout.
1002    pub fn is_inline(&self) -> bool {
1003        self.inline.is_some()
1004    }
1005
1006    /// Mutable reference to the current widget's inline info.
1007    ///
1008    /// The widget must configure this to be inlined in parent layout. This is only `Some(_)` if inline is enabled.
1009    ///
1010    /// See [`WidgetInlineMeasure`] for more details.
1011    pub fn inline(&mut self) -> Option<&mut WidgetInlineMeasure> {
1012        self.inline.as_mut()
1013    }
1014
1015    /// Sets [`is_inline`] to `false`.
1016    ///
1017    /// Must be called before child delegation, otherwise children that inline may render expecting to fit in
1018    /// the inline flow.
1019    ///
1020    /// Note that this disables inline for the calling widget's next layout too, every property that affects layout and does
1021    /// not support inline layout must propagate measure using this method to correctly configure the widget.
1022    ///
1023    /// Prefer [`measure_block`] as if also clears the layout constraints.
1024    ///
1025    /// [`is_inline`]: Self::is_inline
1026    /// [`measure_block`]: Self::measure_block
1027    pub fn disable_inline(&mut self) {
1028        if !self.inline_locked {
1029            self.inline = None;
1030        }
1031    }
1032
1033    /// Disable inline and measure child with no inline constraints.
1034    pub fn measure_block(&mut self, child: &mut impl UiNode) -> PxSize {
1035        self.disable_inline();
1036        LAYOUT.with_no_inline(|| child.measure(self))
1037    }
1038
1039    /// Measure the child node with inline enabled for the `child` node context.
1040    ///
1041    /// The `first_max` and `mid_clear_min` parameters match the [`InlineConstraintsMeasure`] members, and will be set in
1042    /// the `child` context.
1043    ///
1044    /// Note that this does not enabled inline in the calling widget if inlining was disabled by the parent nodes, it creates
1045    /// a new inlining context.
1046    ///
1047    /// Returns the inline requirements of the child and its desired bounds size, returns `None` requirements if the child
1048    /// disables inline or is not a full widget.
1049    ///
1050    /// [`InlineConstraintsMeasure`]: zng_layout::context::InlineConstraintsMeasure
1051    pub fn measure_inline(&mut self, first_max: Px, mid_clear_min: Px, child: &mut impl UiNode) -> (Option<WidgetInlineMeasure>, PxSize) {
1052        let constraints = InlineConstraints::Measure(InlineConstraintsMeasure { first_max, mid_clear_min });
1053        let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1054        let size = LAYOUT.with_context(metrics, || child.measure(self));
1055        let inline = child
1056            .with_context(WidgetUpdateMode::Ignore, || WIDGET.bounds().measure_inline())
1057            .flatten();
1058        (inline, size)
1059    }
1060
1061    /// Measure a widget.
1062    pub fn with_widget(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1063        let metrics = LAYOUT.metrics();
1064        let bounds = WIDGET.bounds();
1065
1066        let snap = metrics.snapshot();
1067        if !WIDGET.layout_is_pending(&self.layout_widgets) {
1068            let measure_uses = bounds.measure_metrics_used();
1069            if bounds.measure_metrics().map(|m| m.masked_eq(&snap, measure_uses)).unwrap_or(false) {
1070                let mut reused = false;
1071                if let Some(inline) = self.inline() {
1072                    if let Some(prev) = bounds.measure_inline() {
1073                        *inline = prev;
1074                        reused = true;
1075                    }
1076                } else {
1077                    reused = bounds.measure_inline().is_none();
1078                }
1079
1080                if reused {
1081                    // LAYOUT.register_metrics_use(measure_uses); // measure does not propagate uses.
1082                    return bounds.measure_outer_size();
1083                }
1084            }
1085        }
1086
1087        let parent_inline = self.inline.take();
1088        if LAYOUT.inline_constraints().is_some() {
1089            self.inline = Some(Default::default());
1090        }
1091
1092        let (measure_uses, size) = LAYOUT.capture_metrics_use(|| measure(self));
1093
1094        bounds.set_measure_metrics(Some(snap), measure_uses);
1095        bounds.set_measure_outer_size(size);
1096
1097        if let Some(inline) = self.inline.take() {
1098            if inline.is_default() && !size.is_empty() {
1099                // widget did not handle inline
1100                bounds.set_measure_inline(None);
1101            } else {
1102                #[cfg(debug_assertions)]
1103                if !inline.last_wrapped && inline.first != inline.last {
1104                    tracing::error!(
1105                        "widget {:?} invalid inline measure, last {:?} != first {:?} but last did not wrap",
1106                        WIDGET.id(),
1107                        inline.last,
1108                        inline.first
1109                    );
1110                }
1111
1112                bounds.set_measure_inline(Some(inline));
1113            }
1114        } else {
1115            bounds.set_measure_inline(None);
1116        }
1117        self.inline = parent_inline;
1118
1119        size
1120    }
1121
1122    /// Calls `measure` with inline force enabled on the widget.
1123    ///
1124    /// The widget will be inlining even if the parent widget is not inlining, if properties request [`disable_inline`]
1125    /// these requests are ignored.
1126    ///
1127    /// [`disable_inline`]: crate::widget::info::WidgetMeasure::disable_inline
1128    pub fn with_inline_visual(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1129        self.inline_locked = true;
1130        if self.inline.is_none() {
1131            self.inline = Some(Default::default());
1132        }
1133        let metrics = LAYOUT.metrics();
1134        let size = if metrics.inline_constraints().is_none() {
1135            let constraints = InlineConstraints::Measure(InlineConstraintsMeasure {
1136                first_max: metrics.constraints().x.max_or(Px::MAX),
1137                mid_clear_min: Px(0),
1138            });
1139            let metrics = metrics.with_inline_constraints(Some(constraints));
1140            LAYOUT.with_context(metrics, || measure(self))
1141        } else {
1142            measure(self)
1143        };
1144        self.inline_locked = false;
1145
1146        let inline = self.inline.clone().unwrap();
1147        let bounds = WIDGET.bounds();
1148        if inline.is_default() && !size.is_empty() {
1149            // widget did not handle inline
1150            bounds.set_measure_inline(None);
1151        } else {
1152            bounds.set_measure_inline(Some(inline));
1153        }
1154        bounds.set_measure_outer_size(size);
1155
1156        size
1157    }
1158
1159    /// Start a parallel measure.
1160    ///
1161    /// Returns an instance that can be used to acquire multiple mutable [`WidgetMeasure`] during measure.
1162    /// The [`parallel_fold`] method must be called after the parallel processing is done.
1163    ///
1164    /// [`parallel_fold`]: Self::parallel_fold
1165    pub fn parallel_split(&self) -> ParallelBuilder<WidgetMeasure> {
1166        ParallelBuilder(Some(Self {
1167            layout_widgets: self.layout_widgets.clone(),
1168            inline: self.inline.clone(),
1169            inline_locked: self.inline_locked,
1170        }))
1171    }
1172
1173    /// Collect the parallel changes back.
1174    pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetMeasure>) {
1175        let _ = split.take();
1176    }
1177}
1178
1179/// Represents the in-progress layout pass for a widget tree.
1180pub struct WidgetLayout {
1181    layout_widgets: Arc<LayoutUpdates>,
1182    bounds: WidgetBoundsInfo,
1183    nest_group: LayoutNestGroup,
1184    inline: Option<WidgetInlineInfo>,
1185    needs_ref_count: Option<u32>,
1186}
1187impl WidgetLayout {
1188    /// Defines the root widget outer-bounds scope.
1189    ///
1190    /// The default window implementation calls this inside the root widget context.
1191    pub fn with_root_widget(layout_widgets: Arc<LayoutUpdates>, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1192        Self {
1193            layout_widgets,
1194            bounds: WIDGET.bounds(),
1195            nest_group: LayoutNestGroup::Inner,
1196            inline: None,
1197            needs_ref_count: None,
1198        }
1199        .with_widget(layout)
1200    }
1201
1202    /// Start a parallel layout.
1203    ///
1204    /// Returns an instance that can be used to acquire multiple mutable [`WidgetLayout`] during layout.
1205    /// The [`parallel_fold`] method must be called after the parallel processing is done.
1206    ///
1207    /// Must be called outside of the [child] scope.
1208    ///
1209    /// [child]: Self::with_child
1210    /// [`parallel_fold`]: Self::parallel_fold
1211    pub fn parallel_split(&self) -> ParallelBuilder<WidgetLayout> {
1212        if self.nest_group != LayoutNestGroup::Child && WIDGET.parent_id().is_some() {
1213            tracing::error!("called `parallel_split` outside child scope");
1214        }
1215        ParallelBuilder(Some(WidgetLayout {
1216            layout_widgets: self.layout_widgets.clone(),
1217            bounds: self.bounds.clone(),
1218            nest_group: LayoutNestGroup::Child,
1219            inline: None,
1220            needs_ref_count: None,
1221        }))
1222    }
1223
1224    /// Collect the parallel changes back.
1225    pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetLayout>) {
1226        let folded = split.take();
1227        assert_eq!(self.bounds, folded.bounds);
1228
1229        let count = self.needs_ref_count.unwrap_or(0) + folded.needs_ref_count.unwrap_or(0);
1230        self.needs_ref_count = Some(count);
1231    }
1232
1233    /// Defines a widget scope, translations inside `layout` target the widget's inner offset.
1234    ///
1235    /// If the widget layout is not invalidated and none of the used metrics have changed skips calling
1236    /// `layout` and returns the current outer-size, the outer transform is still updated.
1237    ///
1238    /// The default widget constructor calls this, see [`base::node::widget`].
1239    ///
1240    /// [`base::node::widget`]: crate::widget::base::node::widget
1241    pub fn with_widget(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1242        let metrics = LAYOUT.metrics();
1243        let bounds = WIDGET.bounds();
1244
1245        let snap = metrics.snapshot();
1246        if let Some(c) = &mut self.needs_ref_count {
1247            *c += 1;
1248        }
1249
1250        if !WIDGET.take_update(UpdateFlags::LAYOUT) && !self.layout_widgets.delivery_list().enter_widget(WIDGET.id()) {
1251            // layout not invalidated by request
1252            let uses = bounds.metrics_used();
1253            if bounds.metrics().map(|m| m.masked_eq(&snap, uses)).unwrap_or(false) {
1254                // layout not invalidated by used metrics
1255                LAYOUT.register_metrics_use(uses); // propagate to parent
1256                return bounds.outer_size();
1257            }
1258        }
1259
1260        let parent_needs_ref_count = self.needs_ref_count.take();
1261        let parent_inline = self.inline.take();
1262        if LAYOUT.inline_constraints().is_some() && bounds.measure_inline().is_some() {
1263            // inline enabled by parent and widget
1264            self.inline = bounds.take_inline();
1265            if let Some(inline) = self.inline.as_mut() {
1266                inline.clear();
1267            } else {
1268                self.inline = Some(Default::default());
1269            }
1270        }
1271        let parent_bounds = mem::replace(&mut self.bounds, bounds);
1272        self.nest_group = LayoutNestGroup::Inner;
1273        let prev_inner_offset = self.bounds.inner_offset();
1274        let prev_child_offset = self.bounds.child_offset();
1275        let prev_baseline = self.bounds.baseline();
1276        let prev_inner_offset_baseline = self.bounds.inner_offset_baseline();
1277        let prev_can_auto_hide = self.bounds.can_auto_hide();
1278        let prev_transform_style = self.bounds.transform_style();
1279        let prev_perspective = self.bounds.raw_perspective();
1280        let prev_perspective_origin = self.bounds.raw_perspective_origin();
1281        self.bounds.set_inner_offset(PxVector::zero());
1282        self.bounds.set_child_offset(PxVector::zero());
1283        self.bounds.set_baseline(Px(0));
1284        self.bounds.set_inner_offset_baseline(false);
1285        self.bounds.set_can_auto_hide(true);
1286        self.bounds.set_transform_style(TransformStyle::Flat);
1287        self.bounds.set_perspective(f32::INFINITY);
1288        self.bounds.set_perspective_origin(None);
1289
1290        // layout
1291        let (uses, size) = LAYOUT.capture_metrics_use(|| layout(self));
1292
1293        LAYOUT.register_metrics_use(uses);
1294        self.bounds.set_outer_size(size);
1295        self.bounds.set_metrics(Some(snap), uses);
1296        if let Some(inline) = &mut self.inline {
1297            inline.inner_size = self.bounds.inner_size();
1298            inline.invalidate_negative_space();
1299        }
1300        self.bounds.set_inline(self.inline.take());
1301
1302        if prev_can_auto_hide != self.bounds.can_auto_hide() || prev_transform_style != self.bounds.transform_style() {
1303            WIDGET.render();
1304        } else if prev_inner_offset != self.bounds.inner_offset()
1305            || prev_child_offset != self.bounds.child_offset()
1306            || prev_inner_offset_baseline != self.bounds.inner_offset_baseline()
1307            || prev_perspective != self.bounds.raw_perspective()
1308            || prev_perspective_origin != self.bounds.raw_perspective_origin()
1309            || (self.bounds.inner_offset_baseline() && prev_baseline != self.bounds.baseline())
1310        {
1311            WIDGET.render_update();
1312        }
1313
1314        self.needs_ref_count = parent_needs_ref_count;
1315        self.inline = parent_inline;
1316        self.bounds = parent_bounds;
1317        self.nest_group = LayoutNestGroup::Child;
1318
1319        size
1320    }
1321
1322    /// Calls `layout` with inline force enabled on the widget.
1323    ///
1324    /// The widget will use the inline visual even if the parent did not inline it, but it will not
1325    /// inline if it has properties that disable inlining.
1326    pub fn with_inline_visual(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1327        if self.is_inline() {
1328            let size = layout(self);
1329            WIDGET.bounds().set_inline(self.inline.clone());
1330            size
1331        } else {
1332            let bounds = WIDGET.bounds();
1333            if let Some(measure) = bounds.measure_inline() {
1334                let constraints = InlineConstraintsLayout {
1335                    first: PxRect::from_size(measure.first),
1336                    mid_clear: Px(0),
1337                    last: {
1338                        let mut r = PxRect::from_size(measure.last);
1339                        r.origin.y = bounds.measure_outer_size().height - measure.last.height;
1340                        r
1341                    },
1342                    first_segs: Arc::new(vec![]),
1343                    last_segs: Arc::new(vec![]),
1344                };
1345
1346                self.inline = Some(Default::default());
1347
1348                let metrics = LAYOUT
1349                    .metrics()
1350                    .with_inline_constraints(Some(InlineConstraints::Layout(constraints)));
1351                let size = LAYOUT.with_context(metrics, || layout(self));
1352
1353                bounds.set_inline(self.inline.clone());
1354                size
1355            } else {
1356                layout(self)
1357            }
1358        }
1359    }
1360
1361    /// Defines the widget's inner scope, translations inside `layout` target the widget's child offset.
1362    ///
1363    /// This method also updates the border info.
1364    ///
1365    /// The default widget borders constructor calls this, see [`base::node::widget_inner`].
1366    ///
1367    /// [`base::node::widget_inner`]: crate::widget::base::node::widget_inner
1368    pub fn with_inner(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1369        self.nest_group = LayoutNestGroup::Child;
1370        let size = BORDER.with_inner(|| layout(self));
1371        WIDGET.bounds().set_inner_size(size);
1372        self.nest_group = LayoutNestGroup::Inner;
1373        size
1374    }
1375
1376    /// Defines the widget's child scope, translations inside `layout` target the widget's child offset.
1377    ///
1378    /// Returns the child size and if a reference frame is required to offset the child.
1379    ///
1380    /// The default widget child layout constructor implements this, see [`base::node::widget_child`].
1381    ///
1382    /// [`base::node::widget_child`]: crate::widget::base::node::widget_child
1383    /// [`child_offset`]: WidgetBoundsInfo::child_offset
1384    /// [`with_branch_child`]: Self::with_branch_child
1385    pub fn with_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, bool) {
1386        let parent_needs_ref_count = mem::replace(&mut self.needs_ref_count, Some(0));
1387
1388        self.nest_group = LayoutNestGroup::Child;
1389        let child_size = layout(self);
1390        self.nest_group = LayoutNestGroup::Child;
1391
1392        let need_ref_frame = self.needs_ref_count != Some(1);
1393        self.needs_ref_count = parent_needs_ref_count;
1394        (child_size, need_ref_frame)
1395    }
1396
1397    /// Ensure that the parent [`with_child`] will receive a reference frame request.
1398    ///
1399    /// Nodes that branch out children inside the widget's child scope must call this to ensure that the offsets
1400    /// are not given to the only widget child among other nodes.
1401    ///
1402    /// [`with_child`]: Self::with_child
1403    pub fn require_child_ref_frame(&mut self) {
1404        if let Some(c) = &mut self.needs_ref_count {
1405            *c += 2;
1406        }
1407    }
1408
1409    /// Defines a custom scope that does not affect the widget's offsets, only any widget inside `layout`.
1410    ///
1411    /// Nodes that branch out children outside widget's child scope must use this method.
1412    ///
1413    /// Returns the output of `layout` and a translate vector if any translations inside `layout` where not handled
1414    /// by child widgets.
1415    pub fn with_branch_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, PxVector) {
1416        let parent_needs_ref_count = self.needs_ref_count;
1417        let parent_translate = self.bounds.child_offset();
1418        let parent_inner_offset_baseline = self.bounds.inner_offset_baseline();
1419        self.bounds.set_child_offset(PxVector::zero());
1420        let parent_group = self.nest_group;
1421
1422        self.nest_group = LayoutNestGroup::Child;
1423        let child_size = layout(self);
1424
1425        let translate = self.bounds.child_offset();
1426        self.bounds.set_child_offset(parent_translate);
1427        self.bounds.set_inner_offset_baseline(parent_inner_offset_baseline);
1428        self.nest_group = parent_group;
1429        self.needs_ref_count = parent_needs_ref_count;
1430
1431        (child_size, translate)
1432    }
1433
1434    /// Adds the `offset` to the closest *inner* bounds offset.
1435    ///
1436    /// This affects the inner offset if called from a node inside the widget and before the `BORDER` group, or it affects
1437    /// the child offset if called inside the widget and inside the `BORDER` group.
1438    pub fn translate(&mut self, offset: PxVector) {
1439        match self.nest_group {
1440            LayoutNestGroup::Inner => {
1441                let mut o = self.bounds.inner_offset();
1442                o += offset;
1443                self.bounds.set_inner_offset(o);
1444            }
1445            LayoutNestGroup::Child => {
1446                let mut o = self.bounds.child_offset();
1447                o += offset;
1448                self.bounds.set_child_offset(o);
1449            }
1450        }
1451    }
1452
1453    /// Set the baseline offset of the widget. The value is up from the bottom of the inner bounds.
1454    pub fn set_baseline(&mut self, baseline: Px) {
1455        self.bounds.set_baseline(baseline);
1456    }
1457
1458    /// Set if the baseline is added to the inner offset *y* axis.
1459    pub fn translate_baseline(&mut self, enabled: bool) {
1460        self.bounds.set_inner_offset_baseline(enabled);
1461    }
1462
1463    /// Set if the widget preserved 3D perspective form the parent.
1464    pub fn set_transform_style(&mut self, style: TransformStyle) {
1465        self.bounds.set_transform_style(style);
1466    }
1467
1468    /// Set the 3D perspective that defines the children 3D space.
1469    ///
1470    /// This is the distance from the Z-plane to the viewer.
1471    pub fn set_perspective(&mut self, d: f32) {
1472        self.bounds.set_perspective(d)
1473    }
1474
1475    /// Sets the vanishing point of the children 3D space as a point in the inner bounds of this widget.
1476    pub fn set_perspective_origin(&mut self, origin: PxPoint) {
1477        self.bounds.set_perspective_origin(Some(origin))
1478    }
1479
1480    /// Sets if the widget only renders if [`outer_bounds`] intersects with the [`FrameBuilder::auto_hide_rect`].
1481    ///
1482    /// This is `true` by default.
1483    ///
1484    /// [`outer_bounds`]: WidgetBoundsInfo::outer_bounds
1485    /// [`FrameBuilder::auto_hide_rect`]: crate::render::FrameBuilder::auto_hide_rect
1486    pub fn allow_auto_hide(&mut self, enabled: bool) {
1487        self.bounds.set_can_auto_hide(enabled);
1488    }
1489
1490    /// Collapse the layout of `self` and descendants, the size and offsets are set to zero.
1491    ///
1492    /// Nodes that set the visibility to the equivalent of [`Collapsed`] must skip layout and return `PxSize::zero` as
1493    /// the size, ignoring the min-size constraints, and call this method to update all the descendant
1494    /// bounds information to be a zero-sized point.
1495    ///
1496    /// Note that the widget will automatically not be rendered when collapsed.
1497    ///
1498    /// [`Collapsed`]: Visibility::Collapsed
1499    pub fn collapse(&mut self) {
1500        WIDGET.take_update(UpdateFlags::LAYOUT);
1501        let tree = WINDOW.info();
1502        let id = WIDGET.id();
1503        if let Some(w) = tree.get(id) {
1504            for w in w.self_and_descendants() {
1505                let info = w.info();
1506                info.bounds_info.set_outer_size(PxSize::zero());
1507                info.bounds_info.set_inner_size(PxSize::zero());
1508                info.bounds_info.set_baseline(Px(0));
1509                info.bounds_info.set_inner_offset_baseline(false);
1510                info.bounds_info.set_can_auto_hide(true);
1511                info.bounds_info.set_inner_offset(PxVector::zero());
1512                info.bounds_info.set_child_offset(PxVector::zero());
1513                info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1514                info.bounds_info.set_metrics(None, LayoutMask::empty());
1515                info.bounds_info.set_is_collapsed(true);
1516                info.bounds_info.set_rendered(None, &tree);
1517            }
1518        } else {
1519            tracing::error!("collapse did not find `{}` in the info tree", id)
1520        }
1521    }
1522
1523    /// Collapse layout of all descendants, the size and offsets are set to zero.
1524    ///
1525    /// Widgets that control the visibility of their children can use this method and then, in the same layout pass, layout
1526    /// the children that should be visible.
1527    ///
1528    /// Note that the widgets will automatically not be rendered when collapsed.
1529    ///
1530    /// [`Collapsed`]: Visibility::Collapsed
1531    pub fn collapse_descendants(&mut self) {
1532        let tree = WINDOW.info();
1533        let id = WIDGET.id();
1534        if let Some(w) = tree.get(id) {
1535            for w in w.descendants() {
1536                let info = w.info();
1537                info.bounds_info.set_outer_size(PxSize::zero());
1538                info.bounds_info.set_inner_size(PxSize::zero());
1539                info.bounds_info.set_baseline(Px(0));
1540                info.bounds_info.set_inner_offset_baseline(false);
1541                info.bounds_info.set_can_auto_hide(true);
1542                info.bounds_info.set_inner_offset(PxVector::zero());
1543                info.bounds_info.set_child_offset(PxVector::zero());
1544                info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1545                info.bounds_info.set_metrics(None, LayoutMask::empty());
1546                info.bounds_info.set_is_collapsed(true);
1547            }
1548        } else {
1549            tracing::error!("collapse_descendants did not find `{}` in the info tree", id)
1550        }
1551    }
1552
1553    /// Collapse layout of the child and all its descendants, the size and offsets are set to zero.
1554    ///
1555    /// Widgets that control the visibility of their children can use this method and then, in the same layout pass, layout
1556    /// the children that should be visible.
1557    ///
1558    /// Note that the widgets will automatically not be rendered when collapsed.
1559    ///
1560    /// [`Collapsed`]: Visibility::Collapsed
1561    pub fn collapse_child(&mut self, index: usize) {
1562        let tree = WINDOW.info();
1563        let id = WIDGET.id();
1564        if let Some(w) = tree.get(id) {
1565            if let Some(w) = w.children().nth(index) {
1566                for w in w.self_and_descendants() {
1567                    let info = w.info();
1568                    info.bounds_info.set_outer_size(PxSize::zero());
1569                    info.bounds_info.set_inner_size(PxSize::zero());
1570                    info.bounds_info.set_baseline(Px(0));
1571                    info.bounds_info.set_inner_offset_baseline(false);
1572                    info.bounds_info.set_can_auto_hide(true);
1573                    info.bounds_info.set_inner_offset(PxVector::zero());
1574                    info.bounds_info.set_child_offset(PxVector::zero());
1575                    info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1576                    info.bounds_info.set_metrics(None, LayoutMask::empty());
1577                    info.bounds_info.set_is_collapsed(true);
1578                }
1579            } else {
1580                tracing::error!(
1581                    "collapse_child out-of-bounds for `{}` in the children of `{}` in the info tree",
1582                    index,
1583                    id
1584                )
1585            }
1586        } else {
1587            tracing::error!("collapse_child did not find `{}` in the info tree", id)
1588        }
1589    }
1590
1591    /// If the parent widget is doing inline layout and this widget signaled that it can support this
1592    /// during measure.
1593    ///
1594    /// See [`WidgetMeasure::inline`] for more details.
1595    pub fn is_inline(&self) -> bool {
1596        self.inline.is_some()
1597    }
1598
1599    /// Mutable reference to the current widget's inline info.
1600    ///
1601    /// This is `Some(_)` if the parent widget is doing inline layout and this widget signaled that it can be inlined
1602    /// in the previous measure pass. You can use [`WidgetMeasure::disable_inline`] in the measure pass to disable
1603    /// inline in both passes, measure and layout.
1604    ///
1605    /// The rows and negative space are already reset when widget layout started, and the inner size will be updated when
1606    /// the widget layout ends, the inline layout node only needs to push rows.
1607    ///
1608    /// When this is `Some(_)` the [`LayoutMetrics::inline_constraints`] is also `Some(_)`.
1609    ///
1610    /// See [`WidgetInlineInfo`] for more details.
1611    ///
1612    /// [`LayoutMetrics::inline_constraints`]: zng_layout::context::LayoutMetrics::inline_constraints
1613    pub fn inline(&mut self) -> Option<&mut WidgetInlineInfo> {
1614        self.inline.as_mut()
1615    }
1616
1617    /// Create an [`WidgetMeasure`] for an [`UiNode::measure`] call.
1618    ///
1619    /// [`UiNode::measure`]: crate::widget::node::UiNode::measure
1620    pub fn to_measure(&self, inline: Option<WidgetInlineMeasure>) -> WidgetMeasure {
1621        WidgetMeasure {
1622            layout_widgets: self.layout_widgets.clone(),
1623            inline,
1624            inline_locked: false,
1625        }
1626    }
1627
1628    /// Layout the child node in a context without inline constraints.
1629    ///
1630    /// This must be called inside inlining widgets to layout block child nodes, otherwise the inline constraints from
1631    /// the calling widget propagate to the child.
1632    pub fn layout_block(&mut self, child: &mut impl UiNode) -> PxSize {
1633        LAYOUT.with_no_inline(|| child.layout(self))
1634    }
1635
1636    /// Layout the child node with inline enabled in the `child` node context.
1637    ///
1638    /// The `mid_clear`, `last`, `first_segs` and `last_segs` parameters match the [`InlineConstraintsLayout`] members, and will be set in
1639    /// the `child` context.
1640    ///
1641    /// Returns the child final size.
1642    ///
1643    /// [`InlineConstraintsLayout`]: zng_layout::context::InlineConstraintsLayout
1644    pub fn layout_inline(
1645        &mut self,
1646        first: PxRect,
1647        mid_clear: Px,
1648        last: PxRect,
1649        first_segs: Arc<Vec<InlineSegmentPos>>,
1650        last_segs: Arc<Vec<InlineSegmentPos>>,
1651        child: &mut impl UiNode,
1652    ) -> PxSize {
1653        let constraints = InlineConstraints::Layout(InlineConstraintsLayout {
1654            first,
1655            mid_clear,
1656            last,
1657            first_segs,
1658            last_segs,
1659        });
1660        let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1661        LAYOUT.with_context(metrics, || child.layout(self))
1662    }
1663
1664    /// Call `layout` with a different set of `layout_updates`.
1665    ///
1666    /// This is usually managed by the window implementer, nested windows can use this to override the updates.
1667    pub fn with_layout_updates(&mut self, layout_updates: Arc<LayoutUpdates>, layout: impl FnOnce(&mut WidgetLayout) -> PxSize) -> PxSize {
1668        let parent_layout_widgets = mem::replace(&mut self.layout_widgets, layout_updates);
1669        let r = layout(self);
1670        self.layout_widgets = parent_layout_widgets;
1671        r
1672    }
1673}
1674
1675#[derive(Debug, Clone, Copy, PartialEq)]
1676enum LayoutNestGroup {
1677    /// Inside widget, outside `BORDER`.
1678    Inner,
1679    /// Inside `BORDER`.
1680    Child,
1681}
1682
1683/// Represents a builder split from the main builder that can be used in parallel and then folded
1684/// back onto the main builder.
1685///
1686/// # Error
1687///
1688/// Logs an error on drop if it was not moved to the `B::parallel_fold` method.
1689#[must_use = "use in parallel task, then move it to `B::parallel_fold`"]
1690pub struct ParallelBuilder<B>(pub(crate) Option<B>);
1691impl<B> ParallelBuilder<B> {
1692    pub(crate) fn take(&mut self) -> B {
1693        self.0.take().expect("parallel builder finished")
1694    }
1695}
1696impl<B> ops::Deref for ParallelBuilder<B> {
1697    type Target = B;
1698
1699    fn deref(&self) -> &Self::Target {
1700        self.0.as_ref().expect("parallel builder finished")
1701    }
1702}
1703impl<B> ops::DerefMut for ParallelBuilder<B> {
1704    fn deref_mut(&mut self) -> &mut Self::Target {
1705        self.0.as_mut().expect("parallel builder finished")
1706    }
1707}
1708impl<B> Drop for ParallelBuilder<B> {
1709    fn drop(&mut self) {
1710        if self.0.is_some() && !std::thread::panicking() {
1711            tracing::error!("builder dropped without calling `{}::parallel_fold`", std::any::type_name::<B>())
1712        }
1713    }
1714}