Skip to main content

zng_wgt/
node.rs

1//! Helper nodes.
2//!
3//! This module defines some foundational nodes that can be used for declaring properties and widgets.
4
5use std::{any::Any, sync::Arc};
6
7use crate::WidgetFn;
8use zng_app::{
9    event::{Command, CommandHandle, CommandScope, Event, EventArgs},
10    handler::{Handler, HandlerExt as _},
11    render::{FrameBuilder, FrameValueKey},
12    update::WidgetUpdates,
13    widget::{
14        VarLayout, WIDGET,
15        border::{BORDER, BORDER_ALIGN_VAR, BORDER_OVER_VAR},
16        info::{Interactivity, WIDGET_TREE_CHANGED_EVENT},
17        node::*,
18    },
19    window::WINDOW,
20};
21use zng_app_context::{ContextLocal, LocalContext};
22use zng_layout::{
23    context::LAYOUT,
24    unit::{PxConstraints2d, PxCornerRadius, PxPoint, PxRect, PxSideOffsets, PxSize, PxVector, SideOffsets},
25};
26use zng_state_map::{StateId, StateMapRef, StateValue};
27use zng_var::*;
28
29#[doc(hidden)]
30pub use pastey::paste;
31
32#[doc(hidden)]
33pub mod __macro_util {
34    pub use zng_app::{
35        event::CommandArgs,
36        handler::{Handler, hn},
37        widget::{
38            node::{IntoUiNode, UiNode},
39            property,
40        },
41    };
42    pub use zng_var::{IntoVar, context_var};
43}
44
45/// Helper for declaring properties that sets a context var.
46///
47/// The generated [`UiNode`] delegates each method to `child` inside a call to [`ContextVar::with_context`].
48///
49/// # Examples
50///
51/// A simple context property declaration:
52///
53/// ```
54/// # fn main() -> () { }
55/// # use zng_app::{*, widget::{node::*, *}};
56/// # use zng_var::*;
57/// # use zng_wgt::node::*;
58/// #
59/// context_var! {
60///     pub static FOO_VAR: u32 = 0u32;
61/// }
62///
63/// /// Sets the [`FOO_VAR`] in the widgets and its content.
64/// #[property(CONTEXT, default(FOO_VAR))]
65/// pub fn foo(child: impl IntoUiNode, value: impl IntoVar<u32>) -> UiNode {
66///     with_context_var(child, FOO_VAR, value)
67/// }
68/// ```
69///
70/// When set in a widget, the `value` is accessible in all inner nodes of the widget, using `FOO_VAR.get`, and if `value` is set to a
71/// variable the `FOO_VAR` will also reflect its [`is_new`] and [`read_only`]. If the `value` var is not read-only inner nodes
72/// can modify it using `FOO_VAR.set` or `FOO_VAR.modify`.
73///
74/// Also note that the property [`default`] is set to the same `FOO_VAR`, this causes the property to *pass-through* the outer context
75/// value, as if it was not set.
76///
77/// **Tip:** You can use a [`merge_var!`] to merge a new value to the previous context value:
78///
79/// ```
80/// # fn main() -> () { }
81/// # use zng_app::{*, widget::{node::*, *}};
82/// # use zng_var::*;
83/// # use zng_wgt::node::*;
84/// #
85/// #[derive(Debug, Clone, Default, PartialEq)]
86/// pub struct Config {
87///     pub foo: bool,
88///     pub bar: bool,
89/// }
90///
91/// context_var! {
92///     pub static CONFIG_VAR: Config = Config::default();
93/// }
94///
95/// /// Sets the *foo* config.
96/// #[property(CONTEXT, default(false))]
97/// pub fn foo(child: impl IntoUiNode, value: impl IntoVar<bool>) -> UiNode {
98///     with_context_var(
99///         child,
100///         CONFIG_VAR,
101///         merge_var!(CONFIG_VAR, value.into_var(), |c, &v| {
102///             let mut c = c.clone();
103///             c.foo = v;
104///             c
105///         }),
106///     )
107/// }
108///
109/// /// Sets the *bar* config.
110/// #[property(CONTEXT, default(false))]
111/// pub fn bar(child: impl IntoUiNode, value: impl IntoVar<bool>) -> UiNode {
112///     with_context_var(
113///         child,
114///         CONFIG_VAR,
115///         merge_var!(CONFIG_VAR, value.into_var(), |c, &v| {
116///             let mut c = c.clone();
117///             c.bar = v;
118///             c
119///         }),
120///     )
121/// }
122/// ```
123///
124/// When set in a widget, the [`merge_var!`] will read the context value of the parent properties, modify a clone of the value and
125/// the result will be accessible to the inner properties, the widget user can then set with the composed value in steps and
126/// the final consumer of the composed value only need to monitor to a single context variable.
127///
128/// [`is_new`]: zng_var::AnyVar::is_new
129/// [`read_only`]: zng_var::Var::read_only
130/// [`default`]: zng_app::widget::property#default
131/// [`merge_var!`]: zng_var::merge_var
132/// [`UiNode`]: zng_app::widget::node::UiNode
133/// [`ContextVar::with_context`]: zng_var::ContextVar::with_context
134pub fn with_context_var<T: VarValue>(child: impl IntoUiNode, context_var: ContextVar<T>, value: impl IntoVar<T>) -> UiNode {
135    let value = value.into_var();
136    let mut actual_value = None;
137    let mut id = None;
138
139    match_node(child, move |child, op| {
140        let mut is_deinit = false;
141        match &op {
142            UiNodeOp::Init => {
143                id = Some(ContextInitHandle::new());
144                actual_value = Some(Arc::new(value.current_context().into()));
145            }
146            UiNodeOp::Deinit => {
147                is_deinit = true;
148            }
149            _ => {}
150        }
151
152        context_var.with_context(id.clone().expect("node not inited"), &mut actual_value, || child.op(op));
153
154        if is_deinit {
155            id = None;
156            actual_value = None;
157        }
158    })
159}
160
161/// Helper for declaring properties that sets a context var to a value generated on init.
162///
163/// The method calls the `init_value` closure on init to produce a *value* var that is presented as the [`ContextVar<T>`]
164/// in the widget and widget descendants. The closure can be called more than once if the returned node is reinited.
165///
166/// Apart from the value initialization this behaves just like [`with_context_var`].
167///
168/// [`ContextVar<T>`]: zng_var::ContextVar
169pub fn with_context_var_init<T: VarValue>(
170    child: impl IntoUiNode,
171    var: ContextVar<T>,
172    mut init_value: impl FnMut() -> Var<T> + Send + 'static,
173) -> UiNode {
174    let mut id = None;
175    let mut value = None;
176    match_node(child, move |child, op| {
177        let mut is_deinit = false;
178        match &op {
179            UiNodeOp::Init => {
180                id = Some(ContextInitHandle::new());
181                value = Some(Arc::new(init_value().current_context().into()));
182            }
183            UiNodeOp::Deinit => {
184                is_deinit = true;
185            }
186            _ => {}
187        }
188
189        var.with_context(id.clone().expect("node not inited"), &mut value, || child.op(op));
190
191        if is_deinit {
192            id = None;
193            value = None;
194        }
195    })
196}
197
198/// Helper for declaring event properties.
199pub struct EventNodeBuilder<A: EventArgs, F, M> {
200    event: Event<A>,
201    filter_builder: F,
202    map_args: M,
203}
204/// Helper for declaring event properties from variables.
205pub struct VarEventNodeBuilder<I, F, M> {
206    init_var: I,
207    filter_builder: F,
208    map_args: M,
209}
210
211impl<A: EventArgs> EventNodeBuilder<A, (), ()> {
212    /// Node that calls the handler for all args that target the widget and has not stopped propagation.
213    pub fn new(event: Event<A>) -> EventNodeBuilder<A, (), ()> {
214        EventNodeBuilder {
215            event,
216            filter_builder: (),
217            map_args: (),
218        }
219    }
220}
221impl<I, T> VarEventNodeBuilder<I, (), ()>
222where
223    T: VarValue,
224    I: FnMut() -> Var<T> + Send + 'static,
225{
226    /// Node that calls the handler for var updates.
227    ///
228    /// The `init_var` is called on init to
229    pub fn new(init_var: I) -> VarEventNodeBuilder<I, (), ()> {
230        VarEventNodeBuilder {
231            init_var,
232            filter_builder: (),
233            map_args: (),
234        }
235    }
236}
237
238impl<A: EventArgs, M> EventNodeBuilder<A, (), M> {
239    /// Filter event.
240    ///
241    /// The `filter_builder` is called on init and on event, it must produce another closure, the filter predicate. The `filter_builder`
242    /// runs in the widget context, the filter predicate does not always.
243    ///
244    /// In the event hook the filter predicate runs in the app context, it is called if the args target the widget, the predicate must
245    /// use any captured contextual info to filter the args, this is an optimization, it can save a visit to the widget node.
246    ///
247    /// If the event is received the second filter predicate is called again to confirm the event.
248    /// The second instance is called if [`propagation`] was not stopped, if it returns `true` the `handler` closure is called.
249    ///
250    /// Note that events that represent an *interaction* with the widget are send for both [`ENABLED`] and [`DISABLED`] targets,
251    /// event properties should probably distinguish if they fire on normal interactions vs on *disabled* interactions.
252    ///
253    /// [`propagation`]: zng_app::event::AnyEventArgs::propagation
254    /// [`ENABLED`]: Interactivity::ENABLED
255    /// [`DISABLED`]: Interactivity::DISABLED
256    pub fn filter<FB, F>(self, filter_builder: FB) -> EventNodeBuilder<A, FB, M>
257    where
258        FB: FnMut() -> F + Send + 'static,
259        F: Fn(&A) -> bool + Send + Sync + 'static,
260    {
261        EventNodeBuilder {
262            event: self.event,
263            filter_builder,
264            map_args: self.map_args,
265        }
266    }
267}
268impl<T, I, M> VarEventNodeBuilder<I, (), M>
269where
270    T: VarValue,
271    I: FnMut() -> Var<T> + Send + 'static,
272{
273    /// Filter event.
274    ///
275    /// The `filter_builder` is called on init and on new, it must produce another closure, the filter predicate. The `filter_builder`
276    /// runs in the widget context, the filter predicate does not always.
277    ///
278    /// In the variable hook the filter predicate runs in the app context, it is called if the args target the widget, the predicate must
279    /// use any captured contextual info to filter the args, this is an optimization, it can save a visit to the widget node.
280    ///
281    /// If the update is received the second filter predicate is called again to confirm the update.
282    /// If it returns `true` the `handler` closure is called.
283    pub fn filter<FB, F>(self, filter_builder: FB) -> VarEventNodeBuilder<I, FB, M>
284    where
285        FB: FnMut() -> F + Send + 'static,
286        F: Fn(&T) -> bool + Send + Sync + 'static,
287    {
288        VarEventNodeBuilder {
289            init_var: self.init_var,
290            filter_builder,
291            map_args: self.map_args,
292        }
293    }
294}
295
296impl<A: EventArgs, F> EventNodeBuilder<A, F, ()> {
297    /// Convert args.
298    ///
299    /// The `map_args` closure is called in context, just before the handler is called.
300    pub fn map_args<M, MA>(self, map_args: M) -> EventNodeBuilder<A, F, M>
301    where
302        M: FnMut(&A) -> MA + Send + 'static,
303        MA: Clone + 'static,
304    {
305        EventNodeBuilder {
306            event: self.event,
307            filter_builder: self.filter_builder,
308            map_args,
309        }
310    }
311}
312impl<T, I, F> VarEventNodeBuilder<I, F, ()>
313where
314    T: VarValue,
315    I: FnMut() -> Var<T> + Send + 'static,
316{
317    /// Convert args.
318    ///
319    /// The `map_args` closure is called in context, just before the handler is called.
320    ///
321    /// Note that if the args is a full [`EventArgs`] type it must share the same propagation handle in the preview and normal route
322    /// properties, if the source type is also a full args just clone the propagation handle, otherwise you must use [`WIDGET::set_state`]
323    /// to communicate between the properties.
324    pub fn map_args<M, MA>(self, map_args: M) -> VarEventNodeBuilder<I, F, M>
325    where
326        M: FnMut(&T) -> MA + Send + 'static,
327        MA: Clone + 'static,
328    {
329        VarEventNodeBuilder {
330            init_var: self.init_var,
331            filter_builder: self.filter_builder,
332            map_args,
333        }
334    }
335}
336
337/// Build with filter and args mapping.
338impl<A, F, FB, MA, M> EventNodeBuilder<A, FB, M>
339where
340    A: EventArgs,
341    F: Fn(&A) -> bool + Send + Sync + 'static,
342    FB: FnMut() -> F + Send + 'static,
343    MA: Clone + 'static,
344    M: FnMut(&A) -> MA + Send + 'static,
345{
346    /// Build node.
347    ///
348    /// If `PRE` is `true` the handler is called before the children, *preview* route.
349    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<MA>) -> UiNode {
350        let Self {
351            event,
352            mut filter_builder,
353            mut map_args,
354        } = self;
355        let mut handler = handler.into_wgt_runner();
356        match_node(child, move |child, op| match op {
357            UiNodeOp::Init => {
358                WIDGET.sub_event_when(&event, filter_builder());
359            }
360            UiNodeOp::Deinit => {
361                handler.deinit();
362            }
363            UiNodeOp::Update { updates } => {
364                if !PRE {
365                    child.update(updates);
366                }
367
368                handler.update();
369
370                let mut f = None;
371                event.each_update(false, |args| {
372                    if f.get_or_insert_with(&mut filter_builder)(args) {
373                        handler.event(&map_args(args));
374                    }
375                });
376            }
377            _ => {}
378        })
379    }
380}
381
382/// Build with filter and args mapping.
383impl<T, I, F, FB, MA, M> VarEventNodeBuilder<I, FB, M>
384where
385    T: VarValue,
386    I: FnMut() -> Var<T> + Send + 'static,
387    F: Fn(&T) -> bool + Send + Sync + 'static,
388    FB: FnMut() -> F + Send + 'static,
389    MA: Clone + 'static,
390    M: FnMut(&T) -> MA + Send + 'static,
391{
392    /// Build node.
393    ///
394    /// If `PRE` is `true` the handler is called before the children, *preview* route.
395    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<MA>) -> UiNode {
396        let Self {
397            mut init_var,
398            mut filter_builder,
399            mut map_args,
400        } = self;
401        let mut handler = handler.into_wgt_runner();
402        let mut var = None;
403        match_node(child, move |child, op| match op {
404            UiNodeOp::Init => {
405                let v = init_var();
406                let f = filter_builder();
407                WIDGET.sub_var_when(&v, move |a| f(a.value()));
408                var = Some(v);
409            }
410            UiNodeOp::Deinit => {
411                handler.deinit();
412                var = None;
413            }
414            UiNodeOp::Update { updates } => {
415                if PRE {
416                    child.update(updates);
417                }
418
419                handler.update();
420
421                var.as_ref().unwrap().with_new(|t| {
422                    if filter_builder()(t) {
423                        handler.event(&map_args(t));
424                    }
425                });
426            }
427            _ => {}
428        })
429    }
430}
431
432/// Build with filter and without args mapping.
433impl<A, F, FB> EventNodeBuilder<A, FB, ()>
434where
435    A: EventArgs,
436    F: Fn(&A) -> bool + Send + Sync + 'static,
437    FB: FnMut() -> F + Send + 'static,
438{
439    /// Build node.
440    ///
441    /// If `PRE` is `true` the handler is called before the children, *preview* route.
442    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<A>) -> UiNode {
443        let Self {
444            event, mut filter_builder, ..
445        } = self;
446        let mut handler = handler.into_wgt_runner();
447        match_node(child, move |child, op| match op {
448            UiNodeOp::Init => {
449                WIDGET.sub_event_when(&event, filter_builder());
450            }
451            UiNodeOp::Deinit => {
452                handler.deinit();
453            }
454            UiNodeOp::Update { updates } => {
455                if !PRE {
456                    child.update(updates);
457                }
458
459                handler.update();
460
461                let mut f = None;
462                event.each_update(false, |args| {
463                    if f.get_or_insert_with(&mut filter_builder)(args) {
464                        handler.event(args);
465                    }
466                });
467            }
468            _ => {}
469        })
470    }
471}
472/// Build with filter and without args mapping.
473impl<T, I, F, FB> VarEventNodeBuilder<I, FB, ()>
474where
475    T: VarValue,
476    I: FnMut() -> Var<T> + Send + 'static,
477    F: Fn(&T) -> bool + Send + Sync + 'static,
478    FB: FnMut() -> F + Send + 'static,
479{
480    /// Build node.
481    ///
482    /// If `PRE` is `true` the handler is called before the children, *preview* route.
483    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<T>) -> UiNode {
484        let Self {
485            mut init_var,
486            mut filter_builder,
487            ..
488        } = self;
489        let mut handler = handler.into_wgt_runner();
490        let mut var = None;
491        match_node(child, move |child, op| match op {
492            UiNodeOp::Init => {
493                let v = init_var();
494                let f = filter_builder();
495                WIDGET.sub_var_when(&v, move |a| f(a.value()));
496                var = Some(v);
497            }
498            UiNodeOp::Deinit => {
499                handler.deinit();
500                var = None;
501            }
502            UiNodeOp::Update { updates } => {
503                if !PRE {
504                    child.update(updates);
505                }
506
507                handler.update();
508
509                var.as_ref().unwrap().with_new(|t| {
510                    if filter_builder()(t) {
511                        handler.event(t);
512                    }
513                });
514            }
515            _ => {}
516        })
517    }
518}
519
520/// Build without filter and without args mapping.
521impl<A> EventNodeBuilder<A, (), ()>
522where
523    A: EventArgs,
524{
525    /// Build node.
526    ///
527    /// If `PRE` is `true` the handler is called before the children, *preview* route.
528    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<A>) -> UiNode {
529        let Self { event, .. } = self;
530        let mut handler = handler.into_wgt_runner();
531        match_node(child, move |child, op| match op {
532            UiNodeOp::Init => {
533                WIDGET.sub_event(&event);
534            }
535            UiNodeOp::Deinit => {
536                handler.deinit();
537            }
538            UiNodeOp::Update { updates } => {
539                if !PRE {
540                    child.update(updates);
541                }
542
543                handler.update();
544
545                event.each_update(false, |args| {
546                    handler.event(args);
547                });
548            }
549            _ => {}
550        })
551    }
552}
553/// Build without filter and without args mapping.
554impl<T, I> VarEventNodeBuilder<I, (), ()>
555where
556    T: VarValue,
557    I: FnMut() -> Var<T> + Send + 'static,
558{
559    /// Build node.
560    ///
561    /// If `PRE` is `true` the handler is called before the children, *preview* route.
562    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<T>) -> UiNode {
563        let Self { mut init_var, .. } = self;
564        let mut handler = handler.into_wgt_runner();
565        let mut var = None;
566        match_node(child, move |child, op| match op {
567            UiNodeOp::Init => {
568                let v = init_var();
569                WIDGET.sub_var(&v);
570                var = Some(v);
571            }
572            UiNodeOp::Deinit => {
573                handler.deinit();
574                var = None;
575            }
576            UiNodeOp::Update { updates } => {
577                if !PRE {
578                    child.update(updates);
579                }
580
581                handler.update();
582
583                var.as_ref().unwrap().with_new(|t| {
584                    handler.event(t);
585                });
586            }
587            _ => {}
588        })
589    }
590}
591
592/// Build with no filter and args mapping.
593impl<A, MA, M> EventNodeBuilder<A, (), M>
594where
595    A: EventArgs,
596    MA: Clone + 'static,
597    M: FnMut(&A) -> MA + Send + 'static,
598{
599    /// Build node.
600    ///
601    /// If `PRE` is `true` the handler is called before the children, *preview* route.
602    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<MA>) -> UiNode {
603        self.filter(|| |_| true).build::<PRE>(child, handler)
604    }
605}
606/// Build with no filter and args mapping.
607impl<T, I, MA, M> VarEventNodeBuilder<I, (), M>
608where
609    T: VarValue,
610    I: FnMut() -> Var<T> + Send + 'static,
611    MA: Clone + 'static,
612    M: FnMut(&T) -> MA + Send + 'static,
613{
614    /// Build node.
615    ///
616    /// If `PRE` is `true` the handler is called before the children, *preview* route.
617    pub fn build<const PRE: bool>(self, child: impl IntoUiNode, handler: Handler<MA>) -> UiNode {
618        self.filter(|| |_| true).build::<PRE>(child, handler)
619    }
620}
621
622///<span data-del-macro-root></span> Declare event properties.
623///
624/// Each declaration can expand to an `on_event` and optionally an `on_pre_event`. The body can be declared using [`EventNodeBuilder`] or
625/// [`VarEventNodeBuilder`].
626///
627/// # Examples
628///
629/// ```
630/// # fn main() { }
631/// # use zng_app::{event::*, widget::{node::*, *}, handler::*};
632/// # use zng_wgt::node::*;
633/// # #[derive(Clone, Debug, PartialEq)] pub enum KeyState { Pressed }
634/// # event_args! { pub struct KeyInputArgs { pub state: KeyState, .. fn is_in_target(&self, _id: WidgetId) -> bool { true } } }
635/// # event! { pub static KEY_INPUT_EVENT: KeyInputArgs; }
636/// # struct CONTEXT;
637/// # impl CONTEXT { pub fn state(&self) -> zng_var::Var<bool> { zng_var::var(true) } }
638/// event_property! {
639///     /// Docs copied for `on_key_input` and `on_pre_key_input`.
640///     ///
641///     /// The macro also generates docs linking between the two properties.
642///     #[property(EVENT)]
643///     pub fn on_key_input<on_pre_key_input>(child: impl IntoUiNode, handler: Handler<KeyInputArgs>) -> UiNode {
644///         // Preview flag, only if the signature contains the `<on_pre...>` part,
645///         // the macro matches `const $IDENT: bool;` and expands to `const IDENT: bool = true/false;`.
646///         const PRE: bool;
647///
648///         // rest of the body can be anything the builds a node.
649///         EventNodeBuilder::new(KEY_INPUT_EVENT).build::<PRE>(child, handler)
650///     }
651///
652///     /// Another property.
653///     #[property(EVENT)]
654///     pub fn on_key_down<on_pre_key_down>(child: impl IntoUiNode, handler: Handler<KeyInputArgs>) -> UiNode {
655///         const PRE: bool;
656///         EventNodeBuilder::new(KEY_INPUT_EVENT)
657///             .filter(|| |a| a.state == KeyState::Pressed)
658///             .build::<PRE>(child, handler)
659///     }
660///
661///     /// Another, this time derived from a var source, and without the optional preview property.
662///     #[property(EVENT)]
663///     pub fn on_state(child: impl IntoUiNode, handler: Handler<bool>) -> UiNode {
664///         VarEventNodeBuilder::new(|| CONTEXT.state())
665///             .map_args(|b| !*b)
666///             .build::<false>(child, handler)
667///     }
668/// }
669/// ```
670///
671/// The example above generates five event properties.
672///
673/// # Route
674///
675/// Note that is an event property has an `on_pre_*` pair it is expected to be representing a fully routing event, with args that
676/// implement [`EventArgs`]. If the property does not have a preview pair it is expected to be a *direct* event. This is the event
677/// property pattern and is explained in the generated documentation, don't declare a non-standard pair using this macro.
678///
679/// # Commands
680///
681/// You can use [`command_property`] to declare command event properties, it also generates enabled control properties.
682#[macro_export]
683macro_rules! event_property {
684    ($(
685        $(#[$meta:meta])+
686        $vis:vis fn $on_ident:ident $(< $on_pre_ident:ident $(,)?>)? (
687            $child:ident: impl $IntoUiNode:path,
688            $handler:ident: $Handler:ty $(,)?
689        ) -> $UiNode:path {
690            $($body:tt)+
691        }
692    )+) => {$(
693       $crate::event_property_impl! {
694            $(#[$meta])+
695            $vis fn $on_ident $(< $on_pre_ident >)? ($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
696                $($body)+
697            }
698       }
699    )+};
700}
701#[doc(inline)]
702pub use event_property;
703
704#[doc(hidden)]
705#[macro_export]
706macro_rules! event_property_impl {
707    (
708        $(#[$meta:meta])+
709        $vis:vis fn $on_ident:ident < $on_pre_ident:ident > ($child:ident : impl $IntoUiNode:path, $handler:ident : $Handler:ty) -> $UiNode:path {
710            const $PRE:ident : bool;
711            $($body:tt)+
712        }
713    ) => {
714        $(#[$meta])+
715        ///
716        /// # Route
717        ///
718        /// This event property uses the normal route, that is, the `handler` is called after the children widget handlers and after the
719        #[doc = concat!("[`", stringify!($pn_pre_ident), "`](fn@", stringify!($pn_pre_ident), ")")]
720        /// handlers.
721        $vis fn $on_ident($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
722            const $PRE: bool = false;
723            $($body)+
724        }
725
726        $(#[$meta])+
727        ///
728        /// # Route
729        ///
730        /// This event property uses the preview route, that is, the `handler` is called before the children widget handlers and before the
731        #[doc = concat!("[`", stringify!($pn_ident), "`](fn@", stringify!($pn_ident), ")")]
732        /// handlers.
733        $vis fn $on_pre_ident($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
734            const $PRE: bool = true;
735            $($body)+
736        }
737    };
738
739    (
740        $(#[$meta:meta])+
741        $vis:vis fn $on_ident:ident ($child:ident : impl $IntoUiNode:path, $handler:ident : $Handler:path) -> $UiNode:path {
742            $($body:tt)+
743        }
744    ) => {
745        $(#[$meta])+
746        ///
747        /// # Route
748        ///
749        /// This event property uses a *direct* route, that is, it cannot be intercepted in parent widgets.
750        $vis fn $on_ident($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
751            $($body)+
752        }
753    };
754}
755
756///<span data-del-macro-root></span> Declare command event properties.
757///
758/// Each declaration can expand to an `on_cmd`, `on_pre_cmd` and  and optionally an `can_cmd` and `CAN_CMD_VAR`.
759///
760/// # Examples
761///
762/// ```
763/// # fn main() { }
764/// # use zng_app::{event::*, widget::{*, node::*}, handler::*};
765/// # use zng_app::var::*;
766/// # use zng_wgt::node::*;
767/// # command! {
768/// # pub static COPY_CMD;
769/// # pub static PASTE_CMD;
770/// # }
771/// command_property! {
772///     /// Property docs.
773///     #[property(EVENT)]
774///     pub fn on_paste<on_pre_paste>(child: impl IntoUiNode, handler: Handler<CommandArgs>) -> UiNode {
775///         PASTE_CMD
776///     }
777///
778///     /// Another property, with optional `can_*` contextual property.
779///     #[property(EVENT)]
780///     pub fn on_copy<on_pre_copy, can_copy>(child: impl IntoUiNode, handler: Handler<CommandArgs>) -> UiNode {
781///         COPY_CMD
782///     }
783/// }
784/// ```
785///
786/// The example above declares five properties and a context var. Note that unlike [`event_property!`] the body only defines the command,
787/// a standard node is generated.
788///
789/// # Enabled
790///
791/// An optional contextual property (`can_*`) and context var (`CAN_*_VAR`) can be generated. When defined the command handle enabled status
792/// is controlled by the contextual property. When not defined the command handle is always enabled.
793#[macro_export]
794macro_rules! command_property {
795    ($(
796        $(#[$($attr:tt)+])+
797        $vis:vis fn $on_ident:ident $(< $on_pre_ident:ident $(, $can_ident:ident)? $(,)?>)? (
798            $child:ident: impl $IntoUiNode:path,
799            $handler:ident: $Handler:ty $(,)?
800        ) -> $UiNode:path {
801            $COMMAND:path
802        }
803    )+) => {$(
804       $crate::command_property_impl! {
805            not_property {}
806            attributes {
807                $(#[$($attr)+])+
808            }
809            fn {
810                $vis fn $on_ident$(<$on_pre_ident $(, $can_ident)?>)?($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
811                    $COMMAND
812                }
813            }
814       }
815    )+};
816}
817#[doc(inline)]
818pub use command_property;
819#[doc(hidden)]
820#[macro_export]
821macro_rules! command_property_impl {
822    // found #[property $tt]
823    (
824        not_property { $($not_property:tt)* }
825        attributes {
826            #[property $property:tt]
827            $($attributes:tt)*
828        }
829        fn { $($fn:tt)+ }
830    ) => {
831        $crate::command_property_impl! {
832            property { $property }
833            attributes {
834                $($not_property)*
835                $($attributes)*
836            }
837            fn { $($fn)+ }
838        }
839    };
840    // found some other attribute
841    (
842        not_property { $($not_property:tt)* }
843        attributes {
844            #[$($some_attr:tt)*]
845            $($attributes:tt)*
846        }
847        fn { $($fn:tt)+ }
848    ) => {
849        $crate::command_property_impl! {
850            not_property {
851                $($not_property)*
852                #[$($some_attr)*]
853            }
854            attributes {
855                $($attributes)+
856            }
857            fn { $($fn)+ }
858        }
859    };
860    // did not find #[property]
861    (
862        not_property { $($not_property:tt)* }
863        attributes { }
864        fn { $($fn:tt)+ }
865    ) => {
866        compile_error!{"expected #[property(...)] attribute"}
867    };
868
869    // implement on_cmd, on_pre_cmd, can_cmd
870    (
871        property { ( $p_group:expr $(, default $p_default:tt)? $(, widget_impl $p_widget_impl:tt)? $(,)? ) }
872        attributes { $(#[$meta:meta])* }
873        fn {
874            $vis:vis fn $on_ident:ident < $on_pre_ident:ident, $can_ident:ident> (
875                $child:ident: impl $IntoUiNode:path,
876                $handler:ident: $Handler:ty
877            ) -> $UiNode:path {
878                $COMMAND:path
879            }
880        }
881    ) => {
882        $crate::node::paste! {
883            $crate::node::__macro_util::context_var! {
884                /// Defines if
885                #[doc = concat!("[`", stringify!($on_ident), "`](fn@", stringify!($on_ident), ")")]
886                /// and
887                #[doc = concat!("[`", stringify!($on_pre_ident), "`](fn@", stringify!($on_pre_ident), ")")]
888                /// command handlers are enabled in a widget and descendants.
889                ///
890                /// Use
891                #[doc = concat!("[`", stringify!($can_ident), "`](fn@", stringify!($can_ident), ")")]
892                /// to set. Is enabled by default.
893                $vis static [<$can_ident:upper _VAR>]: bool = true;
894            }
895
896            /// Defines if
897            #[doc = concat!("[`", stringify!($on_ident), "`](fn@", stringify!($on_ident), ")")]
898            /// and
899            #[doc = concat!("[`", stringify!($on_pre_ident), "`](fn@", stringify!($on_pre_ident), ")")]
900            /// command handlers are enabled in the widget and descendants.
901            ///
902            #[doc = "Sets the [`"$can_ident:upper "_VAR`]."]
903            #[$crate::node::__macro_util::property(CONTEXT, default([<$can_ident:upper _VAR>]) $(, widget_impl $p_widget_impl)? )]
904            $vis fn $can_ident(
905                child: impl $crate::node::__macro_util::IntoUiNode,
906                enabled: impl $crate::node::__macro_util::IntoVar<bool>,
907            ) -> $crate::node::__macro_util::UiNode {
908                $crate::node::with_context_var(child, self::[<$can_ident:upper _VAR>], enabled)
909            }
910
911            $crate::event_property! {
912                $(#[$meta])*
913                #[$crate::node::__macro_util::property ( $p_group $(, default $p_default)? $(, widget_impl $p_widget_impl)? )]
914                ///
915                /// # Command
916                ///
917                /// This property will subscribe to the
918                #[doc = concat!("[`", stringify!($COMMAND), "`]")]
919                /// command scoped on the widget. If set on the `Window!` root widget it will also subscribe to
920                /// the command scoped on the window.
921                ///
922                /// The command handle is enabled by default and can be disabled using the contextual property
923                #[doc = concat!("[`", stringify!($can_ident), "`](fn@", stringify!($can_ident), ")")]
924                /// .
925                $vis fn $on_ident<$on_pre_ident>($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
926                    const PRE: bool;
927                    let child = $crate::node::EventNodeBuilder::new(*$COMMAND)
928                        .filter(|| {
929                            let enabled = self::[<$can_ident:upper _VAR>].current_context();
930                            move |_| enabled.get()
931                        })
932                        .build::<PRE>($child, $handler);
933                    $crate::node::command_contextual_enabled(child, $COMMAND, [<$can_ident:upper _VAR>])
934                }
935            }
936        }
937    };
938    // implement on_cmd, on_pre_cmd
939    (
940        property { $property:tt }
941        attributes { $(#[$meta:meta])* }
942        fn {
943            $vis:vis fn $on_ident:ident< $on_pre_ident:ident> (
944                $child:ident: impl $IntoUiNode:path,
945                $handler:ident: $Handler:ty
946            ) -> $UiNode:path {
947                $COMMAND:path
948            }
949        }
950    ) => {
951        $crate::event_property! {
952            #[$crate::node::__macro_util::property $property]
953            $(#[$meta])*
954            ///
955            /// # Command
956            ///
957            /// This property will subscribe to the
958            #[doc = concat!("[`", stringify!($COMMAND), "`]")]
959            /// command scoped on the widget. If set on the `Window!` root widget it will also subscribe to
960            /// the command scoped on the window.
961            ///
962            /// The command handle is always enabled.
963            $vis fn $on_ident<$on_pre_ident>($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
964                const PRE: bool;
965                let child = $crate::node::EventNodeBuilder::new(*$COMMAND).build::<PRE>($child, $handler);
966                $crate::node::command_always_enabled(child, $COMMAND)
967            }
968        }
969    };
970    (
971        property { $property:tt }
972        attributes { $(#[$meta:meta])* }
973        fn {
974            $vis:vis fn $on_ident:ident (
975                $child:ident: impl $IntoUiNode:path,
976                $handler:ident: $Handler:ty
977            ) -> $UiNode:path {
978                $COMMAND:path
979            }
980        }
981    ) => {
982        $crate::event_property! {
983            #[$crate::node::__macro_util::property $property]
984            $(#[$meta])*
985            ///
986            /// # Command
987            ///
988            /// This property will subscribe to the
989            #[doc = concat!("[`", stringify!($COMMAND), "`]")]
990            /// command scoped on the widget. If set on the `Window!` root widget it will also subscribe to
991            /// the command scoped on the window.
992            ///
993            /// The command handle is always enabled.
994            $vis fn $on_ident($child: impl $IntoUiNode, $handler: $Handler) -> $UiNode {
995                let child = $crate::node::EventNodeBuilder::new(*$COMMAND).build::<false>($child, $handler);
996                $crate::node::command_always_enabled(child, $COMMAND)
997            }
998        }
999    };
1000}
1001
1002fn validate_cmd(cmd: Command) {
1003    if !matches!(cmd.scope(), CommandScope::App) {
1004        tracing::error!("command for command property cannot be scoped, {cmd:?} scope will be ignored");
1005    }
1006}
1007
1008#[doc(hidden)]
1009pub fn command_always_enabled(child: UiNode, cmd: Command) -> UiNode {
1010    let mut _wgt_handle = CommandHandle::dummy();
1011    let mut _win_handle = CommandHandle::dummy();
1012    match_node(child, move |_, op| match op {
1013        UiNodeOp::Init => {
1014            validate_cmd(cmd);
1015            _wgt_handle = cmd.scoped(WIDGET.id()).subscribe(true);
1016            if WIDGET.parent_id().is_none() {
1017                _win_handle = cmd.scoped(WINDOW.id()).subscribe(true);
1018            }
1019        }
1020        UiNodeOp::Deinit => {
1021            _wgt_handle = CommandHandle::dummy();
1022            _win_handle = CommandHandle::dummy();
1023        }
1024        _ => {}
1025    })
1026}
1027
1028#[doc(hidden)]
1029pub fn command_contextual_enabled(child: UiNode, cmd: Command, ctx: ContextVar<bool>) -> UiNode {
1030    let mut _handle = VarHandle::dummy();
1031    let mut _wgt_handle = CommandHandle::dummy();
1032    let mut _win_handle = CommandHandle::dummy();
1033    match_node(child, move |_, op| match op {
1034        UiNodeOp::Init => {
1035            let ctx = ctx.current_context();
1036            let handle = cmd.scoped(WIDGET.id()).subscribe(ctx.get());
1037            let win_handle = if WIDGET.parent_id().is_none() {
1038                cmd.scoped(WINDOW.id()).subscribe(ctx.get())
1039            } else {
1040                CommandHandle::dummy()
1041            };
1042            if !ctx.capabilities().is_const() {
1043                let handle = handle.enabled().clone();
1044                let win_handle = win_handle.enabled().clone();
1045                _handle = ctx.hook(move |a| {
1046                    handle.set(*a.value());
1047                    win_handle.set(*a.value());
1048                    true
1049                });
1050            }
1051            _wgt_handle = handle;
1052            _win_handle = win_handle;
1053        }
1054        UiNodeOp::Deinit => {
1055            _handle = VarHandle::dummy();
1056            _wgt_handle = CommandHandle::dummy();
1057            _win_handle = CommandHandle::dummy();
1058        }
1059        _ => {}
1060    })
1061}
1062
1063/// Logs an error if the `_var` is always read-only.
1064pub fn validate_getter_var<T: VarValue>(_var: &Var<T>) {
1065    #[cfg(debug_assertions)]
1066    if _var.capabilities().is_always_read_only() {
1067        tracing::error!(
1068            "`is_`, `has_` or `get_` property inited with read-only var in `{}`",
1069            WIDGET.trace_id()
1070        );
1071    }
1072}
1073
1074/// Helper for declaring state properties that are controlled by a variable.
1075///
1076/// On init the `state` variable is set to `source` and bound to it, you can use this to create state properties
1077/// that map from a context variable or to create composite properties that merge other state properties.
1078pub fn bind_state<T: VarValue>(child: impl IntoUiNode, source: impl IntoVar<T>, state: impl IntoVar<T>) -> UiNode {
1079    let source = source.into_var();
1080    bind_state_init(child, state, move |state| {
1081        state.set_from(&source);
1082        source.bind(state)
1083    })
1084}
1085
1086/// Helper for declaring state properties that are controlled by a variable that can only be retrieved on init.
1087///
1088/// On init the `bind` closure is called with the `state` variable, it must set and bind it.
1089pub fn bind_state_init<T>(
1090    child: impl IntoUiNode,
1091    state: impl IntoVar<T>,
1092    mut bind: impl FnMut(&Var<T>) -> VarHandle + Send + 'static,
1093) -> UiNode
1094where
1095    T: VarValue,
1096{
1097    let state = state.into_var();
1098    let mut _binding = VarHandle::dummy();
1099
1100    match_node(child, move |_, op| match op {
1101        UiNodeOp::Init => {
1102            validate_getter_var(&state);
1103            _binding = bind(&state);
1104        }
1105        UiNodeOp::Deinit => {
1106            _binding = VarHandle::dummy();
1107        }
1108        _ => {}
1109    })
1110}
1111
1112/// Helper for declaring state properties that are controlled by a variable that can only be derived from the widget info.
1113///
1114/// On info init (first update after the window info tree builds) the `bind` closure is called with the `state` variable, it must set and bind it.
1115pub fn bind_state_info<T>(
1116    child: impl IntoUiNode,
1117    state: impl IntoVar<T>,
1118    mut bind: impl FnMut(&Var<T>) -> VarHandle + Send + 'static,
1119) -> UiNode
1120where
1121    T: VarValue,
1122{
1123    let state = state.into_var();
1124    let mut _binding = VarHandle::dummy();
1125
1126    match_node(child, move |_, op| match op {
1127        UiNodeOp::Init => {
1128            let id = WINDOW.id();
1129            WIDGET.sub_event_when(&WIDGET_TREE_CHANGED_EVENT, move |a| !a.is_update && a.tree.window_id() == id);
1130        }
1131        UiNodeOp::Update { .. } => {
1132            WIDGET_TREE_CHANGED_EVENT.each_update(true, |a| {
1133                if !a.is_update && a.tree.window_id() == WINDOW.id() {
1134                    _binding = bind(&state);
1135                }
1136            });
1137        }
1138        UiNodeOp::Deinit => {
1139            _binding = VarHandle::dummy();
1140        }
1141        _ => {}
1142    })
1143}
1144
1145/// Helper for declaring state properties that are controlled by values in the widget state map.
1146///
1147/// The `predicate` closure is called with the widget state on init and every update, if the returned value changes the `state`
1148/// updates. The `deinit` closure is called on deinit to get the *reset* value.
1149pub fn widget_state_is_state(
1150    child: impl IntoUiNode,
1151    predicate: impl Fn(StateMapRef<WIDGET>) -> bool + Send + 'static,
1152    deinit: impl Fn(StateMapRef<WIDGET>) -> bool + Send + 'static,
1153    state: impl IntoVar<bool>,
1154) -> UiNode {
1155    let state = state.into_var();
1156
1157    match_node(child, move |child, op| match op {
1158        UiNodeOp::Init => {
1159            validate_getter_var(&state);
1160            child.init();
1161            let s = WIDGET.with_state(&predicate);
1162            if s != state.get() {
1163                state.set(s);
1164            }
1165        }
1166        UiNodeOp::Deinit => {
1167            child.deinit();
1168            let s = WIDGET.with_state(&deinit);
1169            if s != state.get() {
1170                state.set(s);
1171            }
1172        }
1173        UiNodeOp::Update { updates } => {
1174            child.update(updates);
1175            let s = WIDGET.with_state(&predicate);
1176            if s != state.get() {
1177                state.set(s);
1178            }
1179        }
1180        _ => {}
1181    })
1182}
1183
1184/// Helper for declaring state getter properties that are controlled by values in the widget state map.
1185///
1186/// The `get_new` closure is called with the widget state and current `state` every init and update, if it returns some value
1187/// the `state` updates. The `get_deinit` closure is called on deinit to get the *reset* value.
1188pub fn widget_state_get_state<T: VarValue>(
1189    child: impl IntoUiNode,
1190    get_new: impl Fn(StateMapRef<WIDGET>, &T) -> Option<T> + Send + 'static,
1191    get_deinit: impl Fn(StateMapRef<WIDGET>, &T) -> Option<T> + Send + 'static,
1192    state: impl IntoVar<T>,
1193) -> UiNode {
1194    let state = state.into_var();
1195    match_node(child, move |child, op| match op {
1196        UiNodeOp::Init => {
1197            validate_getter_var(&state);
1198            child.init();
1199            let new = state.with(|s| WIDGET.with_state(|w| get_new(w, s)));
1200            if let Some(new) = new {
1201                state.set(new);
1202            }
1203        }
1204        UiNodeOp::Deinit => {
1205            child.deinit();
1206
1207            let new = state.with(|s| WIDGET.with_state(|w| get_deinit(w, s)));
1208            if let Some(new) = new {
1209                state.set(new);
1210            }
1211        }
1212        UiNodeOp::Update { updates } => {
1213            child.update(updates);
1214            let new = state.with(|s| WIDGET.with_state(|w| get_new(w, s)));
1215            if let Some(new) = new {
1216                state.set(new);
1217            }
1218        }
1219        _ => {}
1220    })
1221}
1222
1223/// Transforms and clips the `content` node according with the default widget border align behavior.
1224///
1225/// Properties that *fill* the widget can wrap their fill content in this node to automatically implement
1226/// the expected interaction with the widget borders, the content will be positioned, sized and clipped according to the
1227/// widget borders, corner radius and border align.
1228pub fn fill_node(content: impl IntoUiNode) -> UiNode {
1229    let mut clip_bounds = PxSize::zero();
1230    let mut clip_corners = PxCornerRadius::zero();
1231
1232    let mut offset = PxVector::zero();
1233    let offset_key = FrameValueKey::new_unique();
1234    let mut define_frame = false;
1235
1236    match_node(content, move |child, op| match op {
1237        UiNodeOp::Init => {
1238            WIDGET.sub_var_layout(&BORDER_ALIGN_VAR);
1239            define_frame = false;
1240            offset = PxVector::zero();
1241        }
1242        UiNodeOp::Measure { desired_size, .. } => {
1243            let offsets = BORDER.inner_offsets();
1244            let align = BORDER_ALIGN_VAR.get();
1245
1246            let our_offsets = offsets * align;
1247            let size_offset = offsets - our_offsets;
1248
1249            let size_increase = PxSize::new(size_offset.horizontal(), size_offset.vertical());
1250
1251            *desired_size = LAYOUT.constraints().fill_size() + size_increase;
1252        }
1253        UiNodeOp::Layout { wl, final_size } => {
1254            // We are inside the *inner* bounds AND inside border_nodes:
1255            //
1256            // .. ( layout ( new_border/inner ( border_nodes ( FILL_NODES ( new_child_context ( new_child_layout ( ..
1257
1258            let (bounds, corners) = BORDER.fill_bounds();
1259
1260            let mut new_offset = bounds.origin.to_vector();
1261
1262            if clip_bounds != bounds.size || clip_corners != corners {
1263                clip_bounds = bounds.size;
1264                clip_corners = corners;
1265                WIDGET.render();
1266            }
1267
1268            let (_, branch_offset) = LAYOUT.with_constraints(PxConstraints2d::new_exact_size(bounds.size), || {
1269                wl.with_branch_child(|wl| child.layout(wl))
1270            });
1271            new_offset += branch_offset;
1272
1273            if offset != new_offset {
1274                offset = new_offset;
1275
1276                if define_frame {
1277                    WIDGET.render_update();
1278                } else {
1279                    define_frame = true;
1280                    WIDGET.render();
1281                }
1282            }
1283
1284            *final_size = bounds.size;
1285        }
1286        UiNodeOp::Render { frame } => {
1287            let mut render = |frame: &mut FrameBuilder| {
1288                let bounds = PxRect::from_size(clip_bounds);
1289                frame.push_clips(
1290                    |c| {
1291                        if clip_corners != PxCornerRadius::zero() {
1292                            c.push_clip_rounded_rect(bounds, clip_corners, false, false);
1293                        } else {
1294                            c.push_clip_rect(bounds, false, false);
1295                        }
1296
1297                        if let Some(inline) = WIDGET.bounds().inline() {
1298                            for r in inline.negative_space().iter() {
1299                                c.push_clip_rect(*r, true, false);
1300                            }
1301                        }
1302                    },
1303                    |f| child.render(f),
1304                );
1305            };
1306
1307            if define_frame {
1308                frame.push_reference_frame(offset_key.into(), offset_key.bind(offset.into(), false), true, false, |frame| {
1309                    render(frame);
1310                });
1311            } else {
1312                render(frame);
1313            }
1314        }
1315        UiNodeOp::RenderUpdate { update } => {
1316            if define_frame {
1317                update.with_transform(offset_key.update(offset.into(), false), false, |update| {
1318                    child.render_update(update);
1319                });
1320            } else {
1321                child.render_update(update);
1322            }
1323        }
1324        _ => {}
1325    })
1326}
1327
1328/// Creates a border node that delegates rendering to a `border_visual` and manages the `border_offsets` coordinating
1329/// with the other borders of the widget.
1330///
1331/// This node disables inline layout for the widget.
1332pub fn border_node(child: impl IntoUiNode, border_offsets: impl IntoVar<SideOffsets>, border_visual: impl IntoUiNode) -> UiNode {
1333    let offsets = border_offsets.into_var();
1334    let mut render_offsets = PxSideOffsets::zero();
1335    let mut border_rect = PxRect::zero();
1336
1337    match_node(ui_vec![child, border_visual], move |children, op| match op {
1338        UiNodeOp::Init => {
1339            WIDGET.sub_var_layout(&offsets).sub_var_render(&BORDER_OVER_VAR);
1340        }
1341        UiNodeOp::Measure { wm, desired_size } => {
1342            let offsets = offsets.layout();
1343            *desired_size = BORDER.measure_border(offsets, || {
1344                LAYOUT.with_sub_size(PxSize::new(offsets.horizontal(), offsets.vertical()), || {
1345                    children.node().with_child(0, |n| wm.measure_block(n))
1346                })
1347            });
1348            children.delegated();
1349        }
1350        UiNodeOp::Layout { wl, final_size } => {
1351            // We are inside the *inner* bounds or inside a parent border_node:
1352            //
1353            // .. ( layout ( new_border/inner ( BORDER_NODES ( fill_nodes ( new_child_context ( new_child_layout ( ..
1354            //
1355            // `wl` is targeting the child transform, child nodes are naturally inside borders, so we
1356            // need to add to the offset and take the size, fill_nodes optionally cancel this transform.
1357
1358            let offsets = offsets.layout();
1359            if render_offsets != offsets {
1360                render_offsets = offsets;
1361                WIDGET.render();
1362            }
1363
1364            let parent_offsets = BORDER.inner_offsets();
1365            let origin = PxPoint::new(parent_offsets.left, parent_offsets.top);
1366            if border_rect.origin != origin {
1367                border_rect.origin = origin;
1368                WIDGET.render();
1369            }
1370
1371            // layout child and border visual
1372            BORDER.layout_border(offsets, || {
1373                wl.translate(PxVector::new(offsets.left, offsets.top));
1374
1375                let taken_size = PxSize::new(offsets.horizontal(), offsets.vertical());
1376                border_rect.size = LAYOUT.with_sub_size(taken_size, || children.node().with_child(0, |n| n.layout(wl)));
1377
1378                // layout border visual
1379                LAYOUT.with_constraints(PxConstraints2d::new_exact_size(border_rect.size), || {
1380                    BORDER.with_border_layout(border_rect, offsets, || {
1381                        children.node().with_child(1, |n| n.layout(wl));
1382                    });
1383                });
1384            });
1385            children.delegated();
1386
1387            *final_size = border_rect.size;
1388        }
1389        UiNodeOp::Render { frame } => {
1390            if BORDER_OVER_VAR.get() {
1391                children.node().with_child(0, |c| c.render(frame));
1392                BORDER.with_border_layout(border_rect, render_offsets, || {
1393                    children.node().with_child(1, |c| c.render(frame));
1394                });
1395            } else {
1396                BORDER.with_border_layout(border_rect, render_offsets, || {
1397                    children.node().with_child(1, |c| c.render(frame));
1398                });
1399                children.node().with_child(0, |c| c.render(frame));
1400            }
1401            children.delegated();
1402        }
1403        UiNodeOp::RenderUpdate { update } => {
1404            children.node().with_child(0, |c| c.render_update(update));
1405            BORDER.with_border_layout(border_rect, render_offsets, || {
1406                children.node().with_child(1, |c| c.render_update(update));
1407            });
1408            children.delegated();
1409        }
1410        _ => {}
1411    })
1412}
1413
1414/// Helper for declaring nodes that sets a context local value.
1415///
1416/// See [`context_local!`] for more details about contextual values.
1417///
1418/// [`context_local!`]: crate::prelude::context_local
1419pub fn with_context_local<T: Any + Send + Sync + 'static>(
1420    child: impl IntoUiNode,
1421    context: &'static ContextLocal<T>,
1422    value: impl Into<T>,
1423) -> UiNode {
1424    let mut value = Some(Arc::new(value.into()));
1425
1426    match_node(child, move |child, op| {
1427        context.with_context(&mut value, || child.op(op));
1428    })
1429}
1430
1431/// Helper for declaring nodes that sets a context local value generated on init.
1432///
1433/// The method calls the `init_value` closure on init to produce a *value* var that is presented as the [`ContextLocal<T>`]
1434/// in the widget and widget descendants. The closure can be called more than once if the returned node is reinited.
1435///
1436/// Apart from the value initialization this behaves just like [`with_context_local`].
1437///
1438/// [`ContextLocal<T>`]: zng_app_context::ContextLocal
1439pub fn with_context_local_init<T: Any + Send + Sync + 'static>(
1440    child: impl IntoUiNode,
1441    context: &'static ContextLocal<T>,
1442    init_value: impl FnMut() -> T + Send + 'static,
1443) -> UiNode {
1444    with_context_local_init_impl(child.into_node(), context, init_value)
1445}
1446fn with_context_local_init_impl<T: Any + Send + Sync + 'static>(
1447    child: UiNode,
1448    context: &'static ContextLocal<T>,
1449    mut init_value: impl FnMut() -> T + Send + 'static,
1450) -> UiNode {
1451    let mut value = None;
1452
1453    match_node(child, move |child, op| {
1454        let mut is_deinit = false;
1455        match &op {
1456            UiNodeOp::Init => {
1457                value = Some(Arc::new(init_value()));
1458            }
1459            UiNodeOp::Deinit => {
1460                is_deinit = true;
1461            }
1462            _ => {}
1463        }
1464
1465        context.with_context(&mut value, || child.op(op));
1466
1467        if is_deinit {
1468            value = None;
1469        }
1470    })
1471}
1472
1473/// Helper for declaring widgets that are recontextualized to take in some of the context
1474/// of an *original* parent.
1475///
1476/// See [`LocalContext::with_context_blend`] for more details about `over`. The returned
1477/// node will delegate all node operations to inside the blend. The [`WidgetUiNode::with_context`]
1478/// will delegate to the `child` widget context, but the `ctx` is not blended for this method, only
1479/// for [`UiNodeOp`] methods.
1480///
1481/// # Warning
1482///
1483/// Properties, context vars and context locals are implemented with the assumption that all consumers have
1484/// released the context on return, that is even if the context was shared with worker threads all work was block-waited.
1485/// This node breaks this assumption, specially with `over: true` you may cause unexpected behavior if you don't consider
1486/// carefully what context is being captured and what context is being replaced.
1487///
1488/// As a general rule, only capture during init or update in [`NestGroup::CHILD`], only wrap full widgets and only place the wrapped
1489/// widget in a parent's [`NestGroup::CHILD`] for a parent that has no special expectations about the child.
1490///
1491/// As an example of things that can go wrong, if you capture during layout, the `LAYOUT` context is captured
1492/// and replaces `over` the actual layout context during all subsequent layouts in the actual parent.
1493///
1494/// # Panics
1495///
1496/// Panics during init if `ctx` is not from the same app as the init context.
1497///
1498/// [`NestGroup::CHILD`]: zng_app::widget::builder::NestGroup::CHILD
1499/// [`UiNodeOp`]: zng_app::widget::node::UiNodeOp
1500/// [`LocalContext::with_context_blend`]: zng_app_context::LocalContext::with_context_blend
1501pub fn with_context_blend(mut ctx: LocalContext, over: bool, child: impl IntoUiNode) -> UiNode {
1502    match_widget(child, move |c, op| {
1503        if let UiNodeOp::Init = op {
1504            let init_app = LocalContext::current_app();
1505            ctx.with_context_blend(over, || {
1506                let ctx_app = LocalContext::current_app();
1507                assert_eq!(init_app, ctx_app);
1508                c.op(op)
1509            });
1510        } else {
1511            ctx.with_context_blend(over, || c.op(op));
1512        }
1513    })
1514}
1515
1516/// Helper for declaring properties that set the widget state.
1517///
1518/// The state ID is set in [`WIDGET`] on init and is kept updated. On deinit it is set to the `default` value.
1519///
1520/// # Examples
1521///
1522/// ```
1523/// # fn main() -> () { }
1524/// # use zng_app::{widget::{property, node::{UiNode, IntoUiNode}, WIDGET, WidgetUpdateMode}};
1525/// # use zng_var::IntoVar;
1526/// # use zng_wgt::node::with_widget_state;
1527/// # use zng_state_map::{StateId, static_id};
1528/// #
1529/// static_id! {
1530///     pub static ref FOO_ID: StateId<u32>;
1531/// }
1532///
1533/// #[property(CONTEXT)]
1534/// pub fn foo(child: impl IntoUiNode, value: impl IntoVar<u32>) -> UiNode {
1535///     with_widget_state(child, *FOO_ID, || 0, value)
1536/// }
1537///
1538/// // after the property is used and the widget initializes:
1539///
1540/// /// Get the value from outside the widget.
1541/// fn get_foo_outer(widget: &mut UiNode) -> u32 {
1542///     if let Some(mut wgt) = widget.as_widget() {
1543///         wgt.with_context(WidgetUpdateMode::Ignore, || WIDGET.get_state(*FOO_ID))
1544///             .unwrap_or(0)
1545///     } else {
1546///         0
1547///     }
1548/// }
1549///
1550/// /// Get the value from inside the widget.
1551/// fn get_foo_inner() -> u32 {
1552///     WIDGET.get_state(*FOO_ID).unwrap_or_default()
1553/// }
1554/// ```
1555///
1556/// [`WIDGET`]: zng_app::widget::WIDGET
1557pub fn with_widget_state<U, I, T>(child: U, id: impl Into<StateId<T>>, default: I, value: impl IntoVar<T>) -> UiNode
1558where
1559    U: IntoUiNode,
1560    I: Fn() -> T + Send + 'static,
1561    T: StateValue + VarValue,
1562{
1563    with_widget_state_impl(child.into_node(), id.into(), default, value.into_var())
1564}
1565fn with_widget_state_impl<I, T>(child: UiNode, id: impl Into<StateId<T>>, default: I, value: impl IntoVar<T>) -> UiNode
1566where
1567    I: Fn() -> T + Send + 'static,
1568    T: StateValue + VarValue,
1569{
1570    let id = id.into();
1571    let value = value.into_var();
1572
1573    match_node(child, move |child, op| match op {
1574        UiNodeOp::Init => {
1575            child.init();
1576            WIDGET.sub_var(&value);
1577            WIDGET.set_state(id, value.get());
1578        }
1579        UiNodeOp::Deinit => {
1580            child.deinit();
1581            WIDGET.set_state(id, default());
1582        }
1583        UiNodeOp::Update { updates } => {
1584            child.update(updates);
1585            if let Some(v) = value.get_new() {
1586                WIDGET.set_state(id, v);
1587            }
1588        }
1589        _ => {}
1590    })
1591}
1592
1593/// Helper for declaring properties that set the widget state with a custom closure.
1594///
1595/// The `default` closure is used to init the state value, then the `modify` closure is used to modify the state using the variable value.
1596///
1597/// On deinit the `default` value is set on the state again.
1598///
1599/// See [`with_widget_state`] for more details.
1600pub fn with_widget_state_modify<U, S, V, I, M>(child: U, id: impl Into<StateId<S>>, value: impl IntoVar<V>, default: I, modify: M) -> UiNode
1601where
1602    U: IntoUiNode,
1603    S: StateValue,
1604    V: VarValue,
1605    I: Fn() -> S + Send + 'static,
1606    M: FnMut(&mut S, &V) + Send + 'static,
1607{
1608    with_widget_state_modify_impl(child.into_node(), id.into(), value.into_var(), default, modify)
1609}
1610fn with_widget_state_modify_impl<S, V, I, M>(
1611    child: UiNode,
1612    id: impl Into<StateId<S>>,
1613    value: impl IntoVar<V>,
1614    default: I,
1615    mut modify: M,
1616) -> UiNode
1617where
1618    S: StateValue,
1619    V: VarValue,
1620    I: Fn() -> S + Send + 'static,
1621    M: FnMut(&mut S, &V) + Send + 'static,
1622{
1623    let id = id.into();
1624    let value = value.into_var();
1625
1626    match_node(child, move |child, op| match op {
1627        UiNodeOp::Init => {
1628            child.init();
1629
1630            WIDGET.sub_var(&value);
1631
1632            value.with(|v| {
1633                WIDGET.with_state_mut(|mut s| {
1634                    modify(s.entry(id).or_insert_with(&default), v);
1635                })
1636            })
1637        }
1638        UiNodeOp::Deinit => {
1639            child.deinit();
1640
1641            WIDGET.set_state(id, default());
1642        }
1643        UiNodeOp::Update { updates } => {
1644            child.update(updates);
1645            value.with_new(|v| {
1646                WIDGET.with_state_mut(|mut s| {
1647                    modify(s.req_mut(id), v);
1648                })
1649            });
1650        }
1651        _ => {}
1652    })
1653}
1654
1655/// Create a node that controls interaction for all widgets inside `node`.
1656///
1657/// When the `interactive` var is `false` all descendant widgets are [`BLOCKED`].
1658///
1659/// Unlike the [`interactive`] property this does not apply to the contextual widget, only `child` and descendants.
1660///
1661/// The node works for either if the `child` is a widget or if it only contains widgets, the performance
1662/// is slightly better if the `child` is a widget.
1663///
1664/// [`interactive`]: fn@crate::interactive
1665/// [`BLOCKED`]: Interactivity::BLOCKED
1666pub fn interactive_node(child: impl IntoUiNode, interactive: impl IntoVar<bool>) -> UiNode {
1667    let interactive = interactive.into_var();
1668
1669    match_node(child, move |child, op| match op {
1670        UiNodeOp::Init => {
1671            WIDGET.sub_var_info(&interactive);
1672        }
1673        UiNodeOp::Info { info } => {
1674            if interactive.get() {
1675                child.info(info);
1676            } else if let Some(mut wgt) = child.node().as_widget() {
1677                let id = wgt.id();
1678                // child is a widget.
1679                info.push_interactivity_filter(move |args| {
1680                    if args.info.id() == id {
1681                        Interactivity::BLOCKED
1682                    } else {
1683                        Interactivity::ENABLED
1684                    }
1685                });
1686                child.info(info);
1687            } else {
1688                let block_range = info.with_children_range(|info| child.info(info));
1689                if !block_range.is_empty() {
1690                    // has child widgets.
1691
1692                    let id = WIDGET.id();
1693                    info.push_interactivity_filter(move |args| {
1694                        if let Some(parent) = args.info.parent()
1695                            && parent.id() == id
1696                        {
1697                            // check child range
1698                            for (i, item) in parent.children().enumerate() {
1699                                if item == args.info {
1700                                    return if !block_range.contains(&i) {
1701                                        Interactivity::ENABLED
1702                                    } else {
1703                                        Interactivity::BLOCKED
1704                                    };
1705                                } else if i >= block_range.end {
1706                                    break;
1707                                }
1708                            }
1709                        }
1710                        Interactivity::ENABLED
1711                    });
1712                }
1713            }
1714        }
1715        _ => {}
1716    })
1717}
1718
1719/// Helper for a property that gets the index of the widget in the parent panel.
1720///
1721/// See [`with_index_len_node`] for more details.
1722pub fn with_index_node(
1723    child: impl IntoUiNode,
1724    panel_list_id: impl Into<StateId<PanelListRange>>,
1725    mut update: impl FnMut(Option<usize>) + Send + 'static,
1726) -> UiNode {
1727    let panel_list_id = panel_list_id.into();
1728    let mut version = None;
1729    match_node(child, move |_, op| match op {
1730        UiNodeOp::Deinit => {
1731            update(None);
1732            version = None;
1733        }
1734        UiNodeOp::Update { .. } => {
1735            // parent PanelList requests updates for this widget every time there is an update.
1736            let info = WIDGET.info();
1737            if let Some(parent) = info.parent()
1738                && let Some(mut c) = PanelListRange::update(&parent, panel_list_id, &mut version)
1739            {
1740                let id = info.id();
1741                let p = c.position(|w| w.id() == id);
1742                update(p);
1743            }
1744        }
1745        _ => {}
1746    })
1747}
1748
1749/// Helper for a property that gets the reverse index of the widget in the parent panel.
1750///
1751/// See [`with_index_len_node`] for more details.
1752pub fn with_rev_index_node(
1753    child: impl IntoUiNode,
1754    panel_list_id: impl Into<StateId<PanelListRange>>,
1755    mut update: impl FnMut(Option<usize>) + Send + 'static,
1756) -> UiNode {
1757    let panel_list_id = panel_list_id.into();
1758    let mut version = None;
1759    match_node(child, move |_, op| match op {
1760        UiNodeOp::Deinit => {
1761            update(None);
1762            version = None;
1763        }
1764        UiNodeOp::Update { .. } => {
1765            let info = WIDGET.info();
1766            if let Some(parent) = info.parent()
1767                && let Some(c) = PanelListRange::update(&parent, panel_list_id, &mut version)
1768            {
1769                let id = info.id();
1770                let p = c.rev().position(|w| w.id() == id);
1771                update(p);
1772            }
1773        }
1774        _ => {}
1775    })
1776}
1777
1778/// Helper for a property that gets the index of the widget in the parent panel and the number of children.
1779///  
1780/// Panels must use [`PanelList::track_info_range`] to collect the `panel_list_id`, then implement getter properties
1781/// using the methods in this module. See the `stack!` getter properties for examples.
1782///
1783/// [`PanelList::track_info_range`]: zng_app::widget::node::PanelList::track_info_range
1784pub fn with_index_len_node(
1785    child: impl IntoUiNode,
1786    panel_list_id: impl Into<StateId<PanelListRange>>,
1787    mut update: impl FnMut(Option<(usize, usize)>) + Send + 'static,
1788) -> UiNode {
1789    let panel_list_id = panel_list_id.into();
1790    let mut version = None;
1791    match_node(child, move |_, op| match op {
1792        UiNodeOp::Deinit => {
1793            update(None);
1794            version = None;
1795        }
1796        UiNodeOp::Update { .. } => {
1797            let info = WIDGET.info();
1798            if let Some(parent) = info.parent()
1799                && let Some(mut iter) = PanelListRange::update(&parent, panel_list_id, &mut version)
1800            {
1801                let id = info.id();
1802                let mut p = 0;
1803                let mut count = 0;
1804                for c in &mut iter {
1805                    if c.id() == id {
1806                        p = count;
1807                        count += 1 + iter.count();
1808                        break;
1809                    } else {
1810                        count += 1;
1811                    }
1812                }
1813                update(Some((p, count)));
1814            }
1815        }
1816        _ => {}
1817    })
1818}
1819
1820/// Node that presents `data` using `wgt_fn`.
1821///
1822/// The node's child is always the result of `wgt_fn` called for the `data` value, it is reinited every time
1823/// either variable changes. If the child is an widget the node becomes it. If the child is a list the presenter
1824/// node does not become a list.
1825///
1826/// See also [`presenter_opt`] for a presenter that is nil with the data is `None`.
1827///
1828/// See also the [`present`](VarPresent::present) method that can be called on the `data`` variable and [`present_data`](VarPresentData::present_data)
1829/// that can be called on the `wgt_fn` variable.
1830///
1831/// See [`list_presenter_from_node`] to generate node lists from data.
1832pub fn presenter<D: VarValue>(data: impl IntoVar<D>, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
1833    Presenter {
1834        data: data.into_var(),
1835        wgt_fn: wgt_fn.into_var(),
1836        child: UiNode::nil(),
1837    }
1838    .into_node()
1839}
1840
1841/// Node that presents `data` using `wgt_fn` if data is available, otherwise presents nil.
1842///
1843/// This behaves like [`presenter`], but `wgt_fn` is not called if `data` is `None`.
1844///
1845/// See also the [`present_opt`](VarPresentOpt::present_opt) method that can be called on the data variable.
1846pub fn presenter_opt<D: VarValue>(data: impl IntoVar<Option<D>>, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
1847    presenter(
1848        data,
1849        wgt_fn.into_var().map(|w_fn| {
1850            crate::wgt_fn!(w_fn, |d| match d {
1851                Some(d) => w_fn(d),
1852                None => UiNode::nil(),
1853            })
1854        }),
1855    )
1856}
1857
1858/// Node list that presents `list` using `item_fn` for each new list item.
1859///
1860/// The node's children is the list mapped to node items, it is kept in sync, any list update is propagated to the node list.
1861///
1862/// See also the [`present_list`](VarPresentList::present_list) method that can be called on the list variable.
1863pub fn list_presenter<D: VarValue>(list: impl IntoVar<ObservableVec<D>>, item_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
1864    ListPresenter {
1865        list: list.into_var(),
1866        item_fn: item_fn.into_var(),
1867        view: ui_vec![],
1868    }
1869    .into_node()
1870}
1871
1872/// Node list that presents `list` using `item_fn` for each list item.
1873///
1874/// The node's children are **regenerated** for each change in `list`, if possible prefer using [`ObservableVec`] with [`list_presenter`].
1875///
1876/// See also the [`present_list_from_iter`](VarPresentListFromIter::present_list_from_iter) method that can be called on the list variable.
1877pub fn list_presenter_from_iter<D, L>(list: impl IntoVar<L>, item_fn: impl IntoVar<WidgetFn<D>>) -> UiNode
1878where
1879    D: VarValue,
1880    L: IntoIterator<Item = D> + VarValue,
1881{
1882    ListPresenterFromIter {
1883        list: list.into_var(),
1884        item_fn: item_fn.into_var(),
1885        view: ui_vec![],
1886    }
1887    .into_node()
1888}
1889
1890/// Node list that presents `list` using `list_fn` to generate the list node.
1891///
1892/// See also [`present_list_from_node`](VarPresentListFromNode::present_list_from_node) method that can be called on the list variable.
1893pub fn list_presenter_from_node<D>(list: impl IntoVar<D>, list_fn: impl IntoVar<WidgetFn<D>>) -> UiNode
1894where
1895    D: VarValue,
1896{
1897    Presenter {
1898        data: list.into_var(),
1899        wgt_fn: list_fn.into_var(),
1900        child: ui_vec![].into_node(),
1901    }
1902    .into_node()
1903}
1904
1905struct Presenter<D>
1906where
1907    D: VarValue,
1908{
1909    data: Var<D>,
1910    wgt_fn: Var<WidgetFn<D>>,
1911    child: UiNode,
1912}
1913impl<D> Presenter<D>
1914where
1915    D: VarValue,
1916{
1917    fn on_update(&mut self) -> bool {
1918        if self.data.is_new() || self.wgt_fn.is_new() {
1919            let was_list = self.child.is_list();
1920
1921            self.child.deinit();
1922
1923            let new_child = self.wgt_fn.get()(self.data.get());
1924            if was_list {
1925                if !new_child.is_list() {
1926                    #[cfg(debug_assertions)]
1927                    tracing::warn!("presenter changed to !is_list, will convert to list");
1928                }
1929                self.child = new_child.into_list();
1930            } else {
1931                #[cfg(debug_assertions)]
1932                if self.child.is_list() {
1933                    tracing::warn!("presenter changed to is_list, likely only first entry node will be used");
1934                }
1935                self.child = new_child;
1936            }
1937
1938            self.child.init();
1939            WIDGET.update_info().layout().render();
1940            true
1941        } else {
1942            false
1943        }
1944    }
1945}
1946impl<D> UiNodeImpl for Presenter<D>
1947where
1948    D: VarValue,
1949{
1950    fn children_len(&self) -> usize {
1951        self.child.children_len()
1952    }
1953
1954    fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
1955        self.child.with_child(index, visitor)
1956    }
1957
1958    fn is_list(&self) -> bool {
1959        self.child.is_list()
1960    }
1961
1962    fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
1963        self.child.as_dyn().for_each_child(visitor);
1964    }
1965
1966    fn try_for_each_child(
1967        &mut self,
1968        visitor: &mut dyn FnMut(usize, &mut UiNode) -> std::ops::ControlFlow<BoxAnyVarValue>,
1969    ) -> std::ops::ControlFlow<BoxAnyVarValue> {
1970        self.child.as_dyn().try_for_each_child(visitor)
1971    }
1972
1973    fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
1974        self.child.as_dyn().par_each_child(visitor);
1975    }
1976
1977    fn par_fold_reduce(
1978        &mut self,
1979        identity: BoxAnyVarValue,
1980        fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
1981        reduce: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
1982    ) -> BoxAnyVarValue {
1983        self.child.as_dyn().par_fold_reduce(identity, fold, reduce)
1984    }
1985
1986    fn init(&mut self) {
1987        WIDGET.sub_var(&self.data).sub_var(&self.wgt_fn);
1988        self.child = self.wgt_fn.get()(self.data.get());
1989        self.child.init();
1990    }
1991
1992    fn deinit(&mut self) {
1993        self.child.deinit();
1994        if self.child.is_list() {
1995            self.child = ui_vec![].into_node();
1996        } else {
1997            self.child = UiNode::nil();
1998        }
1999    }
2000
2001    fn info(&mut self, info: &mut zng_app::widget::info::WidgetInfoBuilder) {
2002        self.child.info(info);
2003    }
2004
2005    fn update(&mut self, updates: &WidgetUpdates) {
2006        if !self.on_update() {
2007            self.child.update(updates);
2008        }
2009    }
2010
2011    fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
2012        if self.on_update() {
2013            observer.reset();
2014        } else {
2015            self.child.as_dyn().update_list(updates, observer);
2016        }
2017    }
2018
2019    fn measure(&mut self, wm: &mut zng_app::widget::info::WidgetMeasure) -> PxSize {
2020        self.child.as_dyn().measure(wm)
2021    }
2022
2023    fn measure_list(
2024        &mut self,
2025        wm: &mut zng_app::widget::info::WidgetMeasure,
2026        measure: &(dyn Fn(usize, &mut UiNode, &mut zng_app::widget::info::WidgetMeasure) -> PxSize + Sync),
2027        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
2028    ) -> PxSize {
2029        self.child.as_dyn().measure_list(wm, measure, fold_size)
2030    }
2031
2032    fn layout(&mut self, wl: &mut zng_app::widget::info::WidgetLayout) -> PxSize {
2033        self.child.as_dyn().layout(wl)
2034    }
2035
2036    fn layout_list(
2037        &mut self,
2038        wl: &mut zng_app::widget::info::WidgetLayout,
2039        layout: &(dyn Fn(usize, &mut UiNode, &mut zng_app::widget::info::WidgetLayout) -> PxSize + Sync),
2040        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
2041    ) -> PxSize {
2042        self.child.as_dyn().layout_list(wl, layout, fold_size)
2043    }
2044
2045    fn render(&mut self, frame: &mut FrameBuilder) {
2046        self.child.as_dyn().render(frame);
2047    }
2048
2049    fn render_list(&mut self, frame: &mut FrameBuilder, render: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
2050        self.child.as_dyn().render_list(frame, render);
2051    }
2052
2053    fn render_update(&mut self, update: &mut zng_app::render::FrameUpdate) {
2054        self.child.as_dyn().render_update(update);
2055    }
2056
2057    fn render_update_list(
2058        &mut self,
2059        update: &mut zng_app::render::FrameUpdate,
2060        render_update: &(dyn Fn(usize, &mut UiNode, &mut zng_app::render::FrameUpdate) + Sync),
2061    ) {
2062        self.child.as_dyn().render_update_list(update, render_update);
2063    }
2064
2065    fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
2066        self.child.as_dyn().as_widget()
2067    }
2068}
2069
2070struct ListPresenter<D>
2071where
2072    D: VarValue,
2073{
2074    list: Var<ObservableVec<D>>,
2075    item_fn: Var<WidgetFn<D>>,
2076    view: UiVec,
2077}
2078
2079impl<D> UiNodeImpl for ListPresenter<D>
2080where
2081    D: VarValue,
2082{
2083    fn children_len(&self) -> usize {
2084        self.view.len()
2085    }
2086
2087    fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
2088        self.view.with_child(index, visitor)
2089    }
2090
2091    fn is_list(&self) -> bool {
2092        true
2093    }
2094
2095    fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
2096        self.view.for_each_child(visitor);
2097    }
2098
2099    fn try_for_each_child(
2100        &mut self,
2101        visitor: &mut dyn FnMut(usize, &mut UiNode) -> std::ops::ControlFlow<BoxAnyVarValue>,
2102    ) -> std::ops::ControlFlow<BoxAnyVarValue> {
2103        self.view.try_for_each_child(visitor)
2104    }
2105
2106    fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
2107        self.view.par_each_child(visitor);
2108    }
2109
2110    fn par_fold_reduce(
2111        &mut self,
2112        identity: BoxAnyVarValue,
2113        fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
2114        reduce: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
2115    ) -> BoxAnyVarValue {
2116        self.view.par_fold_reduce(identity, fold, reduce)
2117    }
2118
2119    fn init(&mut self) {
2120        debug_assert!(self.view.is_empty());
2121        self.view.clear();
2122
2123        WIDGET.sub_var(&self.list).sub_var(&self.item_fn);
2124
2125        let e_fn = self.item_fn.get();
2126        self.list.with(|l| {
2127            for el in l.iter() {
2128                let child = e_fn(el.clone());
2129                self.view.push(child);
2130            }
2131        });
2132
2133        self.view.init();
2134    }
2135
2136    fn deinit(&mut self) {
2137        self.view.deinit();
2138        self.view.clear();
2139    }
2140
2141    fn update(&mut self, updates: &WidgetUpdates) {
2142        self.update_list(updates, &mut ());
2143    }
2144
2145    fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
2146        let mut need_reset = self.item_fn.is_new();
2147
2148        let is_new = self
2149            .list
2150            .with_new(|l| {
2151                need_reset |= l.changes().is_empty() || l.changes() == [VecChange::Clear];
2152
2153                if need_reset {
2154                    return;
2155                }
2156
2157                // update before new items to avoid update before init.
2158                self.view.update_list(updates, observer);
2159
2160                let e_fn = self.item_fn.get();
2161
2162                for change in l.changes() {
2163                    match change {
2164                        VecChange::Insert { index, count } => {
2165                            for i in *index..(*index + count) {
2166                                let mut el = e_fn(l[i].clone());
2167                                el.init();
2168                                self.view.insert(i, el);
2169                                observer.inserted(i);
2170                            }
2171                        }
2172                        VecChange::Remove { index, count } => {
2173                            let mut count = *count;
2174                            let index = *index;
2175                            while count > 0 {
2176                                count -= 1;
2177
2178                                let mut el = self.view.remove(index);
2179                                el.deinit();
2180                                observer.removed(index);
2181                            }
2182                        }
2183                        VecChange::Move { from_index, to_index } => {
2184                            let el = self.view.remove(*from_index);
2185                            self.view.insert(*to_index, el);
2186                            observer.moved(*from_index, *to_index);
2187                        }
2188                        VecChange::Clear => unreachable!(),
2189                    }
2190                }
2191            })
2192            .is_some();
2193
2194        if !need_reset && !is_new && self.list.with(|l| l.len() != self.view.len()) {
2195            need_reset = true;
2196        }
2197
2198        if need_reset {
2199            self.view.deinit();
2200            self.view.clear();
2201
2202            let e_fn = self.item_fn.get();
2203            self.list.with(|l| {
2204                for el in l.iter() {
2205                    let child = e_fn(el.clone());
2206                    self.view.push(child);
2207                }
2208            });
2209
2210            self.view.init();
2211        } else if !is_new {
2212            self.view.update_list(updates, observer);
2213        }
2214    }
2215
2216    fn info(&mut self, info: &mut zng_app::widget::info::WidgetInfoBuilder) {
2217        self.view.info(info);
2218    }
2219
2220    fn measure(&mut self, wm: &mut zng_app::widget::info::WidgetMeasure) -> PxSize {
2221        self.view.measure(wm)
2222    }
2223
2224    fn measure_list(
2225        &mut self,
2226        wm: &mut zng_app::widget::info::WidgetMeasure,
2227        measure: &(dyn Fn(usize, &mut UiNode, &mut zng_app::widget::info::WidgetMeasure) -> PxSize + Sync),
2228        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
2229    ) -> PxSize {
2230        self.view.measure_list(wm, measure, fold_size)
2231    }
2232
2233    fn layout(&mut self, wl: &mut zng_app::widget::info::WidgetLayout) -> PxSize {
2234        self.view.layout(wl)
2235    }
2236
2237    fn layout_list(
2238        &mut self,
2239        wl: &mut zng_app::widget::info::WidgetLayout,
2240        layout: &(dyn Fn(usize, &mut UiNode, &mut zng_app::widget::info::WidgetLayout) -> PxSize + Sync),
2241        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
2242    ) -> PxSize {
2243        self.view.layout_list(wl, layout, fold_size)
2244    }
2245
2246    fn render(&mut self, frame: &mut FrameBuilder) {
2247        self.view.render(frame);
2248    }
2249
2250    fn render_list(&mut self, frame: &mut FrameBuilder, render: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
2251        self.view.render_list(frame, render);
2252    }
2253
2254    fn render_update(&mut self, update: &mut zng_app::render::FrameUpdate) {
2255        self.view.render_update(update);
2256    }
2257
2258    fn render_update_list(
2259        &mut self,
2260        update: &mut zng_app::render::FrameUpdate,
2261        render_update: &(dyn Fn(usize, &mut UiNode, &mut zng_app::render::FrameUpdate) + Sync),
2262    ) {
2263        self.view.render_update_list(update, render_update);
2264    }
2265
2266    fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
2267        None
2268    }
2269}
2270
2271struct ListPresenterFromIter<D, L>
2272where
2273    D: VarValue,
2274    L: IntoIterator<Item = D> + VarValue,
2275{
2276    list: Var<L>,
2277    item_fn: Var<WidgetFn<D>>,
2278    view: UiVec,
2279}
2280
2281impl<D, L> UiNodeImpl for ListPresenterFromIter<D, L>
2282where
2283    D: VarValue,
2284    L: IntoIterator<Item = D> + VarValue,
2285{
2286    fn children_len(&self) -> usize {
2287        self.view.len()
2288    }
2289
2290    fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
2291        self.view.with_child(index, visitor)
2292    }
2293
2294    fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
2295        self.view.for_each_child(visitor)
2296    }
2297
2298    fn try_for_each_child(
2299        &mut self,
2300        visitor: &mut dyn FnMut(usize, &mut UiNode) -> std::ops::ControlFlow<BoxAnyVarValue>,
2301    ) -> std::ops::ControlFlow<BoxAnyVarValue> {
2302        self.view.try_for_each_child(visitor)
2303    }
2304
2305    fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
2306        self.view.par_each_child(visitor);
2307    }
2308
2309    fn par_fold_reduce(
2310        &mut self,
2311        identity: BoxAnyVarValue,
2312        fold: &(dyn Fn(BoxAnyVarValue, usize, &mut UiNode) -> BoxAnyVarValue + Sync),
2313        reduce: &(dyn Fn(BoxAnyVarValue, BoxAnyVarValue) -> BoxAnyVarValue + Sync),
2314    ) -> BoxAnyVarValue {
2315        self.view.par_fold_reduce(identity, fold, reduce)
2316    }
2317
2318    fn is_list(&self) -> bool {
2319        true
2320    }
2321
2322    fn init(&mut self) {
2323        debug_assert!(self.view.is_empty());
2324        self.view.clear();
2325
2326        WIDGET.sub_var(&self.list).sub_var(&self.item_fn);
2327
2328        let e_fn = self.item_fn.get();
2329
2330        self.view.extend(self.list.get().into_iter().map(&*e_fn));
2331        self.view.init();
2332    }
2333
2334    fn deinit(&mut self) {
2335        self.view.deinit();
2336        self.view.clear();
2337    }
2338
2339    fn update(&mut self, updates: &WidgetUpdates) {
2340        self.update_list(updates, &mut ())
2341    }
2342    fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
2343        if self.list.is_new() || self.item_fn.is_new() {
2344            self.view.deinit();
2345            self.view.clear();
2346            let e_fn = self.item_fn.get();
2347            self.view.extend(self.list.get().into_iter().map(&*e_fn));
2348            self.view.init();
2349            observer.reset();
2350        } else {
2351            self.view.update_list(updates, observer);
2352        }
2353    }
2354
2355    fn info(&mut self, info: &mut zng_app::widget::info::WidgetInfoBuilder) {
2356        self.view.info(info)
2357    }
2358
2359    fn measure(&mut self, wm: &mut zng_app::widget::info::WidgetMeasure) -> PxSize {
2360        self.view.measure(wm)
2361    }
2362
2363    fn measure_list(
2364        &mut self,
2365        wm: &mut zng_app::widget::info::WidgetMeasure,
2366        measure: &(dyn Fn(usize, &mut UiNode, &mut zng_app::widget::info::WidgetMeasure) -> PxSize + Sync),
2367        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
2368    ) -> PxSize {
2369        self.view.measure_list(wm, measure, fold_size)
2370    }
2371
2372    fn layout(&mut self, wl: &mut zng_app::widget::info::WidgetLayout) -> PxSize {
2373        self.view.layout(wl)
2374    }
2375
2376    fn layout_list(
2377        &mut self,
2378        wl: &mut zng_app::widget::info::WidgetLayout,
2379        layout: &(dyn Fn(usize, &mut UiNode, &mut zng_app::widget::info::WidgetLayout) -> PxSize + Sync),
2380        fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
2381    ) -> PxSize {
2382        self.view.layout_list(wl, layout, fold_size)
2383    }
2384
2385    fn render(&mut self, frame: &mut FrameBuilder) {
2386        self.view.render(frame);
2387    }
2388
2389    fn render_list(&mut self, frame: &mut FrameBuilder, render: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
2390        self.view.render_list(frame, render);
2391    }
2392
2393    fn render_update(&mut self, update: &mut zng_app::render::FrameUpdate) {
2394        self.view.render_update(update);
2395    }
2396
2397    fn render_update_list(
2398        &mut self,
2399        update: &mut zng_app::render::FrameUpdate,
2400        render_update: &(dyn Fn(usize, &mut UiNode, &mut zng_app::render::FrameUpdate) + Sync),
2401    ) {
2402        self.view.render_update_list(update, render_update);
2403    }
2404
2405    fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
2406        None
2407    }
2408}
2409
2410/// Extension method to *convert* a variable to a node.
2411pub trait VarPresent<D: VarValue> {
2412    /// Present the variable data using a [`presenter`] node.
2413    fn present(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode;
2414}
2415impl<D: VarValue> VarPresent<D> for Var<D> {
2416    fn present(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
2417        presenter(self.clone(), wgt_fn)
2418    }
2419}
2420
2421/// Extension method to *convert* a variable to a node.
2422pub trait VarPresentOpt<D: VarValue> {
2423    /// Present the variable data using a [`presenter_opt`] node.
2424    fn present_opt(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode;
2425}
2426impl<D: VarValue> VarPresentOpt<D> for Var<Option<D>> {
2427    fn present_opt(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
2428        presenter_opt(self.clone(), wgt_fn)
2429    }
2430}
2431
2432/// Extension method fo *convert* a variable to a node list.
2433pub trait VarPresentList<D: VarValue> {
2434    /// Present the variable data using a [`list_presenter`] node list.
2435    fn present_list(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode;
2436}
2437impl<D: VarValue> VarPresentList<D> for Var<ObservableVec<D>> {
2438    fn present_list(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
2439        list_presenter(self.clone(), wgt_fn)
2440    }
2441}
2442
2443/// Extension method fo *convert* a variable to a node list.
2444pub trait VarPresentListFromIter<D: VarValue, L: IntoIterator<Item = D> + VarValue> {
2445    /// Present the variable data using a [`list_presenter_from_iter`] node list.
2446    fn present_list_from_iter(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode;
2447}
2448impl<D: VarValue, L: IntoIterator<Item = D> + VarValue> VarPresentListFromIter<D, L> for Var<L> {
2449    fn present_list_from_iter(&self, wgt_fn: impl IntoVar<WidgetFn<D>>) -> UiNode {
2450        list_presenter_from_iter(self.clone(), wgt_fn)
2451    }
2452}
2453
2454/// Extension method to *convert* a variable to a node list.
2455pub trait VarPresentListFromNode<L: VarValue> {
2456    /// Present the variable data using a [`list_presenter_from_node`] node list.
2457    fn present_list_from_node(&self, list_fn: impl IntoVar<WidgetFn<L>>) -> UiNode;
2458}
2459impl<L: VarValue> VarPresentListFromNode<L> for Var<L> {
2460    fn present_list_from_node(&self, list_fn: impl IntoVar<WidgetFn<L>>) -> UiNode {
2461        list_presenter_from_node(self.clone(), list_fn)
2462    }
2463}
2464
2465/// Extension method to *convert* a variable to a node.
2466pub trait VarPresentData<D: VarValue> {
2467    /// Present the `data` variable using a [`presenter`] node.
2468    fn present_data(&self, data: impl IntoVar<D>) -> UiNode;
2469}
2470impl<D: VarValue> VarPresentData<D> for Var<WidgetFn<D>> {
2471    fn present_data(&self, data: impl IntoVar<D>) -> UiNode {
2472        presenter(data, self.clone())
2473    }
2474}