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