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