zng_app/widget/node/
match_node.rs

1use std::{fmt, mem, ops};
2
3use zng_layout::unit::PxSize;
4
5use crate::{
6    render::{FrameBuilder, FrameUpdate},
7    update::WidgetUpdates,
8    widget::info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
9};
10
11use super::*;
12
13/// Represents a node operation in a [`match_node`].
14///
15/// [`match_node`]: fn@match_node
16#[non_exhaustive]
17pub enum UiNodeOp<'a> {
18    /// The [`UiNode::init`].
19    ///
20    /// Initialize the node in a new UI context.
21    ///
22    /// Common init operations are subscribing to variables and events and initializing data.
23    /// You can use [`WIDGET`] to subscribe events and vars, the subscriptions live until the widget is deinited.
24    ///
25    /// This operation can be called again after a [`Deinit`].
26    ///
27    /// [`Deinit`]: Self::Deinit
28    Init,
29    /// The [`UiNode::deinit`].
30    ///
31    /// Deinitialize the node in the current UI context.
32    ///
33    /// Common deinit operations include dropping allocations and handlers.
34    ///
35    /// [`Init`] can be called again after this.
36    ///
37    /// [`Init`]: Self::Init
38    Deinit,
39    /// The [`UiNode::info`].
40    ///
41    /// Build widget info.
42    ///
43    /// This operation is called every time there are structural changes in the UI tree such as a node added or removed, you
44    /// can also request an info rebuild using [`WIDGET.update_info`].
45    ///
46    /// Only nodes in widgets that requested info rebuild and nodes in their ancestors receive this call. Other
47    /// widgets reuse their info in the new info tree. The widget's latest built info is available in [`WIDGET.info`].
48    ///
49    /// Note that info rebuild has higher priority over event, update, layout and render, this means that if you set a variable
50    /// and request info update the next info rebuild will still observe the old variable value, you can work around this issue by
51    /// only requesting info rebuild after the variable updates.
52    ///
53    /// [`WIDGET.update_info`]: crate::widget::WIDGET::update_info
54    /// [`WIDGET.info`]: crate::widget::WIDGET::info
55    Info {
56        /// Info builder.
57        info: &'a mut WidgetInfoBuilder,
58    },
59    /// The [`UiNode::update`].
60    ///
61    /// Receive event, variable and other updates.
62    ///
63    /// Calls to this operation aggregate all updates that happen in the last pass, multiple events and variables can be new at the same time.
64    /// You can listen to variable updates by subscribing to then on [`Init`] and using the [`Var::get_new`] method during this operation
65    /// to receive the new values.
66    ///
67    /// Common update operations include reacting to variable changes to generate an intermediary value
68    /// for layout or render. You can use [`WIDGET`] to request layout and render. Note that for simple variables
69    /// that are used directly on layout or render you can subscribe to that operation directly, skipping update.
70    ///
71    /// When an ancestor handles the event before the descendants this is a ***preview*** handling, so match nodes handle
72    /// event operations in preview by default, unless delegated first.
73    ///
74    /// [`Init`]: Self::Init
75    /// [`Var::get_new`]: zng_var::Var::get_new
76    Update {
77        /// Update targets
78        updates: &'a WidgetUpdates,
79    },
80    /// The [`UiNode::measure`].
81    ///
82    /// Compute the widget size given the contextual layout metrics without actually updating the widget layout.
83    ///
84    /// Implementers must set `desired_size` to the same size [`Layout`] sets for the given [`LayoutMetrics`], without
85    /// affecting the actual widget render. Panel widgets that implement some complex layouts need to get
86    /// the estimated widget size for a given layout context, this value is used to inform the actual [`Layout`] call.
87    ///
88    /// Nodes that implement [`Layout`] must also implement this operation, the [`LAYOUT`] context can be used to retrieve the metrics,
89    /// the [`WidgetMeasure`] field can be used to communicate with the parent layout, such as disabling inline layout, the
90    /// [`PxSize`] field must be set to the desired size given the layout context.
91    ///
92    /// [`Layout`]: Self::Layout
93    /// [`LayoutMetrics`]: zng_layout::context::LayoutMetrics
94    /// [`LAYOUT`]: zng_layout::context::LAYOUT
95    /// [`PxSize`]: zng_layout::unit::PxSize
96    Measure {
97        /// Measure pass state.
98        wm: &'a mut WidgetMeasure,
99        /// Return value, the widget's desired size after measure.
100        desired_size: &'a mut PxSize,
101    },
102    /// The [`UiNode::layout`].
103    ///
104    /// Compute the widget layout given the contextual layout metrics.
105    ///
106    /// Implementers must also implement [`Measure`]. This operation is called by the parent layout once the final constraints
107    /// for the frame are defined, the [`LAYOUT`] context can be used to retrieve the constraints, the [`WidgetLayout`] field
108    /// can be used to communicate layout metadata such as inline segments to the parent layout, the [`PxSize`] field must be
109    /// set to the final size given the layout context.
110    ///
111    /// Only widgets and ancestors that requested layout or use metrics that changed since last layout receive this call. Other
112    /// widgets reuse the last layout result.
113    ///
114    /// Nodes that render can also implement this operation just to observe the latest widget size, if changes are detected
115    /// the [`WIDGET.render`] method can be used to request render.
116    ///
117    /// [`Measure`]: Self::Measure
118    /// [`LayoutMetrics`]: zng_layout::context::LayoutMetrics
119    /// [`constraints`]: zng_layout::context::LayoutMetrics::constraints
120    /// [`WIDGET.render`]: crate::widget::WIDGET::render
121    /// [`LAYOUT`]: zng_layout::context::LAYOUT
122    /// [`PxSize`]: zng_layout::unit::PxSize
123    Layout {
124        /// Layout pass state.
125        wl: &'a mut WidgetLayout,
126        /// Return value, the widget's final size after layout.
127        final_size: &'a mut PxSize,
128    },
129    /// The [`UiNode::render`].
130    ///
131    /// Generate render instructions and update transforms and hit-test areas.
132    ///
133    /// This operation does not generate pixels immediately, it generates *display items* that are visual building block instructions
134    /// for the renderer that will run after the window *display list* is built.
135    ///
136    /// Only widgets and ancestors that requested render receive this call, other widgets reuse the display items and transforms
137    /// from the last frame.
138    Render {
139        /// Frame builder.
140        frame: &'a mut FrameBuilder,
141    },
142    /// The [`UiNode::render_update`].
143    ///
144    /// Update values in the last generated frame.
145    ///
146    /// Some display item values and transforms can be updated directly, without needing to rebuild the display list. All [`FrameBuilder`]
147    /// methods that accept a [`FrameValue<T>`] input can be bound to an ID that can be used to update that value.
148    ///
149    /// Only widgets and ancestors that requested render update receive this call. Note that if any other widget in the same window
150    /// requests render all pending render update requests are upgraded to render requests.
151    ///
152    /// [`FrameValue<T>`]: crate::render::FrameValue
153    RenderUpdate {
154        /// Fame updater.
155        update: &'a mut FrameUpdate,
156    },
157}
158impl<'a> UiNodeOp<'a> {
159    /// Gets the operation without the associated data.
160    pub fn mtd(&self) -> UiNodeMethod {
161        match self {
162            UiNodeOp::Init => UiNodeMethod::Init,
163            UiNodeOp::Deinit => UiNodeMethod::Deinit,
164            UiNodeOp::Info { .. } => UiNodeMethod::Info,
165            UiNodeOp::Update { .. } => UiNodeMethod::Update,
166            UiNodeOp::Measure { .. } => UiNodeMethod::Measure,
167            UiNodeOp::Layout { .. } => UiNodeMethod::Layout,
168            UiNodeOp::Render { .. } => UiNodeMethod::Render,
169            UiNodeOp::RenderUpdate { .. } => UiNodeMethod::RenderUpdate,
170        }
171    }
172
173    /// Reborrow the op.
174    pub fn reborrow(&mut self) -> UiNodeOp<'_> {
175        match self {
176            UiNodeOp::Init => UiNodeOp::Init,
177            UiNodeOp::Deinit => UiNodeOp::Deinit,
178            UiNodeOp::Info { info } => UiNodeOp::Info { info },
179            UiNodeOp::Update { updates } => UiNodeOp::Update { updates },
180            UiNodeOp::Measure { wm, desired_size } => UiNodeOp::Measure { wm, desired_size },
181            UiNodeOp::Layout { wl, final_size } => UiNodeOp::Layout { wl, final_size },
182            UiNodeOp::Render { frame } => UiNodeOp::Render { frame },
183            UiNodeOp::RenderUpdate { update } => UiNodeOp::RenderUpdate { update },
184        }
185    }
186}
187impl fmt::Debug for UiNodeOp<'_> {
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        match self {
190            Self::Update { updates } => f.debug_struct("Update").field("updates", updates).finish(),
191            op => write!(f, "{}", op.mtd()),
192        }
193    }
194}
195
196/// Identifies the [`UiNode`] UI methods.
197#[derive(Clone, Copy, serde::Serialize, serde::Deserialize)]
198#[non_exhaustive]
199pub enum UiNodeMethod {
200    /// The [`UiNode::init`].
201    Init,
202    /// The [`UiNode::deinit`].
203    Deinit,
204    /// The [`UiNode::info`].
205    Info,
206    /// The [`UiNode::update`].
207    Update,
208    /// The [`UiNode::update_list`]
209    UpdateList,
210    /// The [`UiNode::measure`].
211    Measure,
212    /// The [`UiNode::measure_list`].
213    MeasureList,
214    /// The [`UiNode::layout`].
215    Layout,
216    /// The [`UiNode::layout_list`].
217    LayoutList,
218    /// The [`UiNode::render`].
219    Render,
220    /// The [`UiNode::render_list`].
221    RenderList,
222    /// The [`UiNode::render_update`].
223    RenderUpdate,
224    /// The [`UiNode::render_update_list`].
225    RenderUpdateList,
226}
227impl UiNodeMethod {
228    /// Gets an static string representing the enum variant (CamelCase).
229    pub fn enum_name(self) -> &'static str {
230        match self {
231            UiNodeMethod::Init => "Init",
232            UiNodeMethod::Deinit => "Deinit",
233            UiNodeMethod::Info => "Info",
234            UiNodeMethod::Update => "Update",
235            UiNodeMethod::UpdateList => "UpdateList",
236            UiNodeMethod::Measure => "Measure",
237            UiNodeMethod::MeasureList => "MeasureList",
238            UiNodeMethod::Layout => "Layout",
239            UiNodeMethod::LayoutList => "LayoutList",
240            UiNodeMethod::Render => "Render",
241            UiNodeMethod::RenderList => "RenderList",
242            UiNodeMethod::RenderUpdate => "RenderUpdate",
243            UiNodeMethod::RenderUpdateList => "RenderUpdateList",
244        }
245    }
246
247    /// Gets an static string representing the method name (snake_case).
248    pub fn mtd_name(self) -> &'static str {
249        match self {
250            UiNodeMethod::Init => "init",
251            UiNodeMethod::Deinit => "deinit",
252            UiNodeMethod::Info => "info",
253            UiNodeMethod::Update => "update",
254            UiNodeMethod::UpdateList => "update_list",
255            UiNodeMethod::Measure => "measure",
256            UiNodeMethod::MeasureList => "measure_list",
257            UiNodeMethod::Layout => "layout",
258            UiNodeMethod::LayoutList => "layout_list",
259            UiNodeMethod::Render => "render",
260            UiNodeMethod::RenderList => "render_list",
261            UiNodeMethod::RenderUpdate => "render_update",
262            UiNodeMethod::RenderUpdateList => "render_update_list",
263        }
264    }
265}
266impl fmt::Debug for UiNodeMethod {
267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268        fmt::Display::fmt(self, f)
269    }
270}
271impl fmt::Display for UiNodeMethod {
272    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273        if f.alternate() {
274            write!(f, "{}", self.enum_name())
275        } else {
276            write!(f, "{}", self.mtd_name())
277        }
278    }
279}
280
281/// Creates a node that is implemented as a closure that matches over [`UiNodeOp`] and delegates to another child node.
282///
283/// The closure node can delegate to `child`, when the `closure` itself does not delegate, the `child` methods
284/// are called after the closure returns. See [`MatchNodeChild`] for more details.
285///
286/// This is a convenient way of declaring anonymous nodes, such as those that implement a property function. By leveraging
287/// closure captures, state can be easily declared and used, without the verbosity of declaring a struct.
288///
289/// # Examples
290///
291/// The example declares a property node that implements multiple UI node operations.
292///
293/// ```
294/// # fn main() { }
295/// # use zng_app::{*, widget::{*, node::*, builder::*}};
296/// # use zng_var::*;
297/// # use zng_layout::context::LAYOUT;
298/// #[property(LAYOUT)]
299/// pub fn count_layout(child: impl IntoUiNode, enabled: impl IntoVar<bool>) -> UiNode {
300///     let enabled = enabled.into_var();
301///     let mut layout_count = 0;
302///
303///     match_node(child, move |child, op| match op {
304///         UiNodeOp::Init => {
305///             WIDGET.sub_var(&enabled);
306///         }
307///         UiNodeOp::Update { .. } => {
308///             if let Some(true) = enabled.get_new() {
309///                 println!("layout count reset");
310///                 layout_count = 0;
311///             }
312///         }
313///         UiNodeOp::Measure { wm, desired_size } => {
314///             let s = child.measure(wm);
315///             *desired_size = LAYOUT.constraints().fill_size_or(s);
316///         }
317///         UiNodeOp::Layout { wl, final_size } => {
318///             if enabled.get() {
319///                 layout_count += 1;
320///                 println!("layout {layout_count}");
321///             }
322///             let s = child.layout(wl);
323///             *final_size = LAYOUT.constraints().fill_size_or(s);
324///         }
325///         _ => {}
326///     })
327/// }
328/// ```
329///
330/// # See Also
331///
332/// See also [`match_node_leaf`] that declares a leaf node (no child) and [`match_widget`] that can extend a widget node.
333///
334/// [`match_widget`]: fn@match_widget
335pub fn match_node(child: impl IntoUiNode, closure: impl FnMut(&mut MatchNodeChild, UiNodeOp) + Send + 'static) -> UiNode {
336    match_node_impl(child.into_node(), closure)
337}
338
339fn match_node_impl(child: UiNode, closure: impl FnMut(&mut MatchNodeChild, UiNodeOp) + Send + 'static) -> UiNode {
340    struct MatchNode<F> {
341        child: MatchNodeChild,
342        closure: F,
343    }
344    impl<F: FnMut(&mut MatchNodeChild, UiNodeOp) + Send + 'static> UiNodeImpl for MatchNode<F> {
345        fn children_len(&self) -> usize {
346            1
347        }
348
349        fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
350            if index == 0 {
351                visitor(&mut self.child.node)
352            }
353        }
354
355        fn init(&mut self) {
356            self.child.delegated = false;
357
358            (self.closure)(&mut self.child, UiNodeOp::Init);
359
360            if !mem::take(&mut self.child.delegated) {
361                self.child.node.0.init();
362            }
363        }
364
365        fn deinit(&mut self) {
366            self.child.delegated = false;
367
368            (self.closure)(&mut self.child, UiNodeOp::Deinit);
369
370            if !mem::take(&mut self.child.delegated) {
371                self.child.node.0.deinit();
372            }
373        }
374
375        fn info(&mut self, info: &mut WidgetInfoBuilder) {
376            self.child.delegated = false;
377
378            (self.closure)(&mut self.child, UiNodeOp::Info { info });
379
380            if !mem::take(&mut self.child.delegated) {
381                self.child.node.0.info(info);
382            }
383        }
384
385        fn update(&mut self, updates: &WidgetUpdates) {
386            self.child.delegated = false;
387
388            (self.closure)(&mut self.child, UiNodeOp::Update { updates });
389
390            if !mem::take(&mut self.child.delegated) {
391                self.child.node.0.update(updates);
392            }
393        }
394
395        fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
396            self.child.delegated = false;
397
398            let mut size = PxSize::zero();
399            (self.closure)(
400                &mut self.child,
401                UiNodeOp::Measure {
402                    wm,
403                    desired_size: &mut size,
404                },
405            );
406
407            if !mem::take(&mut self.child.delegated) {
408                if size != PxSize::zero() {
409                    // this is an error because the child will be measured if the return size is zero,
410                    // flagging delegated ensure consistent behavior.
411                    tracing::error!("measure changed size without flagging delegated");
412                    return size;
413                }
414
415                self.child.node.0.measure(wm)
416            } else {
417                size
418            }
419        }
420
421        fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
422            self.child.delegated = false;
423
424            let mut size = PxSize::zero();
425            (self.closure)(&mut self.child, UiNodeOp::Layout { wl, final_size: &mut size });
426
427            if !mem::take(&mut self.child.delegated) {
428                if size != PxSize::zero() {
429                    // this is an error because the child will be layout if the return size is zero,
430                    // flagging delegated ensure consistent behavior.
431                    tracing::error!("layout changed size without flagging delegated");
432                    return size;
433                }
434
435                self.child.node.0.layout(wl)
436            } else {
437                size
438            }
439        }
440
441        fn render(&mut self, frame: &mut FrameBuilder) {
442            self.child.delegated = false;
443
444            (self.closure)(&mut self.child, UiNodeOp::Render { frame });
445
446            if !mem::take(&mut self.child.delegated) {
447                self.child.node.0.render(frame);
448            }
449        }
450
451        fn render_update(&mut self, update: &mut FrameUpdate) {
452            self.child.delegated = false;
453
454            (self.closure)(&mut self.child, UiNodeOp::RenderUpdate { update });
455
456            if !mem::take(&mut self.child.delegated) {
457                self.child.node.0.render_update(update);
458            }
459        }
460
461        fn is_list(&self) -> bool {
462            false
463        }
464
465        fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
466            visitor(0, &mut self.child.node)
467        }
468
469        fn try_for_each_child(
470            &mut self,
471            visitor: &mut dyn FnMut(usize, &mut UiNode) -> ControlFlow<BoxAnyVarValue>,
472        ) -> ControlFlow<BoxAnyVarValue> {
473            visitor(0, &mut self.child.node)
474        }
475
476        fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
477            visitor(0, &mut self.child.node)
478        }
479
480        fn par_fold_reduce(
481            &mut self,
482            identity: BoxAnyVarValue,
483            fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
484            _: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
485        ) -> BoxAnyVarValue {
486            fold(identity, 0, &mut self.child.node)
487        }
488
489        fn update_list(&mut self, updates: &WidgetUpdates, _: &mut dyn UiNodeListObserver) {
490            self.update(updates);
491        }
492
493        fn measure_list(
494            &mut self,
495            wm: &mut WidgetMeasure,
496            _: &(dyn Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync),
497            _: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
498        ) -> PxSize {
499            self.measure(wm)
500        }
501
502        fn layout_list(
503            &mut self,
504            wl: &mut WidgetLayout,
505            _: &(dyn Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync),
506            _: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
507        ) -> PxSize {
508            self.layout(wl)
509        }
510
511        fn render_list(&mut self, frame: &mut FrameBuilder, _: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
512            self.render(frame)
513        }
514
515        fn render_update_list(&mut self, update: &mut FrameUpdate, _: &(dyn Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync)) {
516            self.render_update(update);
517        }
518
519        fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
520            None
521        }
522    }
523    MatchNode {
524        child: MatchNodeChild {
525            node: child,
526            delegated: false,
527        },
528        closure,
529    }
530    .into_node()
531}
532
533/// Child node of [`match_node`].
534///
535/// When the closure does not delegate to this node the delegation happens after the closure returns.
536///
537/// [`match_node`]: fn@match_node
538pub struct MatchNodeChild {
539    node: UiNode,
540    delegated: bool,
541}
542impl MatchNodeChild {
543    /// Flags the current operation as *delegated*, stopping the default delegation after the closure ends.
544    ///
545    /// Note that each node operation methods already flags this.
546    #[inline(always)]
547    pub fn delegated(&mut self) {
548        self.delegated = true;
549    }
550
551    /// If the current operation was already delegated to the child.
552    #[inline(always)]
553    pub fn has_delegated(&self) -> bool {
554        self.delegated
555    }
556
557    /// Borrow the actual child.
558    ///
559    /// Note that if you delegate using this reference you must call [`delegated`].
560    ///
561    /// [`delegated`]: Self::delegated
562    #[inline(always)]
563    pub fn node(&mut self) -> &mut UiNode {
564        &mut self.node
565    }
566    /// Borrow the actual child implementation.
567    ///
568    /// Note that if you delegate using this reference you must call [`delegated`].
569    ///
570    /// # Panics
571    ///
572    /// Panics if the child node implementation does not match.
573    ///
574    /// [`delegated`]: Self::delegated
575    #[inline(always)]
576    pub fn node_impl<U: UiNodeImpl>(&mut self) -> &mut U {
577        self.node.downcast_mut::<U>().unwrap()
578    }
579
580    /// Delegate [`UiNode::init`].
581    #[inline(always)]
582    pub fn init(&mut self) {
583        self.node.0.init();
584        self.delegated = true;
585    }
586
587    /// Delegate [`UiNode::deinit`].
588    #[inline(always)]
589    pub fn deinit(&mut self) {
590        self.node.0.deinit();
591        self.delegated = true;
592    }
593
594    /// Delegate [`UiNode::info`].
595    #[inline(always)]
596    pub fn info(&mut self, info: &mut WidgetInfoBuilder) {
597        self.node.0.info(info);
598        self.delegated = true;
599    }
600
601    /// Delegate [`UiNode::update`].
602    #[inline(always)]
603    pub fn update(&mut self, updates: &WidgetUpdates) {
604        self.node.0.update(updates);
605        self.delegated = true;
606    }
607
608    /// Delegate [`UiNode::update_list`].
609    #[inline(always)]
610    pub fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
611        self.node.0.update_list(updates, observer);
612        self.delegated = true;
613    }
614
615    /// Delegate [`UiNode::measure`].
616    #[inline(always)]
617    #[must_use]
618    pub fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
619        self.delegated = true;
620        self.node.0.measure(wm)
621    }
622
623    /// Delegate [`UiNode::measure_list`].
624    #[inline(always)]
625    #[must_use]
626    pub fn measure_list(
627        &mut self,
628        wm: &mut WidgetMeasure,
629        measure: impl Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync,
630        fold_size: impl Fn(PxSize, PxSize) -> PxSize + Sync,
631    ) -> PxSize {
632        self.delegated = true;
633        self.node.0.measure_list(wm, &measure, &fold_size)
634    }
635
636    /// Delegate [`UiNode::layout`].
637    #[inline(always)]
638    #[must_use]
639    pub fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
640        self.delegated = true;
641        self.node.0.layout(wl)
642    }
643
644    /// Delegate [`UiNode::layout_list`].
645    #[inline(always)]
646    #[must_use]
647    pub fn layout_list(
648        &mut self,
649        wl: &mut WidgetLayout,
650        layout: impl Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync,
651        fold_size: impl Fn(PxSize, PxSize) -> PxSize + Sync,
652    ) -> PxSize {
653        self.delegated = true;
654        self.node.0.layout_list(wl, &layout, &fold_size)
655    }
656
657    /// Delegate [`UiNode::render`].
658    #[inline(always)]
659    pub fn render(&mut self, frame: &mut FrameBuilder) {
660        self.node.0.render(frame);
661        self.delegated = true;
662    }
663
664    /// Delegate [`UiNode::render_list`].
665    #[inline(always)]
666    pub fn render_list(&mut self, frame: &mut FrameBuilder, render: impl Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync) {
667        self.node.render_list(frame, render);
668        self.delegated = true;
669    }
670
671    /// Delegate [`UiNode::render_update`].
672    #[inline(always)]
673    pub fn render_update(&mut self, update: &mut FrameUpdate) {
674        self.node.0.render_update(update);
675        self.delegated = true;
676    }
677
678    /// Delegate [`UiNode::render_update_list`].
679    #[inline(always)]
680    pub fn render_update_list(&mut self, update: &mut FrameUpdate, render_update: impl Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync) {
681        self.node.render_update_list(update, render_update);
682    }
683
684    /// Delegate [`UiNode::op`].
685    #[inline(always)]
686    pub fn op(&mut self, op: UiNodeOp) {
687        self.node.op(op);
688        self.delegated = true;
689    }
690}
691
692/// Creates a node that is implemented as a closure that matches over [`UiNodeOp`] and does not delegate to any child node.
693pub fn match_node_leaf(closure: impl FnMut(UiNodeOp) + Send + 'static) -> UiNode {
694    struct MatchNodeLeaf<F> {
695        closure: F,
696    }
697    impl<F: FnMut(UiNodeOp) + Send + 'static> UiNodeImpl for MatchNodeLeaf<F> {
698        fn children_len(&self) -> usize {
699            0
700        }
701        fn with_child(&mut self, _: usize, _: &mut dyn FnMut(&mut UiNode)) {}
702
703        fn init(&mut self) {
704            (self.closure)(UiNodeOp::Init);
705        }
706
707        fn deinit(&mut self) {
708            (self.closure)(UiNodeOp::Deinit);
709        }
710
711        fn info(&mut self, info: &mut WidgetInfoBuilder) {
712            (self.closure)(UiNodeOp::Info { info });
713        }
714
715        fn update(&mut self, updates: &WidgetUpdates) {
716            (self.closure)(UiNodeOp::Update { updates });
717        }
718
719        fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
720            let mut size = PxSize::zero();
721            (self.closure)(UiNodeOp::Measure {
722                wm,
723                desired_size: &mut size,
724            });
725            size
726        }
727
728        fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
729            let mut size = PxSize::zero();
730            (self.closure)(UiNodeOp::Layout { wl, final_size: &mut size });
731            size
732        }
733
734        fn render(&mut self, frame: &mut FrameBuilder) {
735            (self.closure)(UiNodeOp::Render { frame });
736        }
737
738        fn render_update(&mut self, update: &mut FrameUpdate) {
739            (self.closure)(UiNodeOp::RenderUpdate { update });
740        }
741
742        fn is_list(&self) -> bool {
743            false
744        }
745
746        fn for_each_child(&mut self, _: &mut dyn FnMut(usize, &mut UiNode)) {}
747
748        fn try_for_each_child(
749            &mut self,
750            _: &mut dyn FnMut(usize, &mut UiNode) -> ControlFlow<BoxAnyVarValue>,
751        ) -> ControlFlow<BoxAnyVarValue> {
752            ControlFlow::Continue(())
753        }
754
755        fn par_each_child(&mut self, _: &(dyn Fn(usize, &mut UiNode) + Sync)) {}
756
757        fn par_fold_reduce(
758            &mut self,
759            identity: BoxAnyVarValue,
760            _: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
761            _: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
762        ) -> BoxAnyVarValue {
763            identity
764        }
765
766        fn update_list(&mut self, updates: &WidgetUpdates, _: &mut dyn UiNodeListObserver) {
767            self.update(updates);
768        }
769
770        fn measure_list(
771            &mut self,
772            wm: &mut WidgetMeasure,
773            _: &(dyn Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync),
774            _: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
775        ) -> PxSize {
776            self.measure(wm)
777        }
778
779        fn layout_list(
780            &mut self,
781            wl: &mut WidgetLayout,
782            _: &(dyn Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync),
783            _: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
784        ) -> PxSize {
785            self.layout(wl)
786        }
787
788        fn render_list(&mut self, frame: &mut FrameBuilder, _: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
789            self.render(frame);
790        }
791
792        fn render_update_list(&mut self, update: &mut FrameUpdate, _: &(dyn Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync)) {
793            self.render_update(update);
794        }
795
796        fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
797            None
798        }
799    }
800    UiNode::new(MatchNodeLeaf { closure })
801}
802
803/// Creates a widget that is implemented as a closure that matches over [`UiNodeOp`] and delegates to another child widget.
804///
805/// The returned node will delegate to `child` like [`match_node`] does, and will also delegate [`UiNode::as_widget`].
806///
807/// Note that the `closure` itself will not run inside [`WidgetUiNode::with_context`].
808pub fn match_widget(child: impl IntoUiNode, closure: impl FnMut(&mut MatchWidgetChild, UiNodeOp) + Send + 'static) -> UiNode {
809    struct MatchWidget<F> {
810        child: MatchWidgetChild,
811        closure: F,
812    }
813    impl<F: FnMut(&mut MatchWidgetChild, UiNodeOp) + Send + 'static> UiNodeImpl for MatchWidget<F> {
814        fn children_len(&self) -> usize {
815            1
816        }
817
818        fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
819            if index == 0 {
820                visitor(&mut self.child.node)
821            }
822        }
823
824        fn init(&mut self) {
825            self.child.0.delegated = false;
826
827            (self.closure)(&mut self.child, UiNodeOp::Init);
828
829            if !mem::take(&mut self.child.0.delegated) {
830                self.child.0.node.0.init();
831            }
832        }
833
834        fn deinit(&mut self) {
835            self.child.0.delegated = false;
836
837            (self.closure)(&mut self.child, UiNodeOp::Deinit);
838
839            if !mem::take(&mut self.child.0.delegated) {
840                self.child.0.node.0.deinit();
841            }
842        }
843
844        fn info(&mut self, info: &mut WidgetInfoBuilder) {
845            self.child.0.delegated = false;
846
847            (self.closure)(&mut self.child, UiNodeOp::Info { info });
848
849            if !mem::take(&mut self.child.0.delegated) {
850                self.child.0.node.0.info(info);
851            } else {
852                #[cfg(debug_assertions)]
853                if self
854                    .child
855                    .0
856                    .node
857                    .as_widget()
858                    .map(|mut w| {
859                        w.with_context(crate::widget::WidgetUpdateMode::Ignore, || {
860                            WIDGET.pending_update().contains(crate::update::UpdateFlags::INFO)
861                        })
862                    })
863                    .unwrap_or(false)
864                {
865                    // this is likely an error, but a child widget could have requested info again
866                    tracing::warn!(target: "match_widget-pending", "pending info build after info delegated in {:?}", WIDGET.id());
867                }
868            }
869        }
870
871        fn update(&mut self, updates: &WidgetUpdates) {
872            self.child.0.delegated = false;
873
874            (self.closure)(&mut self.child, UiNodeOp::Update { updates });
875
876            if !mem::take(&mut self.child.0.delegated) {
877                self.child.0.node.0.update(updates);
878            }
879        }
880
881        fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
882            self.child.0.delegated = false;
883
884            let mut size = PxSize::zero();
885            (self.closure)(
886                &mut self.child,
887                UiNodeOp::Measure {
888                    wm,
889                    desired_size: &mut size,
890                },
891            );
892
893            if !mem::take(&mut self.child.0.delegated) {
894                if size != PxSize::zero() {
895                    // this is an error because the child will be measured if the return size is zero,
896                    // flagging delegated ensure consistent behavior.
897                    tracing::error!("measure changed size without flagging delegated in {:?}", WIDGET.id());
898                    return size;
899                }
900
901                self.child.0.node.0.measure(wm)
902            } else {
903                size
904            }
905        }
906
907        fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
908            self.child.0.delegated = false;
909
910            let mut size = PxSize::zero();
911            (self.closure)(&mut self.child, UiNodeOp::Layout { wl, final_size: &mut size });
912
913            if !mem::take(&mut self.child.0.delegated) {
914                if size != PxSize::zero() {
915                    // this is an error because the child will be layout if the return size is zero,
916                    // flagging delegated ensure consistent behavior.
917                    tracing::error!("layout changed size without flagging delegated in {:?}", WIDGET.id());
918                    return size;
919                }
920
921                self.child.0.node.0.layout(wl)
922            } else {
923                #[cfg(debug_assertions)]
924                if self
925                    .child
926                    .0
927                    .node
928                    .as_widget()
929                    .map(|mut w| {
930                        w.with_context(crate::widget::WidgetUpdateMode::Ignore, || {
931                            WIDGET.pending_update().contains(crate::update::UpdateFlags::LAYOUT)
932                        })
933                    })
934                    .unwrap_or(false)
935                {
936                    // this is likely an error, but a child widget could have requested layout again,
937                    tracing::warn!(target: "match_widget-pending", "pending layout after layout delegated in {:?}", WIDGET.id());
938                }
939                size
940            }
941        }
942
943        fn render(&mut self, frame: &mut FrameBuilder) {
944            self.child.0.delegated = false;
945
946            (self.closure)(&mut self.child, UiNodeOp::Render { frame });
947
948            if !mem::take(&mut self.child.0.delegated) {
949                self.child.0.node.0.render(frame);
950            } else {
951                #[cfg(debug_assertions)]
952                if self
953                    .child
954                    .0
955                    .node
956                    .as_widget()
957                    .map(|mut w| {
958                        w.with_context(crate::widget::WidgetUpdateMode::Ignore, || {
959                            WIDGET.pending_update().contains(crate::update::UpdateFlags::RENDER)
960                        })
961                    })
962                    .unwrap_or(false)
963                {
964                    // this is likely an error, but a child widget could have requested render again,
965                    tracing::warn!(target: "match_widget-pending", "pending render after render delegated in {:?}", WIDGET.id());
966                }
967            }
968        }
969
970        fn render_update(&mut self, update: &mut FrameUpdate) {
971            self.child.0.delegated = false;
972
973            (self.closure)(&mut self.child, UiNodeOp::RenderUpdate { update });
974
975            if !mem::take(&mut self.child.0.delegated) {
976                self.child.0.node.0.render_update(update);
977            } else {
978                #[cfg(debug_assertions)]
979                if self
980                    .child
981                    .0
982                    .node
983                    .as_widget()
984                    .map(|mut w| {
985                        w.with_context(crate::widget::WidgetUpdateMode::Ignore, || {
986                            WIDGET.pending_update().contains(crate::update::UpdateFlags::RENDER_UPDATE)
987                        })
988                    })
989                    .unwrap_or(false)
990                {
991                    // this is likely an error, but a child widget could have requested render_update again,
992                    tracing::warn!(target: "match_widget-pending", "pending render_update after render_update delegated in {:?}", WIDGET.id());
993                }
994            }
995        }
996
997        fn is_list(&self) -> bool {
998            false
999        }
1000
1001        fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
1002            visitor(0, &mut self.child.node)
1003        }
1004
1005        fn try_for_each_child(
1006            &mut self,
1007            visitor: &mut dyn FnMut(usize, &mut UiNode) -> ControlFlow<BoxAnyVarValue>,
1008        ) -> ControlFlow<BoxAnyVarValue> {
1009            visitor(0, &mut self.child.node)
1010        }
1011
1012        fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
1013            visitor(0, &mut self.child.node)
1014        }
1015
1016        fn par_fold_reduce(
1017            &mut self,
1018            identity: BoxAnyVarValue,
1019            fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
1020            _: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
1021        ) -> BoxAnyVarValue {
1022            fold(identity, 0, &mut self.child.node)
1023        }
1024
1025        fn update_list(&mut self, updates: &WidgetUpdates, _: &mut dyn UiNodeListObserver) {
1026            self.update(updates);
1027        }
1028
1029        fn measure_list(
1030            &mut self,
1031            wm: &mut WidgetMeasure,
1032            _: &(dyn Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync),
1033            _: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
1034        ) -> PxSize {
1035            self.measure(wm)
1036        }
1037
1038        fn layout_list(
1039            &mut self,
1040            wl: &mut WidgetLayout,
1041            _: &(dyn Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync),
1042            _: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
1043        ) -> PxSize {
1044            self.layout(wl)
1045        }
1046
1047        fn render_list(&mut self, frame: &mut FrameBuilder, _: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
1048            self.render(frame);
1049        }
1050
1051        fn render_update_list(&mut self, update: &mut FrameUpdate, _: &(dyn Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync)) {
1052            self.render_update(update);
1053        }
1054
1055        fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
1056            self.child.node.0.as_widget()
1057        }
1058    }
1059    MatchWidget {
1060        child: MatchWidgetChild(MatchNodeChild {
1061            node: child.into_node(),
1062            delegated: false,
1063        }),
1064        closure,
1065    }
1066    .into_node()
1067}
1068
1069/// Child node of [`match_widget`].
1070///
1071/// This node delegates like [`MatchNodeChild`] plus delegates [`UiNode::as_widget`].
1072///
1073/// [`match_widget`]: fn@match_widget
1074pub struct MatchWidgetChild(MatchNodeChild);
1075impl ops::Deref for MatchWidgetChild {
1076    type Target = MatchNodeChild;
1077
1078    fn deref(&self) -> &Self::Target {
1079        &self.0
1080    }
1081}
1082impl ops::DerefMut for MatchWidgetChild {
1083    fn deref_mut(&mut self) -> &mut Self::Target {
1084        &mut self.0
1085    }
1086}