zng_app/widget/node/
match_node.rs

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