zng_app/widget/
node.rs

1//! Widget nodes types, [`UiNode`], [`UiVec`] and others.
2
3use std::{any::Any, ops::ControlFlow};
4
5mod adopt;
6pub use adopt::*;
7
8mod arc;
9pub use arc::*;
10
11mod extend;
12pub use extend::*;
13
14mod match_node;
15pub use match_node::*;
16
17mod when;
18pub use when::*;
19
20mod trace;
21
22mod list;
23pub use list::*;
24use zng_app_proc_macros::widget;
25use zng_layout::{context::LAYOUT, unit::PxSize};
26use zng_var::{BoxAnyVarValue, ContextInitHandle, ResponseVar, response_done_var, response_var};
27
28use crate::{
29    render::{FrameBuilder, FrameUpdate},
30    update::WidgetUpdates,
31    widget::builder::{NestGroup, WidgetBuilding},
32};
33
34use super::{
35    WIDGET, WidgetId, WidgetUpdateMode,
36    info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
37};
38
39macro_rules! debug_warn_list {
40    ($self:ident, $op:tt) => {
41        #[cfg(debug_assertions)]
42        {
43            if $self.is_list() {
44                let op = $op;
45                tracing::warn!("UiNodeImpl is_list without implementing `{op}`");
46            }
47        }
48    };
49}
50
51/// Represents an [`UiNode`] implementation.
52///
53/// You can use the [`match_node`] helper to quickly declare a new node from a closure, most property nodes are implemented
54/// using the match helpers. For more advanced nodes you can manually implement this trait.
55pub trait UiNodeImpl: Any + Send {
56    /// Gets the current count of children nodes.
57    fn children_len(&self) -> usize;
58
59    /// Gets if the node represents a list of other nodes.
60    ///
61    /// If `true` the node provides only minimal layout implementations and expects the caller
62    /// to use [`measure_list`], [`layout_list`] or direct access to child nodes for layout.
63    ///
64    /// If `true` the node must implement all methods that iterate over children, for better performance and if possible, parallelization.
65    /// A warning is logged in debug builds if a list node did not implement one of these methods.
66    ///
67    /// [`measure_list`]: UiNodeImpl::measure_list
68    /// [`layout_list`]: UiNodeImpl::layout_list
69    fn is_list(&self) -> bool {
70        false
71    }
72
73    /// Visit a child node by `index`. If the index is not valid `visitor` is not called.
74    ///
75    /// Nodes with many children should also implement [`for_each_child`] and [`par_each_child`] for better performance.
76    ///
77    /// [`for_each_child`]: UiNodeImpl::for_each_child
78    /// [`par_each_child`]: UiNodeImpl::par_each_child
79    fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode));
80
81    /// Call `visitor` for each child node of `self`, one at a time.
82    ///
83    /// The closure parameters are the child index and the child.
84    fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
85        debug_warn_list!(self, "for_each_child");
86
87        for i in 0..self.children_len() {
88            self.with_child(i, &mut |n| visitor(i, n));
89        }
90    }
91
92    /// Call `visitor` for each child node of `self`, one at a time, with control flow.
93    ///
94    /// The closure parameters are the child index and the child.
95    fn try_for_each_child(
96        &mut self,
97        visitor: &mut dyn FnMut(usize, &mut UiNode) -> ControlFlow<BoxAnyVarValue>,
98    ) -> ControlFlow<BoxAnyVarValue> {
99        debug_warn_list!(self, "try_for_each_child");
100
101        for i in 0..self.children_len() {
102            let mut flow = ControlFlow::Continue(());
103            self.with_child(i, &mut |n| flow = visitor(i, n));
104            flow?;
105        }
106        ControlFlow::Continue(())
107    }
108
109    /// Calls `visitor` for each child node in parallel.
110    ///
111    /// The closure parameters are the child index and the child.
112    fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
113        debug_warn_list!(self, "par_each_child");
114
115        for i in 0..self.children_len() {
116            self.with_child(i, &mut |n| visitor(i, n));
117        }
118    }
119
120    /// Calls `fold` for each child node in parallel, with fold accumulators produced by cloning `identity`, then merges the folded results
121    /// using `reduce` to produce the final value also in parallel.
122    ///
123    /// If the `reduce` closure is [associative], an *append* like operation will produce a result in the same order as the input items.
124    ///
125    /// [associative]: https://en.wikipedia.org/wiki/Associative_property
126    fn par_fold_reduce(
127        &mut self,
128        identity: BoxAnyVarValue,
129        fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
130        reduce: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
131    ) -> BoxAnyVarValue {
132        debug_warn_list!(self, "par_fold_reduce");
133
134        let _ = reduce;
135        let mut accumulator = identity;
136        for i in 0..self.children_len() {
137            self.with_child(i, &mut |n| {
138                accumulator = fold(std::mem::replace(&mut accumulator, BoxAnyVarValue::new(())), i, n);
139            });
140        }
141        accumulator
142    }
143
144    /// Initializes the node in a new UI context.
145    ///
146    /// Common init operations are subscribing to variables and events and initializing data.
147    /// You can use [`WIDGET`] to subscribe events and vars, the subscriptions live until the widget is deinited.
148    ///
149    /// If the node is a custom widget it must request an info, layout and render updates, other nodes
150    /// do not need to request any sort of update on init.
151    ///
152    /// Note that this method can be called again, after a [`deinit`].
153    ///
154    /// [`deinit`]: UiNode::deinit
155    fn init(&mut self) {
156        match self.children_len() {
157            0 => {}
158            1 => self.with_child(0, &mut |c| c.0.init()),
159            _ => {
160                debug_warn_list!(self, "init");
161                self.for_each_child(&mut |_, n| n.0.init())
162            }
163        }
164    }
165
166    /// Deinitializes the node in the current UI context.
167    ///
168    /// Common deinit operations include dropping allocations and handlers.
169    ///
170    /// If the node is a custom widget it must request an info, layout and render updates, other nodes
171    /// do not need to request any sort of update on deinit.
172    ///
173    /// Note that [`init`] can be called again after this.
174    ///
175    /// [`init`]: UiNode::init
176    fn deinit(&mut self) {
177        match self.children_len() {
178            0 => {}
179            1 => self.with_child(0, &mut |c| c.0.deinit()),
180            _ => {
181                debug_warn_list!(self, "deinit");
182                self.for_each_child(&mut |_, n| n.0.deinit())
183            }
184        }
185    }
186
187    /// Builds widget info.
188    ///
189    /// This method is called every time there are structural changes in the UI tree such as a node added or removed, you
190    /// can also request an info rebuild using [`WIDGET.update_info`].
191    ///
192    /// Only nodes in widgets that requested info rebuild and nodes in their ancestors receive this call. Other
193    /// widgets reuse their info in the new info tree. The widget's latest built info is available in [`WIDGET.info`].
194    ///
195    /// Note that info rebuild has higher priority over event, update, layout and render, this means that if you set a variable
196    /// and request info update the next info rebuild will still observe the old variable value, you can work around this issue by
197    /// only requesting info rebuild after the variable updates.
198    ///
199    /// [`WIDGET.info`]: crate::widget::WIDGET::info
200    /// [`WIDGET.update_info`]: crate::widget::WIDGET::update_info
201    fn info(&mut self, info: &mut WidgetInfoBuilder) {
202        match self.children_len() {
203            0 => {}
204            1 => self.with_child(0, &mut |c| c.0.info(info)),
205            _ => {
206                debug_warn_list!(self, "info");
207                self.for_each_child(&mut |_, n| n.0.info(info))
208            }
209        }
210    }
211
212    /// Receives event and variable updates.
213    ///
214    /// Calls to this method aggregate all updates that happen in the last pass, multiple events and variables can be new at the same time.
215    /// You can listen to variable updates by subscribing to then on init and using the [`Var::get_new`] method in this method to
216    /// receive the new values.
217    ///
218    /// A custom update can be requested using the context [`WIDGET.update`]. Common update operations include reacting to variable
219    /// changes that generate an intermediary value for layout or render, the update implementation uses [`WIDGET`] to request layout
220    /// and render after updating the data. Note that for simple variables that are used directly on layout or render you can subscribe
221    /// to that operation directly, skipping update.
222    ///
223    /// [`Var::get_new`]: zng_var::Var::get_new
224    /// [`WIDGET.update`]: crate::widget::WIDGET::update
225    fn update(&mut self, updates: &WidgetUpdates) {
226        match self.children_len() {
227            0 => {}
228            1 => self.with_child(0, &mut |c| c.0.update(updates)),
229            _ => {
230                debug_warn_list!(self, "update");
231                self.for_each_child(&mut |_, n| n.0.update(updates))
232            }
233        }
234    }
235
236    /// Does [`update`] and if the node is a list notifies list changes to the `observer`.
237    ///
238    /// [`update`]: UiNodeImpl::update
239    fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
240        if self.is_list() {
241            debug_warn_list!(self, "update_list");
242            let len = self.children_len();
243            self.update(updates);
244            if len != self.children_len() {
245                observer.reset();
246            }
247        } else {
248            self.update(updates);
249        }
250    }
251
252    /// Computes the widget size given the contextual layout metrics without actually updating the widget layout.
253    ///
254    /// Implementers must return the same size [`layout`] returns for the given [`LayoutMetrics`], without
255    /// affecting the actual widget render. Panel widgets that implement some complex layouts need to get an
256    /// what the widget would be given some constraints, this value is used to inform the actual [`layout`] call.
257    ///
258    /// Nodes that implement [`layout`] must also implement this method, the [`LAYOUT`] context can be used to retrieve the metrics,
259    /// the [`WidgetMeasure`] parameter can be used to communicate with the parent layout, such as disabling inline layout, the
260    /// returned [`PxSize`] is the desired size given the parent constraints.
261    ///
262    /// [`layout`]: Self::layout
263    /// [`LayoutMetrics`]: zng_layout::context::LayoutMetrics
264    /// [`LAYOUT`]: zng_layout::context::LAYOUT
265    /// [`PxSize`]: zng_layout::unit::PxSize
266    #[must_use]
267    fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
268        match self.children_len() {
269            0 => LAYOUT.constraints().fill_size(),
270            1 => {
271                let mut r = PxSize::zero();
272                self.with_child(0, &mut |c| r = c.measure(wm));
273                r
274            }
275            _ => {
276                debug_warn_list!(self, "measure");
277                let mut accumulator = PxSize::zero();
278                self.for_each_child(&mut |_, n| accumulator = accumulator.max(n.0.measure(wm)));
279                accumulator
280            }
281        }
282    }
283
284    /// If the node [`is_list`] measure each child and combine the size using `fold_size`.
285    ///
286    /// If the node is not a list, simply measures it.
287    ///
288    /// [`is_list`]: UiNodeImpl::is_list
289    #[must_use]
290    fn measure_list(
291        &mut self,
292        wm: &mut WidgetMeasure,
293        measure: &(dyn Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync),
294        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
295    ) -> PxSize {
296        if self.is_list() {
297            match self.children_len() {
298                0 => PxSize::zero(),
299                1 => {
300                    let mut r = PxSize::zero();
301                    self.with_child(0, &mut |c| r = measure(0, c, wm));
302                    r
303                }
304                _ => {
305                    debug_warn_list!(self, "measure_list");
306
307                    let mut accumulator = PxSize::zero();
308                    self.for_each_child(&mut |i, n| {
309                        let c_s = measure(i, n, wm);
310                        accumulator = fold_size(accumulator, c_s)
311                    });
312                    accumulator
313                }
314            }
315        } else {
316            self.measure(wm)
317        }
318    }
319
320    /// Computes the widget layout given the contextual layout metrics.
321    ///
322    /// Implementers must also implement [`measure`]. This method is called by the parent layout once the final constraints
323    /// for the frame are defined, the [`LAYOUT`] context can be used to retrieve the constraints, the [`WidgetLayout`] parameter
324    /// can be used to communicate layout metadata such as inline segments to the parent layout, the returned [`PxSize`] is the
325    /// final size given the constraints.
326    ///
327    /// Only widgets and ancestors that requested layout or use metrics that changed since last layout receive this call. Other
328    /// widgets reuse the last layout result.
329    ///
330    /// Nodes that render can also implement this operation just to observe the latest widget size, if changes are detected
331    /// the [`WIDGET.render`] method can be used to request render.
332    ///
333    /// [`measure`]: Self::measure
334    /// [`LayoutMetrics`]: zng_layout::context::LayoutMetrics
335    /// [`constraints`]: zng_layout::context::LayoutMetrics::constraints
336    /// [`WIDGET.render`]: crate::widget::WIDGET::render
337    /// [`LAYOUT`]: zng_layout::context::LAYOUT
338    /// [`PxSize`]: zng_layout::unit::PxSize
339    #[must_use]
340    fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
341        match self.children_len() {
342            0 => LAYOUT.constraints().fill_size(),
343            1 => {
344                let mut r = PxSize::zero();
345                self.with_child(0, &mut |c| r = c.layout(wl));
346                r
347            }
348            _ => {
349                debug_warn_list!(self, "layout");
350
351                let mut accumulator = PxSize::zero();
352                self.for_each_child(&mut |_, n| accumulator = accumulator.max(n.0.layout(wl)));
353                accumulator
354            }
355        }
356    }
357
358    /// If the node [`is_list`] layout each child and combine the size using `fold_size`.
359    ///
360    /// If the node is not a list, simply layout it.
361    ///
362    /// [`is_list`]: UiNodeImpl::is_list
363    #[must_use]
364    fn layout_list(
365        &mut self,
366        wl: &mut WidgetLayout,
367        layout: &(dyn Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync),
368        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
369    ) -> PxSize {
370        if self.is_list() {
371            match self.children_len() {
372                0 => PxSize::zero(),
373                1 => {
374                    let mut r = PxSize::zero();
375                    self.with_child(0, &mut |c| r = layout(0, c, wl));
376                    r
377                }
378                _ => {
379                    debug_warn_list!(self, "layout_list");
380
381                    let mut accumulator = PxSize::zero();
382                    self.for_each_child(&mut |i, n| {
383                        let c_s = layout(i, n, wl);
384                        accumulator = fold_size(accumulator, c_s)
385                    });
386                    accumulator
387                }
388            }
389        } else {
390            self.layout(wl)
391        }
392    }
393
394    /// Generates render instructions and updates transforms and hit-test areas.
395    ///
396    /// This method does not generate pixels immediately, it generates *display items* that are visual building block instructions
397    /// for the renderer that will run after the window *display list* is built.
398    ///
399    /// Only widgets and ancestors that requested render receive this call, other widgets reuse the display items and transforms
400    /// from the last frame.
401    fn render(&mut self, frame: &mut FrameBuilder) {
402        match self.children_len() {
403            0 => {}
404            1 => self.with_child(0, &mut |c| c.render(frame)),
405            _ => {
406                debug_warn_list!(self, "render");
407
408                self.for_each_child(&mut |_, n| n.0.render(frame));
409            }
410        }
411    }
412
413    /// If the node [`is_list`] render each child.
414    ///
415    /// If the node is not a list, simply renders it.
416    ///
417    /// [`is_list`]: UiNodeImpl::is_list
418    fn render_list(&mut self, frame: &mut FrameBuilder, render: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
419        if self.is_list() {
420            match self.children_len() {
421                0 => {}
422                1 => self.with_child(0, &mut |n| render(0, n, frame)),
423                _ => {
424                    debug_warn_list!(self, "render_list");
425
426                    self.for_each_child(&mut |i, n| render(i, n, frame));
427                }
428            }
429        } else {
430            self.render(frame);
431        }
432    }
433
434    /// Updates values in the last generated frame.
435    ///
436    /// Some display item values and transforms can be updated directly, without needing to rebuild the display list. All [`FrameBuilder`]
437    /// methods that accept a [`FrameValue<T>`] input can be bound to an ID that can be used to update that value.
438    ///
439    /// Only widgets and ancestors that requested render update receive this call. Note that if any other widget in the same window
440    /// requests render all pending render update requests are upgraded to render requests.
441    ///
442    /// [`FrameValue<T>`]: crate::render::FrameValue
443    fn render_update(&mut self, update: &mut FrameUpdate) {
444        match self.children_len() {
445            0 => {}
446            1 => self.with_child(0, &mut |c| c.render_update(update)),
447            _ => {
448                debug_warn_list!(self, "render_update");
449
450                self.for_each_child(&mut |_, n| n.0.render_update(update));
451            }
452        }
453    }
454
455    /// If the node [`is_list`] render_update each child.
456    ///
457    /// If the node is not a list, simply render_update it.
458    ///
459    /// [`is_list`]: UiNodeImpl::is_list
460    fn render_update_list(&mut self, update: &mut FrameUpdate, render_update: &(dyn Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync)) {
461        if self.is_list() {
462            match self.children_len() {
463                0 => {}
464                1 => self.with_child(0, &mut |n| render_update(0, n, update)),
465                _ => {
466                    debug_warn_list!(self, "render_update_list");
467
468                    self.for_each_child(&mut |i, n| render_update(i, n, update));
469                }
470            }
471        } else {
472            self.render_update(update);
473        }
474    }
475
476    /// Gets the node implementation as a [`WidgetUiNodeImpl`], if the node defines a widget instance scope.
477    fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
478        None
479    }
480}
481impl dyn UiNodeImpl {
482    /// Gets if this node is a good candidate for parallelization when visiting children.
483    ///
484    /// List implementers should check this and [`PARALLEL_VAR`] to enable parallelization of node methods.
485    ///
486    /// [`PARALLEL_VAR`]: crate::widget::base::PARALLEL_VAR
487    pub fn parallelize_hint(&mut self) -> bool {
488        self.children_len() > 1 && self.non_parallel_count() >= MIN_PARALLEL
489    }
490    fn non_parallel_count(&mut self) -> usize {
491        let mut count = 0;
492        let _ = self.try_for_each_child(&mut |_, child| {
493            let cc = child.0.non_parallel_count();
494            if cc < MIN_PARALLEL {
495                count += 1 + cc;
496            }
497            if count >= MIN_PARALLEL {
498                ControlFlow::Break(BoxAnyVarValue::new(()))
499            } else {
500                ControlFlow::Continue(())
501            }
502        });
503        count
504    }
505}
506const MIN_PARALLEL: usize = 24;
507
508/// Represents an [`UiNodeImpl`] that defines a widget instance scope.
509///
510/// Widget defining nodes implement this trait and [`UiNodeImpl::as_widget`].
511pub trait WidgetUiNodeImpl: UiNodeImpl {
512    /// Calls `visitor` with the [`WIDGET`] context of the widget instance defined by the node.
513    ///
514    /// If `update_mode` is [`WidgetUpdateMode::Bubble`] the update flags requested for the widget in `visitor` will be copied to the
515    /// caller widget context, otherwise they are ignored.
516    fn with_context(&mut self, update_mode: WidgetUpdateMode, visitor: &mut dyn FnMut());
517}
518
519/// Represents a value that can become a [`UiNode`] instance.
520#[diagnostic::on_unimplemented(note = "`IntoUiNode` is implemented for all `U: UiNodeImpl`")]
521pub trait IntoUiNode {
522    /// Instantiate the UI node.
523    fn into_node(self) -> UiNode;
524}
525
526impl<U: UiNodeImpl> IntoUiNode for U {
527    #[inline(always)]
528    fn into_node(self) -> UiNode {
529        UiNode::new(self)
530    }
531}
532impl IntoUiNode for UiNode {
533    #[inline(always)]
534    fn into_node(self) -> UiNode {
535        self
536    }
537}
538impl<U: IntoUiNode> IntoUiNode for Option<U> {
539    /// Unwrap or nil.
540    fn into_node(self) -> UiNode {
541        self.map(IntoUiNode::into_node).unwrap_or_else(UiNode::nil)
542    }
543}
544
545impl<A, B> IntoUiNode for std::iter::Chain<A, B>
546where
547    A: Iterator<Item = UiNode>,
548    B: Iterator<Item = A::Item>,
549{
550    fn into_node(self) -> UiNode {
551        let vec: Vec<UiNode> = self.collect();
552        vec.into_node()
553    }
554}
555impl IntoUiNode for std::iter::Empty<UiNode> {
556    fn into_node(self) -> UiNode {
557        ui_vec![].into_node()
558    }
559}
560impl<I, P> IntoUiNode for std::iter::Filter<I, P>
561where
562    I: Iterator<Item = UiNode>,
563    P: FnMut(&<I as Iterator>::Item) -> bool,
564{
565    fn into_node(self) -> UiNode {
566        let vec: Vec<UiNode> = self.collect();
567        vec.into_node()
568    }
569}
570impl<I, F> IntoUiNode for std::iter::FilterMap<I, F>
571where
572    I: Iterator,
573    F: FnMut(<I as Iterator>::Item) -> Option<UiNode>,
574{
575    fn into_node(self) -> UiNode {
576        let vec: Vec<UiNode> = self.collect();
577        vec.into_node()
578    }
579}
580impl<I, U, F> IntoUiNode for std::iter::FlatMap<I, U, F>
581where
582    I: Iterator,
583    U: IntoIterator<Item = UiNode>,
584    F: FnMut(I::Item) -> U,
585{
586    fn into_node(self) -> UiNode {
587        let vec: Vec<UiNode> = self.collect();
588        vec.into_node()
589    }
590}
591impl<I, U> IntoUiNode for std::iter::Flatten<I>
592where
593    I: Iterator,
594    <I as Iterator>::Item: IntoIterator<IntoIter = U, Item = <U as Iterator>::Item>,
595    U: Iterator<Item = UiNode>,
596{
597    fn into_node(self) -> UiNode {
598        let vec: Vec<UiNode> = self.collect();
599        vec.into_node()
600    }
601}
602impl<F> IntoUiNode for std::iter::FromFn<F>
603where
604    F: FnMut() -> Option<UiNode>,
605{
606    fn into_node(self) -> UiNode {
607        let vec: Vec<UiNode> = self.collect();
608        vec.into_node()
609    }
610}
611impl<I, F> IntoUiNode for std::iter::Inspect<I, F>
612where
613    I: Iterator<Item = UiNode>,
614    F: FnMut(&<I as Iterator>::Item),
615{
616    fn into_node(self) -> UiNode {
617        let vec: Vec<UiNode> = self.collect();
618        vec.into_node()
619    }
620}
621impl<I, F> IntoUiNode for std::iter::Map<I, F>
622where
623    I: Iterator,
624    F: FnMut(I::Item) -> UiNode,
625{
626    fn into_node(self) -> UiNode {
627        let vec: Vec<UiNode> = self.collect();
628        vec.into_node()
629    }
630}
631impl<I, P> IntoUiNode for std::iter::MapWhile<I, P>
632where
633    I: Iterator,
634    P: FnMut(<I as Iterator>::Item) -> Option<UiNode>,
635{
636    fn into_node(self) -> UiNode {
637        let vec: Vec<UiNode> = self.collect();
638        vec.into_node()
639    }
640}
641impl<I> IntoUiNode for std::iter::Peekable<I>
642where
643    I: Iterator<Item = UiNode>,
644{
645    fn into_node(self) -> UiNode {
646        let vec: Vec<UiNode> = self.collect();
647        vec.into_node()
648    }
649}
650impl<I> IntoUiNode for std::iter::Rev<I>
651where
652    I: DoubleEndedIterator<Item = UiNode>,
653{
654    fn into_node(self) -> UiNode {
655        let vec: Vec<UiNode> = self.collect();
656        vec.into_node()
657    }
658}
659impl<I, St, F> IntoUiNode for std::iter::Scan<I, St, F>
660where
661    I: Iterator,
662    F: FnMut(&mut St, <I as Iterator>::Item) -> Option<UiNode>,
663{
664    fn into_node(self) -> UiNode {
665        let vec: Vec<UiNode> = self.collect();
666        vec.into_node()
667    }
668}
669impl<I> IntoUiNode for std::iter::Skip<I>
670where
671    I: Iterator<Item = UiNode>,
672{
673    fn into_node(self) -> UiNode {
674        let vec: Vec<UiNode> = self.collect();
675        vec.into_node()
676    }
677}
678impl<I, P> IntoUiNode for std::iter::SkipWhile<I, P>
679where
680    I: Iterator<Item = UiNode>,
681    P: FnMut(&<I as Iterator>::Item) -> bool,
682{
683    fn into_node(self) -> UiNode {
684        let vec: Vec<UiNode> = self.collect();
685        vec.into_node()
686    }
687}
688impl<I> IntoUiNode for std::iter::StepBy<I>
689where
690    I: Iterator<Item = UiNode>,
691{
692    fn into_node(self) -> UiNode {
693        let vec: Vec<UiNode> = self.collect();
694        vec.into_node()
695    }
696}
697impl<F> IntoUiNode for std::iter::Successors<UiNode, F>
698where
699    F: FnMut(&UiNode) -> Option<UiNode>,
700{
701    fn into_node(self) -> UiNode {
702        let vec: Vec<UiNode> = self.collect();
703        vec.into_node()
704    }
705}
706impl<I> IntoUiNode for std::iter::Take<I>
707where
708    I: Iterator<Item = UiNode>,
709{
710    fn into_node(self) -> UiNode {
711        let vec: Vec<UiNode> = self.collect();
712        vec.into_node()
713    }
714}
715impl<I, P> IntoUiNode for std::iter::TakeWhile<I, P>
716where
717    I: Iterator<Item = UiNode>,
718    P: FnMut(&<I as Iterator>::Item) -> bool,
719{
720    fn into_node(self) -> UiNode {
721        let vec: Vec<UiNode> = self.collect();
722        vec.into_node()
723    }
724}
725
726/// Represents an UI tree node instance.
727///
728/// You can use the [`match_node`] helper to quickly declare a new node from a closure, most property nodes are implemented
729/// using the match helpers. For more advanced nodes can implement the [`UiNodeImpl`] trait. Other types can be converted to nodes
730/// if they implement [`IntoUiNode`].
731///
732/// [`match_node`]:fn@match_node
733pub struct UiNode(Box<dyn UiNodeImpl>);
734
735/// Constructors.
736impl UiNode {
737    /// New UI node instance from implementation.
738    ///
739    /// Note that [`IntoUiNode`] is implemented for all `U: UiNodeImpl` so you don't usually need to call this.
740    pub fn new(implementation: impl UiNodeImpl) -> Self {
741        Self(Box::new(implementation))
742    }
743
744    /// New UI node that does nothing and collapses layout.
745    pub fn nil() -> Self {
746        Self::new(NilUiNode)
747    }
748}
749
750/// UI operations.
751impl UiNode {
752    /// Calls the [`UiNodeOp`].
753    #[inline(always)]
754    pub fn op(&mut self, op: UiNodeOp) {
755        match op {
756            UiNodeOp::Init => self.init(),
757            UiNodeOp::Deinit => self.deinit(),
758            UiNodeOp::Info { info } => self.info(info),
759            UiNodeOp::Update { updates } => self.update(updates),
760            UiNodeOp::Measure { wm, desired_size } => *desired_size = self.measure(wm),
761            UiNodeOp::Layout { wl, final_size } => *final_size = self.layout(wl),
762            UiNodeOp::Render { frame } => self.render(frame),
763            UiNodeOp::RenderUpdate { update } => self.render_update(update),
764        }
765    }
766
767    /// Initialize the node in a new UI context.
768    ///
769    /// See [`UiNodeImpl::init`] for more details.
770    #[inline(always)]
771    pub fn init(&mut self) {
772        self.0.init();
773    }
774
775    /// Deinitialize the node in the current UI context.
776    ///
777    /// This must be called before dropping the node.
778    ///
779    /// After calling this you can move the node to a new context and call [`init`] again.
780    ///
781    /// See [`UiNodeImpl::deinit`] for more details.
782    ///
783    /// [`init`]: Self::init
784    #[inline(always)]
785    pub fn deinit(&mut self) {
786        self.0.deinit();
787    }
788
789    /// Continue building widget info metadata.
790    ///
791    /// See [`UiNodeImpl::info`] for more details.
792    #[inline(always)]
793    pub fn info(&mut self, info: &mut WidgetInfoBuilder) {
794        self.0.info(info);
795    }
796
797    /// Notify updates.
798    ///
799    /// See [`UiNodeImpl::update`] for more details.
800    #[inline(always)]
801    pub fn update(&mut self, updates: &WidgetUpdates) {
802        self.0.update(updates);
803    }
804
805    /// Notify updates and observe list changes if the widget is a list.
806    ///
807    /// See [`UiNodeImpl::update_list`] for more details.
808    #[inline(always)]
809    pub fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut impl UiNodeListObserver) {
810        self.0.update_list(updates, observer);
811    }
812
813    /// Estimate node layout without actually updating the node render state.
814    ///
815    /// See [`UiNodeImpl::measure`] for more details.
816    #[inline(always)]
817    #[must_use]
818    pub fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
819        self.0.measure(wm)
820    }
821
822    /// If the node [`is_list`] measure each child and combine the size using `fold_size`.
823    ///
824    /// If the node is not a list, simply measures it.
825    ///
826    /// See [`UiNodeImpl::measure_list`] for more details.
827    ///
828    /// [`is_list`]: UiNode::is_list
829    #[inline(always)]
830    #[must_use]
831    pub fn measure_list(
832        &mut self,
833        wm: &mut WidgetMeasure,
834        measure: impl Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync,
835        fold_size: impl Fn(PxSize, PxSize) -> PxSize + Sync,
836    ) -> PxSize {
837        self.0.measure_list(wm, &measure, &fold_size)
838    }
839
840    /// Update node layout.
841    ///
842    /// See [`UiNodeImpl::layout`] for more details.
843    #[inline(always)]
844    #[must_use]
845    pub fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
846        self.0.layout(wl)
847    }
848
849    /// If the node [`is_list`] layout each child and combine the size using `fold_size`.
850    ///
851    /// If the node is not a list, simply layout it.
852    ///
853    /// See [`UiNodeImpl::layout_list`] for more details.
854    ///
855    /// [`is_list`]: UiNode::is_list
856    #[inline(always)]
857    #[must_use]
858    pub fn layout_list(
859        &mut self,
860        wl: &mut WidgetLayout,
861        layout: impl Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync,
862        fold_size: impl Fn(PxSize, PxSize) -> PxSize + Sync,
863    ) -> PxSize {
864        self.0.layout_list(wl, &layout, &fold_size)
865    }
866
867    /// Collect render instructions for a new frame.
868    ///
869    /// See [`UiNodeImpl::render`] for more details.
870    #[inline(always)]
871    pub fn render(&mut self, frame: &mut FrameBuilder) {
872        self.0.render(frame)
873    }
874
875    /// If the node [`is_list`] render each child.
876    ///
877    /// If the node is not a list, simply renders it.
878    ///
879    /// See [`UiNodeImpl::render_list`] for more details.
880    ///
881    /// [`is_list`]: UiNode::is_list
882    #[inline(always)]
883    pub fn render_list(&mut self, frame: &mut FrameBuilder, render: impl Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync) {
884        self.0.render_list(frame, &render);
885    }
886
887    /// Collect render patches to apply to the previous frame.
888    ///
889    /// See [`UiNodeImpl::render_update`] for more details.
890    #[inline(always)]
891    pub fn render_update(&mut self, update: &mut FrameUpdate) {
892        self.0.render_update(update);
893    }
894
895    /// If the node [`is_list`] render_update each child.
896    ///
897    /// If the node is not a list, simply render_update it.
898    ///
899    /// See [`UiNodeImpl::render_update_list`] for more details.
900    ///
901    /// [`is_list`]: UiNode::is_list
902    #[inline(always)]
903    pub fn render_update_list(&mut self, update: &mut FrameUpdate, render_update: impl Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync) {
904        self.0.render_update_list(update, &render_update);
905    }
906}
907
908/// Children.
909impl UiNode {
910    /// Number of direct descendants of this node.
911    pub fn children_len(&self) -> usize {
912        self.0.children_len()
913    }
914
915    /// Call `visitor` with a exclusive reference to the child node identified by `index`.
916    ///
917    /// If the `index` is out of bounds the closure is not called and returns `None`.
918    pub fn try_with_child<R>(&mut self, index: usize, visitor: impl FnOnce(&mut UiNode) -> R) -> Option<R> {
919        let mut once = Some(visitor);
920        let mut r = None;
921        self.0.with_child(index, &mut |child| r = Some(once.take().unwrap()(child)));
922        r
923    }
924
925    /// Call `visitor` with a exclusive reference to the child node identified by `index`.
926    ///
927    /// Panics if the `index` is out of bounds.
928    pub fn with_child<R>(&mut self, index: usize, visitor: impl FnOnce(&mut UiNode) -> R) -> R {
929        self.try_with_child(index, visitor).expect("index out of bounds")
930    }
931
932    /// Call `visitor` for each child node of `self`, one at a time.
933    ///
934    /// The closure parameters are the child index and the child.
935    pub fn for_each_child(&mut self, mut visitor: impl FnMut(usize, &mut UiNode)) {
936        self.0.for_each_child(&mut visitor);
937    }
938
939    /// Call `visitor` for each child node of `self`, one at a time, with control flow.
940    ///
941    /// The closure parameters are the child index and the child.
942    pub fn try_for_each_child<B>(&mut self, mut visitor: impl FnMut(usize, &mut UiNode) -> ControlFlow<B>) -> ControlFlow<B>
943    where
944        B: zng_var::VarValue,
945    {
946        self.0
947            .try_for_each_child(&mut move |i, n| visitor(i, n).map_break(BoxAnyVarValue::new))
948            .map_break(|b| b.downcast::<B>().unwrap())
949    }
950
951    /// Calls `visitor` for each child node in parallel.
952    ///
953    /// The closure parameters are the child index and the child.
954    pub fn par_each_child(&mut self, visitor: impl Fn(usize, &mut UiNode) + Sync) {
955        self.0.par_each_child(&visitor);
956    }
957
958    /// Calls `fold` for each child node in parallel, with fold accumulators produced by cloning `identity`, then merges the folded results
959    /// using `reduce` to produce the final value also in parallel.
960    ///
961    /// If the `reduce` closure is [associative], an *append* like operation will produce a result in the same order as the input items.
962    ///
963    /// [associative]: https://en.wikipedia.org/wiki/Associative_property
964    pub fn par_fold_reduce<T: zng_var::VarValue>(
965        &mut self,
966        identity: T,
967        fold: impl Fn(T, usize, &mut UiNode) -> T + Sync,
968        reduce: impl Fn(T, T) -> T + Sync,
969    ) -> T {
970        use zng_var::BoxAnyVarValue as B;
971        self.0
972            .par_fold_reduce(
973                B::new(identity),
974                &|accumulator, index, node| {
975                    let r = fold(accumulator.downcast::<T>().unwrap(), index, node);
976                    B::new(r)
977                },
978                &|a, b| {
979                    let r = reduce(a.downcast::<T>().unwrap(), b.downcast::<T>().unwrap());
980                    B::new(r)
981                },
982            )
983            .downcast::<T>()
984            .unwrap()
985    }
986}
987
988/// Node type.
989impl UiNode {
990    /// Returns some reference to implementation of type `U`, if the node instance is of that implementation.
991    #[inline(always)]
992    pub fn downcast_ref<U: UiNodeImpl>(&self) -> Option<&U> {
993        let u: &dyn Any = &*self.0;
994        u.downcast_ref::<U>()
995    }
996
997    /// Returns some mutable reference to implementation of type `U`, if the node instance is of that implementation.
998    #[inline(always)]
999    pub fn downcast_mut<U: UiNodeImpl>(&mut self) -> Option<&mut U> {
1000        let u: &mut dyn Any = &mut *self.0;
1001        u.downcast_mut::<U>()
1002    }
1003
1004    /// Gets if the node is an instance of implementation `U`.
1005    #[inline(always)]
1006    pub fn is<U: UiNodeImpl>(&self) -> bool {
1007        self.downcast_ref::<U>().is_some()
1008    }
1009
1010    /// Exclusive borrow the node implementation directly.
1011    #[inline(always)]
1012    pub fn as_dyn(&mut self) -> &mut dyn UiNodeImpl {
1013        &mut *self.0
1014    }
1015
1016    /// Gets if the node represents a list of other nodes.
1017    ///
1018    /// If `true` the node provides only minimal layout implementations and expects the caller
1019    /// to use [`measure_list`], [`layout_list`] or direct access to the child nodes for layout.
1020    ///
1021    /// [`measure_list`]: Self::measure_list
1022    /// [`layout_list`]: Self::layout_list
1023    #[inline(always)]
1024    pub fn is_list(&self) -> bool {
1025        self.0.is_list()
1026    }
1027
1028    /// Returns a node that [`is_list`].
1029    ///
1030    /// If `self` is a list returns it unchanged.
1031    ///
1032    /// If `self` is nil returns an empty list node.
1033    ///
1034    /// Otherwise returns a new list node with `self` as the single entry.
1035    ///
1036    /// [`is_list`]: Self::is_list
1037    pub fn into_list(self) -> UiNode {
1038        if self.is_list() {
1039            self
1040        } else if self.is_nil() {
1041            ui_vec![].into_node()
1042        } else {
1043            ui_vec![self].into_node()
1044        }
1045    }
1046
1047    /// Gets if is [`nil`].
1048    ///
1049    /// [`nil`]: Self::nil
1050    #[inline(always)]
1051    pub fn is_nil(&self) -> bool {
1052        self.is::<NilUiNode>()
1053    }
1054
1055    /// Access widget node methods, if the node defines a widget context.
1056    #[inline(always)]
1057    pub fn as_widget(&mut self) -> Option<WidgetUiNode<'_>> {
1058        self.0.as_widget().map(WidgetUiNode)
1059    }
1060
1061    /// Returns a node that defines a widget context.
1062    ///
1063    /// If this node already defines a widget just returns it, if not wraps it in a minimal widget implementation.
1064    ///
1065    /// See also [`init_widget`] for a node that awaits until `self` is inited to verify if a new widget really needs to be declared.
1066    ///
1067    /// [`init_widget`]: Self::init_widget
1068    pub fn into_widget(mut self) -> UiNode {
1069        if self.0.as_widget().is_some() {
1070            self
1071        } else {
1072            into_widget!(child = self)
1073        }
1074    }
1075
1076    /// Returns a node that defines a widget context or will begin defining it after [`init`].
1077    ///
1078    /// Also returns a response var that contains or will contain the widget instance ID.
1079    ///
1080    /// If `self` is already an widget node simply returns it and the ID, otherwise returns a node that wraps `self`
1081    /// and checks again if `self` is a widget after init, if `self` is still not a widget after init the wrapper node starts
1082    /// defining a minimal widget context.
1083    ///
1084    /// Some nodes like [`ArcNode::take_on_init`] can only become widgets on init, this helper is an alternative to [`into_widget`]
1085    /// that avoids declaring a second wrapper widget in those cases. Note that because the wrapper node needs to define a widget context
1086    /// after the [`init`] call the wrapped `self` node will need to be reinited inside the new widget.
1087    ///
1088    /// [`init`]: Self::init
1089    /// [`into_widget`]: Self::into_widget
1090    pub fn init_widget(mut self) -> (UiNode, ResponseVar<WidgetId>) {
1091        if let Some(mut wgt) = self.as_widget() {
1092            let id = response_done_var(wgt.id());
1093            (self, id)
1094        } else {
1095            let (r, id) = response_var::<WidgetId>();
1096            let mut first_init = Some(r);
1097            let wgt = match_widget(self, move |c, op| {
1098                if let UiNodeOp::Init = op {
1099                    c.init();
1100
1101                    if let Some(r) = first_init.take() {
1102                        if let Some(mut wgt) = c.node().as_widget() {
1103                            r.respond(wgt.id());
1104                        } else {
1105                            // reinit inside a new widget
1106                            c.deinit();
1107                            let not_wgt = std::mem::replace(c.node(), UiNode::nil());
1108                            *c.node() = into_widget!(child = not_wgt);
1109                            c.init();
1110
1111                            r.respond(c.node().as_widget().unwrap().id());
1112                        }
1113                    }
1114                }
1115            });
1116            (wgt, id)
1117        }
1118    }
1119
1120    /// Wraps this in a node that, before delegating each method, calls a closure with
1121    /// the [`UiNodeMethod`], the closure can return a *span* that is dropped after the method delegation.
1122    ///
1123    /// The tracing node delegates all methods to self, but only traces the [`UiNodeMethod`] methods. If
1124    /// this node is an widget the `enter_mtd` closure will be called (and span dropped) in the context of the widget.
1125    ///
1126    /// You can use the [`tracing`](https://docs.rs/tracing) crate to create the span. You can also use the [`RunOnDrop`]
1127    /// struct to run a closure after the method executes.
1128    ///
1129    /// [`RunOnDrop`]: zng_app_context::RunOnDrop
1130    pub fn trace<E, S>(self, enter_mtd: E) -> UiNode
1131    where
1132        Self: Sized,
1133        E: FnMut(UiNodeMethod) -> S + Send + 'static,
1134    {
1135        UiNode::new(trace::TraceNode::new(self, enter_mtd))
1136    }
1137}
1138
1139/// Extra [`UiNode`] methods for nodes that define a widget instance context.
1140///
1141/// See [`UiNode::as_widget`] for more details.
1142pub struct WidgetUiNode<'u>(&'u mut dyn WidgetUiNodeImpl);
1143
1144impl<'u> WidgetUiNode<'u> {
1145    /// Calls `visitor` with the [`WIDGET`] context of the widget instance defined by the node.
1146    ///
1147    /// If `update_mode` is [`WidgetUpdateMode::Bubble`] the update flags requested for the widget in `visitor` will be copied to the
1148    /// caller widget context, otherwise they are ignored.
1149    #[inline(always)]
1150    pub fn with_context<R>(&mut self, update_mode: WidgetUpdateMode, visitor: impl FnOnce() -> R) -> R {
1151        let mut once = Some(visitor);
1152        let mut r = None;
1153        self.0.with_context(update_mode, &mut || r = Some(once.take().unwrap()()));
1154        r.unwrap()
1155    }
1156
1157    /// Gets the widget instance ID.
1158    pub fn id(&mut self) -> WidgetId {
1159        self.with_context(WidgetUpdateMode::Ignore, || WIDGET.id())
1160    }
1161}
1162
1163/// See [`UiNode::into_widget`]
1164#[expect(non_camel_case_types)]
1165#[widget($crate::widget::node::into_widget)]
1166struct into_widget(crate::widget::base::WidgetBase);
1167#[zng_app_proc_macros::property(CHILD, widget_impl(into_widget))]
1168fn child(wgt: &mut WidgetBuilding, child: impl IntoUiNode) {
1169    wgt.set_child(child);
1170}
1171impl into_widget {
1172    fn widget_intrinsic(&mut self) {
1173        self.widget_builder().push_build_action(|b| {
1174            b.push_intrinsic(NestGroup::CONTEXT, "detailed_hit_test", detailed_hit_test);
1175        });
1176    }
1177}
1178// Use detailed hit-test for `into_widget!`, this is a better default because
1179// the widget can easily end-up filling the available area while the child node
1180// is aligned to a side.
1181fn detailed_hit_test(child: UiNode) -> UiNode {
1182    // this code is equivalent to setting the hit_test_mode property that
1183    // is unfortunately declared in "crates\zng-wgt\src\hit_test_props.rs"
1184    use super::base::*;
1185    let mut mode = None;
1186    let ctx = ContextInitHandle::new();
1187    match_node(child, move |c, op| {
1188        if mode.is_none() {
1189            mode = Some(std::sync::Arc::new(
1190                HIT_TEST_MODE_VAR
1191                    .map(|m| match m {
1192                        HitTestMode::Disabled => HitTestMode::Disabled,
1193                        _ => HitTestMode::Detailed,
1194                    })
1195                    .current_context()
1196                    .into(),
1197            ));
1198        }
1199        HIT_TEST_MODE_VAR.with_context(ctx.clone(), &mut mode, || {
1200            match op {
1201                UiNodeOp::Init => {
1202                    WIDGET.sub_var_render(&HIT_TEST_MODE_VAR);
1203                }
1204                UiNodeOp::Render { frame } => {
1205                    match HIT_TEST_MODE_VAR.get() {
1206                        HitTestMode::Disabled => {}
1207                        _ => {
1208                            // HitTestMode::Detailed
1209                            frame.with_auto_hit_test(true, |frame| c.render(frame));
1210                        }
1211                    }
1212                }
1213                _ => (),
1214            }
1215        })
1216    })
1217}
1218
1219struct NilUiNode;
1220impl UiNodeImpl for NilUiNode {
1221    fn measure(&mut self, _: &mut WidgetMeasure) -> PxSize {
1222        PxSize::zero()
1223    }
1224
1225    fn layout(&mut self, _: &mut WidgetLayout) -> PxSize {
1226        PxSize::zero()
1227    }
1228
1229    fn children_len(&self) -> usize {
1230        0
1231    }
1232
1233    fn with_child(&mut self, _: usize, _: &mut dyn FnMut(&mut UiNode)) {}
1234}
1235
1236/// A UI node that fills the available layout space.
1237///
1238/// The space is blank, the node does nothing other then layout to fill.
1239pub struct FillUiNode;
1240impl UiNodeImpl for FillUiNode {
1241    fn children_len(&self) -> usize {
1242        0
1243    }
1244
1245    fn with_child(&mut self, _: usize, _: &mut dyn FnMut(&mut UiNode)) {}
1246
1247    // default impl is fill
1248}
1249
1250/// Wraps `child` in a node that provides a unique [`ContextInitHandle`], refreshed every (re)init.
1251///
1252/// [`ContextInitHandle`]: zng_var::ContextInitHandle
1253pub fn with_new_context_init_id(child: impl IntoUiNode) -> UiNode {
1254    let mut id = None;
1255
1256    match_node(child, move |child, op| {
1257        let is_deinit = matches!(op, UiNodeOp::Deinit);
1258        id.get_or_insert_with(ContextInitHandle::new).with_context(|| child.op(op));
1259
1260        if is_deinit {
1261            id = None;
1262        }
1263    })
1264}