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