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