zng_app/widget/
builder.rs

1//! Widget and property builder types.
2
3use crate::{handler::WidgetHandler, widget::node::IntoUiNode};
4use std::{
5    any::{Any, TypeId},
6    collections::{HashMap, hash_map},
7    fmt, ops,
8    sync::Arc,
9};
10
11#[doc(hidden)]
12pub use zng_var::{var_getter, var_state};
13
14///<span data-del-macro-root></span> New [`SourceLocation`] that represents the location you call this macro.
15///
16/// This value is used by widget info to mark the property and `when` block declaration source code.
17#[macro_export]
18macro_rules! source_location {
19    () => {
20        $crate::widget::builder::SourceLocation::new(std::file!(), std::line!(), std::column!())
21    };
22}
23#[doc(inline)]
24pub use crate::source_location;
25
26/// A location in source-code.
27///
28/// This value is used by widget info to mark the property and `when` block declaration source code.
29///
30/// Use [`source_location!`] to construct.
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
32#[non_exhaustive]
33pub struct SourceLocation {
34    /// [`std::file!`]
35    pub file: &'static str,
36    /// [`std::line!`]
37    pub line: u32,
38    /// [`std::column!`]
39    pub column: u32,
40}
41
42impl SourceLocation {
43    #[doc(hidden)]
44    pub fn new(file: &'static str, line: u32, column: u32) -> Self {
45        Self { file, line, column }
46    }
47}
48impl fmt::Display for SourceLocation {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        write!(f, "{}:{}:{}", self.file, self.line, self.column)
51    }
52}
53
54#[doc(hidden)]
55pub struct WgtInfo;
56impl WidgetExt for WgtInfo {
57    fn ext_property__(&mut self, _: Box<dyn PropertyArgs>) {
58        panic!("WgtInfo is for extracting info only")
59    }
60
61    fn ext_property_unset__(&mut self, _: PropertyId) {
62        panic!("WgtInfo is for extracting info only")
63    }
64}
65
66///<span data-del-macro-root></span> New [`PropertyId`] that represents the type and name.
67///
68/// # Syntax
69///
70/// * `path::property`: Gets the ID for the property function.
71/// * `Self::property`: Gets the ID for the property method on the widget.
72///
73/// # Examples
74///
75/// ```
76/// # use zng_app::{*, widget::{node::*, builder::*, property, widget}};
77/// # use zng_var::*;
78/// # pub mod path {
79/// # use super::*;
80/// # #[property(CONTEXT)]
81/// # pub fn foo(child: impl IntoUiNode, bar: impl IntoValue<bool>) -> UiNode {
82/// # child.into_node()
83/// # }
84/// # }
85/// # #[widget($crate::FooWgt)]
86/// # pub struct FooWgt(zng_app::widget::base::WidgetBase);
87/// # #[property(CONTEXT, widget_impl(FooWgt))]
88/// # pub fn bar(child: impl IntoUiNode, bar: impl IntoValue<bool>) -> UiNode {
89/// # child.into_node()
90/// # }
91/// # fn main() {
92/// let foo_id = property_id!(path::foo);
93/// let bar_id = property_id!(bar);
94///
95/// assert_ne!(foo_id, bar_id);
96/// # }
97/// ```
98#[macro_export]
99macro_rules! property_id {
100    ($($tt:tt)*) => {
101        $crate::widget::property_meta!($($tt)*).id()
102    }
103}
104#[doc(inline)]
105pub use crate::property_id;
106
107///<span data-del-macro-root></span> New [`PropertyInfo`] from property path.
108///
109/// # Syntax
110///
111/// * `path::property`: Gets the info for the property function.
112/// * `Self::property`: Gets the info for the property method on the widget.
113///
114/// # Examples
115///
116/// ```
117/// # use zng_app::{*, widget::{node::*, builder::*, property}};
118/// # use zng_var::*;
119/// # pub mod path {
120/// # use super::*;
121/// #[property(CONTEXT)]
122/// pub fn foo(child: impl IntoUiNode, bar: impl IntoValue<bool>) -> UiNode {
123///     // ..
124///     # child.into_node()
125/// }
126/// # }
127/// # fn main() {
128/// #
129///
130/// assert_eq!(property_info!(path::foo).inputs[0].name, "bar");
131/// # }
132/// ```
133#[macro_export]
134macro_rules! property_info {
135    ($($property:ident)::+ <$($generics:ty),*>) => {
136        $crate::widget::property_meta!($($property)::+).info::<$($generics),*>()
137    };
138    ($($tt:tt)*) => {
139        $crate::widget::property_meta!($($tt)*).info()
140    }
141}
142#[doc(inline)]
143pub use crate::property_info;
144
145///<span data-del-macro-root></span> Gets the strong input storage types from a property path.
146///
147/// See [`PropertyInputTypes<Tuple>`] for more details.
148///
149/// # Syntax
150///
151/// * `property::path`: Gets the input types for the property function.
152/// * `Self::property`: Gets the input types for the property method on the widget.
153#[macro_export]
154macro_rules! property_input_types {
155    ($($tt:tt)*) => {
156        $crate::widget::property_meta!($($tt)*).input_types()
157    }
158}
159#[doc(inline)]
160pub use crate::property_input_types;
161
162///<span data-del-macro-root></span> New [`Box<PropertyArgs>`](PropertyArgs) box from a property and value.
163///
164/// # Syntax
165///
166/// The syntax is similar to a property assign in a widget.
167///
168/// * `property::path = <value>;` - Args for the property function.
169/// * `property::path;` - Args for property with input of the same name, `path` here.
170///
171/// The `<value>` is the standard property init expression or named fields patterns that are used in widget assigns.
172///
173/// * `property = "value-0", "value-1";` - Unnamed args.
174/// * `property = { value_0: "value-0", value_1: "value-1" }` - Named args.
175///
176/// # Panics
177///
178/// Panics if `unset!` is used as property value.
179#[macro_export]
180macro_rules! property_args {
181    ($($property:ident)::+ = $($value:tt)*) => {
182        {
183            $crate::widget::builder::PropertyArgsGetter! {
184                $($property)::+ = $($value)*
185            }
186        }
187    };
188    ($($property:ident)::+ ::<$($generics:ty),*> = $($value:tt)*) => {
189        {
190            $crate::widget::builder::PropertyArgsGetter! {
191                $($property)::+ ::<$($generics),*> = $($value)*
192            }
193        }
194    };
195    ($property:ident $(;)?) => {
196        {
197            $crate::widget::builder::PropertyArgsGetter! {
198                $property
199            }
200        }
201    }
202}
203#[doc(inline)]
204pub use crate::property_args;
205
206///<span data-del-macro-root></span> Gets the [`WidgetType`] info of a widget.
207#[macro_export]
208macro_rules! widget_type {
209    ($($widget:ident)::+) => {
210        $($widget)::+::widget_type()
211    };
212}
213use parking_lot::Mutex;
214#[doc(inline)]
215pub use widget_type;
216use zng_app_context::context_local;
217use zng_app_proc_macros::widget;
218use zng_txt::{Txt, formatx};
219use zng_unique_id::{IdEntry, IdMap, IdSet, unique_id_32};
220use zng_var::{
221    AnyVar, AnyVarValue, AnyWhenVarBuilder, ContextInitHandle, IntoValue, IntoVar, Var, VarValue, WeakContextInitHandle, any_const_var,
222    const_var, contextual_var, impl_from_and_into_var,
223};
224
225use super::{
226    base::{WidgetBase, WidgetExt},
227    node::{ArcNode, FillUiNode, UiNode, WhenUiNodeBuilder, with_new_context_init_id},
228};
229
230#[doc(hidden)]
231#[widget($crate::widget::builder::PropertyArgsGetter)]
232pub struct PropertyArgsGetter(WidgetBase);
233impl PropertyArgsGetter {
234    pub fn widget_build(&mut self) -> Box<dyn PropertyArgs> {
235        let mut wgt = self.widget_take();
236        if !wgt.p.items.is_empty() {
237            if wgt.p.items.len() > 1 {
238                tracing::error!("properties ignored, `property_args!` only collects args for first property");
239            }
240            match wgt.p.items.remove(0).item {
241                WidgetItem::Property { args, .. } => args,
242                WidgetItem::Intrinsic { .. } => unreachable!(),
243            }
244        } else if wgt.unset.is_empty() {
245            panic!("missing property");
246        } else {
247            panic!("cannot use `unset!` in `property_args!`")
248        }
249    }
250}
251
252/// Represents the sort index of a property or intrinsic node in a widget instance.
253///
254/// Each node "wraps" the next one, so the sort defines `(context#0 (context#1 (event (size (border..)))))`.
255#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
256pub struct NestPosition {
257    /// The major position.
258    pub group: NestGroup,
259    /// Extra sorting within items of the same group.
260    pub index: u16,
261}
262impl NestPosition {
263    /// Default index used for intrinsic nodes, is `u16::MAX / 3`.
264    pub const INTRINSIC_INDEX: u16 = u16::MAX / 3;
265
266    /// Default index used for properties, is `INTRINSIC_INDEX * 2`.
267    pub const PROPERTY_INDEX: u16 = Self::INTRINSIC_INDEX * 2;
268
269    /// New position for property.
270    pub fn property(group: NestGroup) -> Self {
271        NestPosition {
272            group,
273            index: Self::PROPERTY_INDEX,
274        }
275    }
276
277    /// New position for intrinsic node.
278    pub fn intrinsic(group: NestGroup) -> Self {
279        NestPosition {
280            group,
281            index: Self::INTRINSIC_INDEX,
282        }
283    }
284}
285impl fmt::Debug for NestPosition {
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        struct IndexName(u16);
288        impl fmt::Debug for IndexName {
289            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290                match self.0 {
291                    NestPosition::INTRINSIC_INDEX => write!(f, "INTRINSIC_INDEX"),
292                    NestPosition::PROPERTY_INDEX => write!(f, "PROPERTY_INDEX"),
293                    i => write!(f, "{i}"),
294                }
295            }
296        }
297
298        f.debug_struct("NestPosition")
299            .field("group", &self.group)
300            .field("index", &IndexName(self.index))
301            .finish()
302    }
303}
304
305macro_rules! nest_group_items {
306    () => {
307        /// Minimal nest position, property is outside even context properties and is only inside the widget node.
308        ///
309        /// This is rarely used, prefer using `CONTEXT-n` if you must have a property outside the widget context.
310        pub const WIDGET: NestGroup = NestGroup(0);
311
312        /// Property defines a contextual value or variable.
313        ///
314        /// Usually these properties don't define behavior, they just configure the widget. A common pattern
315        /// is defining all widget config as context vars, that are all used by a widget intrinsic node.
316        ///
317        /// These properties are not expected to affect layout or render, if they do some errors may be logged by the default widget base.
318        pub const CONTEXT: NestGroup = NestGroup(NestGroup::NEXT_GROUP);
319        /// Property defines an event handler, or state monitor, they are placed inside all context properties, so can be configured
320        /// by context, but are still outside of the layout and render nodes.
321        ///
322        /// Event handlers can be notified before or after the inner child delegation, if handled before the event is said to be *preview*.
323        /// Implementers can use this intrinsic feature of the UI tree to interrupt notification for child properties and widgets.
324        ///
325        /// These properties are not expected to affect layout or render, if they do some errors may be logged by the default widget base.
326        pub const EVENT: NestGroup = NestGroup(NestGroup::CONTEXT.0 + NestGroup::NEXT_GROUP);
327        /// Property defines the position and size of the widget inside the space made available by the parent widget.
328        ///
329        /// These properties must accumulatively affect the measure and layout, they must avoid rendering. The computed layout is
330        /// usually rendered by the widget as a single transform, the layout properties don't need to render transforms.
331        pub const LAYOUT: NestGroup = NestGroup(NestGroup::EVENT.0 + NestGroup::NEXT_GROUP);
332
333        /// Property strongly enforces a widget size.
334        ///
335        /// Usually the widget final size is a side-effect of all the layout properties, but some properties may enforce a size, they
336        /// can use this group to ensure that they are inside the other layout properties.
337        pub const SIZE: NestGroup = NestGroup(NestGroup::LAYOUT.0 + NestGroup::NEXT_GROUP);
338
339        /// Minimal widget visual position, any property or node can render, but usually only properties inside
340        /// this position render. For example, borders will only render correctly inside this nest position.
341        ///
342        /// This is rarely used, prefer using `BORDER-n` to declare properties that are visually outside the bounds, only
343        /// use this node for intrinsics that define some inner context or service for the visual properties.
344        pub const WIDGET_INNER: NestGroup = NestGroup(NestGroup::SIZE.0 + NestGroup::NEXT_GROUP);
345
346        /// Property renders a border visual.
347        ///
348        /// Borders are strictly coordinated, see the [`border`] module for more details. All nodes of this group
349        /// may render at will, the renderer is already configured to apply the final layout and size.
350        ///
351        /// [`border`]: crate::widget::border
352        pub const BORDER: NestGroup = NestGroup(NestGroup::WIDGET_INNER.0 + NestGroup::NEXT_GROUP);
353        /// Property defines a visual of the widget.
354        ///
355        /// This is the main render group, it usually defines things like a background fill, but it can render over child nodes simply
356        /// by choosing to render after the render is delegated to the inner child.
357        pub const FILL: NestGroup = NestGroup(NestGroup::BORDER.0 + NestGroup::NEXT_GROUP);
358        /// Property defines contextual value or variable for the inner child or children widgets. Config set here does not affect
359        /// the widget where it is set, it only affects the descendants.
360        pub const CHILD_CONTEXT: NestGroup = NestGroup(NestGroup::FILL.0 + NestGroup::NEXT_GROUP);
361        /// Property defines the layout and size of the child or children widgets. These properties don't affect the layout
362        /// of the widget where they are set. Some properties are functionally the same, only changing their effect depending on their
363        /// group, the `margin` and `padding` properties are like this, `margin` is `LAYOUT` and `padding` is `CHILD_LAYOUT`.
364        pub const CHILD_LAYOUT: NestGroup = NestGroup(NestGroup::CHILD_CONTEXT.0 + NestGroup::NEXT_GROUP);
365
366        /// Maximum nest position, property is inside all others and only wraps the widget child node.
367        ///
368        /// Properties that insert child nodes may use this group, properties that only affect the child layout and want
369        /// to be inside other child layout should use `CHILD_LAYOUT+n` instead.
370        pub const CHILD: NestGroup = NestGroup(u16::MAX);
371    };
372}
373
374#[doc(hidden)]
375pub mod nest_group_items {
376    // properties import this const items in their nest group expr, unfortunately we can't import associated const items, so
377    // they are duplicated here.
378
379    use super::NestGroup;
380
381    nest_group_items!();
382}
383
384/// Property nest position group.
385///
386/// Each group has `u16::MAX / 9` in between, custom groups can be created using the +/- operations, `SIZE+1` is
387/// still outside `BORDER`, but slightly inside `SIZE`.
388///
389/// See [`NestPosition`] for more details.
390#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
391pub struct NestGroup(u16);
392impl NestGroup {
393    const NEXT_GROUP: u16 = u16::MAX / 10;
394
395    nest_group_items!();
396
397    /// All groups, from outermost([`WIDGET`]) to innermost([`CHILD`]).
398    ///
399    /// [`WIDGET`]: Self::WIDGET
400    /// [`CHILD`]: Self::CHILD
401    pub const ITEMS: [Self; 11] = [
402        Self::WIDGET,
403        Self::CONTEXT,
404        Self::EVENT,
405        Self::LAYOUT,
406        Self::SIZE,
407        Self::WIDGET_INNER,
408        Self::BORDER,
409        Self::FILL,
410        Self::CHILD_CONTEXT,
411        Self::CHILD_LAYOUT,
412        Self::CHILD,
413    ];
414
415    fn exact_name(self) -> &'static str {
416        if self.0 == Self::WIDGET.0 {
417            "WIDGET"
418        } else if self.0 == Self::CONTEXT.0 {
419            "CONTEXT"
420        } else if self.0 == Self::EVENT.0 {
421            "EVENT"
422        } else if self.0 == Self::LAYOUT.0 {
423            "LAYOUT"
424        } else if self.0 == Self::SIZE.0 {
425            "SIZE"
426        } else if self.0 == Self::WIDGET_INNER.0 {
427            "WIDGET_INNER"
428        } else if self.0 == Self::BORDER.0 {
429            "BORDER"
430        } else if self.0 == Self::FILL.0 {
431            "FILL"
432        } else if self.0 == Self::CHILD_CONTEXT.0 {
433            "CHILD_CONTEXT"
434        } else if self.0 == Self::CHILD_LAYOUT.0 {
435            "CHILD_LAYOUT"
436        } else if self.0 == Self::CHILD.0 {
437            "CHILD"
438        } else {
439            ""
440        }
441    }
442
443    /// Group name.
444    pub fn name(self) -> Txt {
445        let name = self.exact_name();
446        if name.is_empty() {
447            let closest = Self::ITEMS.into_iter().min_by_key(|i| (self.0 as i32 - i.0 as i32).abs()).unwrap();
448            let diff = self.0 as i32 - closest.0 as i32;
449
450            let name = closest.exact_name();
451            debug_assert!(!name.is_empty());
452
453            formatx!("{closest}{diff:+}")
454        } else {
455            Txt::from_static(name)
456        }
457    }
458}
459impl fmt::Debug for NestGroup {
460    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461        if f.alternate() {
462            write!(f, "NestGroup::")?;
463        }
464        write!(f, "{}", self.name())
465    }
466}
467impl fmt::Display for NestGroup {
468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        write!(f, "{}", self.name())
470    }
471}
472impl ops::Add<i16> for NestGroup {
473    type Output = Self;
474
475    fn add(self, rhs: i16) -> Self::Output {
476        let r = (self.0 as i32) + rhs as i32;
477
478        Self(r.clamp(0, u16::MAX as i32) as u16)
479    }
480}
481impl ops::Sub<i16> for NestGroup {
482    type Output = Self;
483
484    fn sub(self, rhs: i16) -> Self::Output {
485        let r = (self.0 as i32) - rhs as i32;
486
487        Self(r.clamp(0, u16::MAX as i32) as u16)
488    }
489}
490impl ops::AddAssign<i16> for NestGroup {
491    fn add_assign(&mut self, rhs: i16) {
492        *self = *self + rhs;
493    }
494}
495impl ops::SubAssign<i16> for NestGroup {
496    fn sub_assign(&mut self, rhs: i16) {
497        *self = *self - rhs;
498    }
499}
500#[test]
501fn nest_group_spacing() {
502    let mut expected = NestGroup::NEXT_GROUP;
503    for g in &NestGroup::ITEMS[1..NestGroup::ITEMS.len() - 1] {
504        assert_eq!(expected, g.0);
505        expected += NestGroup::NEXT_GROUP;
506    }
507    assert_eq!(expected, (u16::MAX / 10) * 10); // 65530
508}
509#[derive(serde::Deserialize)]
510#[serde(untagged)]
511enum NestGroupSerde<'s> {
512    Named(&'s str),
513    Unnamed(u16),
514}
515impl serde::Serialize for NestGroup {
516    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
517    where
518        S: serde::Serializer,
519    {
520        if serializer.is_human_readable() {
521            self.name().serialize(serializer)
522        } else {
523            self.0.serialize(serializer)
524        }
525    }
526}
527impl<'de> serde::Deserialize<'de> for NestGroup {
528    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
529    where
530        D: serde::Deserializer<'de>,
531    {
532        use serde::de::Error;
533
534        match NestGroupSerde::deserialize(deserializer)? {
535            NestGroupSerde::Named(n) => match n.parse() {
536                Ok(g) => Ok(g),
537                Err(e) => Err(D::Error::custom(e)),
538            },
539            NestGroupSerde::Unnamed(i) => Ok(NestGroup(i)),
540        }
541    }
542}
543impl std::str::FromStr for NestGroup {
544    type Err = String;
545
546    fn from_str(s: &str) -> Result<Self, Self::Err> {
547        let mut name = s;
548        let mut add = 0i16;
549
550        if let Some((n, a)) = s.split_once('+') {
551            add = a.parse().map_err(|e| format!("{e}"))?;
552            name = n;
553        } else if let Some((n, s)) = s.split_once('-') {
554            add = -s.parse().map_err(|e| format!("{e}"))?;
555            name = n;
556        }
557
558        match name {
559            "WIDGET" => Ok(NestGroup::WIDGET + add),
560            "CONTEXT" => Ok(NestGroup::CONTEXT + add),
561            "EVENT" => Ok(NestGroup::EVENT + add),
562            "LAYOUT" => Ok(NestGroup::LAYOUT + add),
563            "SIZE" => Ok(NestGroup::SIZE + add),
564            "BORDER" => Ok(NestGroup::BORDER + add),
565            "FILL" => Ok(NestGroup::FILL + add),
566            "CHILD_CONTEXT" => Ok(NestGroup::CHILD_CONTEXT + add),
567            "CHILD_LAYOUT" => Ok(NestGroup::CHILD_LAYOUT + add),
568            "CHILD" => Ok(NestGroup::CHILD + add),
569            ukn => Err(format!("unknown nest group {ukn:?}")),
570        }
571    }
572}
573
574/// Kind of property input.
575#[derive(PartialEq, Eq, Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
576pub enum InputKind {
577    /// Input is `impl IntoVar<T>`, build value is `Var<T>`.
578    Var,
579    /// Input is `impl IntoValue<T>`, build value is `T`.
580    Value,
581    /// Input is `impl IntoUiNode`, build value is `ArcNode`.
582    UiNode,
583    /// Input is `impl WidgetHandler<A>`, build value is `ArcWidgetHandler<A>`.
584    WidgetHandler,
585}
586
587/// Represents a [`WidgetHandler<A>`] that can be reused.
588///
589/// Note that [`hn_once!`] will still only be used once, and [`async_hn!`] tasks are bound to the specific widget
590/// context that spawned them. This `struct` is cloneable to support handler properties in styleable widgets, but the
591/// general expectation is that the handler will be used on one property instance at a time.
592///
593/// [`hn_once!`]: macro@crate::handler::hn_once
594/// [`async_hn!`]: macro@crate::handler::async_hn
595#[derive(Clone)]
596pub struct ArcWidgetHandler<A: Clone + 'static>(Arc<Mutex<dyn WidgetHandler<A>>>);
597impl<A: Clone + 'static> ArcWidgetHandler<A> {
598    /// New from `handler`.
599    pub fn new(handler: impl WidgetHandler<A>) -> Self {
600        Self(Arc::new(Mutex::new(handler)))
601    }
602}
603impl<A: Clone + 'static> WidgetHandler<A> for ArcWidgetHandler<A> {
604    #[inline(always)]
605    fn event(&mut self, args: &A) -> bool {
606        self.0.lock().event(args)
607    }
608
609    #[inline(always)]
610    fn update(&mut self) -> bool {
611        self.0.lock().update()
612    }
613}
614
615/// Represents a type erased [`ArcWidgetHandler<A>`].
616pub trait AnyArcWidgetHandler: Any {
617    /// Access to `dyn Any` methods.
618    fn as_any(&self) -> &dyn Any;
619
620    /// Access to `Box<dyn Any>` methods.
621    fn into_any(self: Box<Self>) -> Box<dyn Any>;
622
623    /// Clone the handler reference.
624    fn clone_boxed(&self) -> Box<dyn AnyArcWidgetHandler>;
625}
626impl<A: Clone + 'static> AnyArcWidgetHandler for ArcWidgetHandler<A> {
627    fn clone_boxed(&self) -> Box<dyn AnyArcWidgetHandler> {
628        Box::new(self.clone())
629    }
630
631    fn as_any(&self) -> &dyn Any {
632        self
633    }
634
635    fn into_any(self: Box<Self>) -> Box<dyn Any> {
636        self
637    }
638}
639
640/// A `when` builder for [`AnyArcWidgetHandler`] values.
641///
642/// This builder is used to generate a composite handler that redirects to active `when` matched property values.
643pub struct AnyWhenArcWidgetHandlerBuilder {
644    default: Box<dyn AnyArcWidgetHandler>,
645    conditions: Vec<(Var<bool>, Box<dyn AnyArcWidgetHandler>)>,
646}
647impl AnyWhenArcWidgetHandlerBuilder {
648    /// New from default value.
649    pub fn new(default: Box<dyn AnyArcWidgetHandler>) -> Self {
650        Self {
651            default,
652            conditions: vec![],
653        }
654    }
655
656    /// Push a conditional handler.
657    pub fn push(&mut self, condition: Var<bool>, handler: Box<dyn AnyArcWidgetHandler>) {
658        self.conditions.push((condition, handler));
659    }
660
661    /// Build the handler.
662    pub fn build<A: Clone + 'static>(self) -> ArcWidgetHandler<A> {
663        match self.default.into_any().downcast::<ArcWidgetHandler<A>>() {
664            Ok(default) => {
665                let mut conditions = Vec::with_capacity(self.conditions.len());
666                for (c, h) in self.conditions {
667                    match h.into_any().downcast::<ArcWidgetHandler<A>>() {
668                        Ok(h) => conditions.push((c, *h)),
669                        Err(_) => continue,
670                    }
671                }
672                ArcWidgetHandler::new(WhenWidgetHandler {
673                    default: *default,
674                    conditions,
675                })
676            }
677            Err(_) => panic!("unexpected build type in widget handler when builder"),
678        }
679    }
680}
681
682struct WhenWidgetHandler<A: Clone + 'static> {
683    default: ArcWidgetHandler<A>,
684    conditions: Vec<(Var<bool>, ArcWidgetHandler<A>)>,
685}
686impl<A: Clone + 'static> WidgetHandler<A> for WhenWidgetHandler<A> {
687    fn event(&mut self, args: &A) -> bool {
688        for (c, h) in &mut self.conditions {
689            if c.get() {
690                return h.event(args);
691            }
692        }
693        self.default.event(args)
694    }
695
696    fn update(&mut self) -> bool {
697        let mut pending = self.default.update();
698        for (_, h) in &mut self.conditions {
699            pending |= h.update();
700        }
701        pending
702    }
703}
704
705/// Property build actions that must be applied to property args.
706///
707/// See [`PropertyNewArgs::build_actions`] for more details.
708pub type PropertyBuildActions = Vec<Vec<Box<dyn AnyPropertyBuildAction>>>;
709
710/// Data for property build actions associated with when condition assigns.
711///
712/// See [`PropertyNewArgs::build_actions_when_data`] for more details.
713pub type PropertyBuildActionsWhenData = Vec<Vec<Option<WhenBuildActionData>>>;
714
715/// Args for [`PropertyInfo::new`] closure.
716#[non_exhaustive]
717pub struct PropertyNewArgs {
718    /// Values for each input in the same order they appear in [`PropertyInfo::inputs`], types must match
719    /// the input kind and type, the function panics if the types don't match or not all inputs are provided.
720    ///
721    /// The expected types for each [`InputKind`] are:
722    ///
723    /// | Kind                | Expected Type
724    /// |---------------------|-------------------------------------------------
725    /// | [`Var`]             | `Box<AnyVar>` or `Box<AnyWhenVarBuilder>`
726    /// | [`Value`]           | `Box<T>`
727    /// | [`UiNode`]          | `Box<ArcNode>` or `Box<WhenUiNodeBuilder>`
728    /// | [`WidgetHandler`]   | `Box<ArcWidgetHandler<A>>` or `Box<AnyWhenArcWidgetHandlerBuilder>`
729    ///
730    /// The new function will downcast and unbox the args.
731    ///
732    /// [`Var`]: InputKind::Var
733    /// [`Value`]: InputKind::Value
734    /// [`UiNode`]: InputKind::UiNode
735    /// [`WidgetHandler`]: InputKind::WidgetHandler
736    pub args: Vec<Box<dyn Any>>,
737
738    /// The property build actions can be empty or each item must contain one builder for each input in the same order they
739    /// appear in [`PropertyInfo::inputs`], the function panics if the types don't match or not all inputs are provided.
740    ///
741    /// The expected types for each [`InputKind`] are:
742    ///
743    /// | Kind                | Expected Type
744    /// |---------------------|-------------------------------------------------
745    /// | [`Var`]             | `Box<PropertyBuildAction<Var<T>>>`
746    /// | [`Value`]           | `Box<PropertyBuildAction<BoxAnyVarValue>>`
747    /// | [`UiNode`]          | `Box<PropertyBuildAction<ArcNode<BoxedUiNode>>>`
748    /// | [`WidgetHandler`]   | `Box<PropertyBuildAction<ArcWidgetHandler<A>>>`
749    ///
750    /// The new function will downcast and unbox the args.
751    ///
752    /// [`Var`]: InputKind::Var
753    /// [`Value`]: InputKind::Value
754    /// [`UiNode`]: InputKind::UiNode
755    /// [`WidgetHandler`]: InputKind::WidgetHandler
756    pub build_actions: PropertyBuildActions,
757
758    /// When build action data for each [`build_actions`].
759    ///
760    /// If not empty, each item is the [`PropertyBuildActionArgs::when_conditions_data`] for each action.
761    ///
762    /// [`build_actions`]: Self::build_actions
763    pub build_actions_when_data: PropertyBuildActionsWhenData,
764}
765
766/// Property info.
767///
768/// You can use the [`property_info!`] macro to retrieve a property's info.
769#[derive(Debug, Clone)]
770pub struct PropertyInfo {
771    /// Property nest position group.
772    pub group: NestGroup,
773    /// Property is "capture-only", no standalone implementation is provided, instantiating does not add a node, just returns the child.
774    ///
775    /// Note that all properties can be captured, but if this is `false` they provide an implementation that works standalone.
776    pub capture: bool,
777
778    /// Unique ID that identifies the property implementation.
779    pub id: PropertyId,
780    /// Property name.
781    pub name: &'static str,
782
783    /// Property declaration location.
784    pub location: SourceLocation,
785
786    /// New default property args.
787    ///
788    /// This is `Some(_)` only if the `#[property(_, default(..))]` was set in the property declaration.
789    pub default: Option<fn() -> Box<dyn PropertyArgs>>,
790
791    /// New property args from dynamically typed args.
792    ///
793    /// # Instance
794    ///
795    /// This function outputs property args, not a property node instance.
796    /// You can use [`PropertyArgs::instantiate`] on the output to generate a property node from the args. If the
797    /// property is known at compile time you can use [`property_args!`] to generate args instead, and you can just
798    /// call the property function directly to instantiate a node.
799    ///
800    pub new: fn(PropertyNewArgs) -> Box<dyn PropertyArgs>,
801
802    /// Property inputs info.
803    pub inputs: Box<[PropertyInput]>,
804
805    #[doc(hidden)] // #[property] generates instantiation in external contexts, so can't mark `#[non_exhaustive]`.
806    pub _non_exhaustive: (),
807}
808impl PropertyInfo {
809    /// Gets the index that can be used to get a named property input value in [`PropertyArgs`].
810    pub fn input_idx(&self, name: &str) -> Option<usize> {
811        self.inputs.iter().position(|i| i.name == name)
812    }
813}
814
815/// Property input info.
816#[derive(Debug, Clone)]
817pub struct PropertyInput {
818    /// Input name.
819    pub name: &'static str,
820    /// Input kind.
821    pub kind: InputKind,
822    /// Type as defined by kind.
823    pub ty: TypeId,
824    /// Type name.
825    pub ty_name: &'static str,
826
827    #[doc(hidden)] // #[property] generates instantiation in external contexts, so can't mark `#[non_exhaustive]`.
828    pub _non_exhaustive: (),
829}
830impl PropertyInput {
831    /// Shorter [`ty_name`].
832    ///
833    /// [`ty_name`]: Self::ty_name
834    pub fn display_ty_name(&self) -> Txt {
835        pretty_type_name::pretty_type_name_str(self.ty_name).into()
836    }
837}
838
839/// Represents a property instantiation request.
840pub trait PropertyArgs: Send + Sync {
841    /// Clones the arguments.
842    fn clone_boxed(&self) -> Box<dyn PropertyArgs>;
843
844    /// Property info.
845    fn property(&self) -> PropertyInfo;
846
847    /// Gets a [`InputKind::Var`].
848    fn var(&self, i: usize) -> &AnyVar {
849        panic_input(&self.property(), i, InputKind::Var)
850    }
851
852    /// Gets a [`InputKind::Value`].
853    fn value(&self, i: usize) -> &dyn AnyVarValue {
854        panic_input(&self.property(), i, InputKind::Value)
855    }
856
857    /// Gets a [`InputKind::UiNode`].
858    fn ui_node(&self, i: usize) -> &ArcNode {
859        panic_input(&self.property(), i, InputKind::UiNode)
860    }
861
862    /// Gets a [`InputKind::WidgetHandler`].
863    ///
864    /// Is a `ArcWidgetHandler<A>`.
865    fn widget_handler(&self, i: usize) -> &dyn AnyArcWidgetHandler {
866        panic_input(&self.property(), i, InputKind::WidgetHandler)
867    }
868
869    /// Create a property instance with args clone or taken.
870    ///
871    /// If the property is [`PropertyInfo::capture`] the `child` is returned.
872    fn instantiate(&self, child: UiNode) -> UiNode;
873}
874impl dyn PropertyArgs + '_ {
875    /// Unique ID.
876    pub fn id(&self) -> PropertyId {
877        self.property().id
878    }
879
880    /// Gets a strongly typed [`value`].
881    ///
882    /// Panics if the type does not match.
883    ///
884    /// [`value`]: PropertyArgs::value
885    pub fn downcast_value<T>(&self, i: usize) -> &T
886    where
887        T: VarValue,
888    {
889        self.value(i).downcast_ref::<T>().expect("cannot downcast value to type")
890    }
891    /// Gets a strongly typed [`var`].
892    ///
893    /// Panics if the variable value type does not match.
894    ///
895    /// [`var`]: PropertyArgs::var
896    pub fn downcast_var<T>(&self, i: usize) -> Var<T>
897    where
898        T: VarValue,
899    {
900        self.var(i)
901            .clone()
902            .downcast::<T>()
903            .unwrap_or_else(|_| panic!("cannot downcast var to type"))
904    }
905
906    /// Gets a strongly typed [`widget_handler`].
907    ///
908    /// Panics if the args type does not match.
909    ///
910    /// [`widget_handler`]: PropertyArgs::widget_handler
911    pub fn downcast_handler<A>(&self, i: usize) -> &ArcWidgetHandler<A>
912    where
913        A: 'static + Clone,
914    {
915        self.widget_handler(i)
916            .as_any()
917            .downcast_ref::<ArcWidgetHandler<A>>()
918            .expect("cannot downcast handler to type")
919    }
920
921    /// Gets the property input as a debug variable.
922    ///
923    /// If the input is a variable the returned variable will update with it, if not it is a static print.
924    ///
925    /// Note that you must call this in the widget context to get the correct value.
926    pub fn live_debug(&self, i: usize) -> Var<Txt> {
927        let p = self.property();
928        match p.inputs[i].kind {
929            InputKind::Var => self.var(i).map_debug(false),
930            InputKind::Value => const_var(formatx!("{:?}", self.value(i))),
931            InputKind::UiNode => const_var(Txt::from_static("UiNode")),
932            InputKind::WidgetHandler => const_var(formatx!("<impl WidgetHandler<{}>>", p.inputs[i].display_ty_name())),
933        }
934    }
935
936    /// Gets the property input current value as a debug text.
937    ///
938    /// Note that you must call this in the widget context to get the correct value.
939    pub fn debug(&self, i: usize) -> Txt {
940        let p = self.property();
941        match p.inputs[i].kind {
942            InputKind::Var => formatx!("{:?}", self.var(i).get()),
943            InputKind::Value => formatx!("{:?}", self.value(i)),
944            InputKind::UiNode => Txt::from_static("UiNode"),
945            InputKind::WidgetHandler => formatx!("<impl WidgetHandler<{}>>", p.inputs[i].display_ty_name()),
946        }
947    }
948
949    /// Call [`new`] with the same instance info and args, but with the `build_actions` and `build_actions_when_data`.
950    ///
951    /// [`new`]: PropertyInfo::new
952    pub fn new_build(
953        &self,
954        build_actions: PropertyBuildActions,
955        build_actions_when_data: PropertyBuildActionsWhenData,
956    ) -> Box<dyn PropertyArgs> {
957        let p = self.property();
958
959        let mut args: Vec<Box<dyn Any>> = Vec::with_capacity(p.inputs.len());
960        for (i, input) in p.inputs.iter().enumerate() {
961            match input.kind {
962                InputKind::Var => args.push(Box::new(self.var(i).clone())),
963                InputKind::Value => args.push(Box::new(self.value(i).clone_boxed())),
964                InputKind::UiNode => args.push(Box::new(self.ui_node(i).clone())),
965                InputKind::WidgetHandler => args.push(self.widget_handler(i).clone_boxed().into_any()),
966            }
967        }
968
969        (p.new)(PropertyNewArgs {
970            args,
971            build_actions,
972            build_actions_when_data,
973        })
974    }
975}
976
977#[doc(hidden)]
978pub fn panic_input(info: &PropertyInfo, i: usize, kind: InputKind) -> ! {
979    if i > info.inputs.len() {
980        panic!("index out of bounds, the input len is {}, but the index is {i}", info.inputs.len())
981    } else if info.inputs[i].kind != kind {
982        panic!(
983            "invalid input request `{:?}`, but `{}` is `{:?}`",
984            kind, info.inputs[i].name, info.inputs[i].kind
985        )
986    } else {
987        panic!("invalid input `{}`", info.inputs[i].name)
988    }
989}
990
991#[doc(hidden)]
992pub fn var_to_args<T: VarValue>(var: impl IntoVar<T>) -> Var<T> {
993    var.into_var()
994}
995
996#[doc(hidden)]
997pub fn value_to_args<T: VarValue>(value: impl IntoValue<T>) -> T {
998    value.into()
999}
1000
1001#[doc(hidden)]
1002pub fn ui_node_to_args(node: impl IntoUiNode) -> ArcNode {
1003    ArcNode::new(node)
1004}
1005
1006#[doc(hidden)]
1007pub fn widget_handler_to_args<A: Clone + 'static>(handler: impl WidgetHandler<A>) -> ArcWidgetHandler<A> {
1008    ArcWidgetHandler::new(handler)
1009}
1010
1011#[doc(hidden)]
1012pub fn iter_input_build_actions<'a>(
1013    actions: &'a PropertyBuildActions,
1014    data: &'a PropertyBuildActionsWhenData,
1015    index: usize,
1016) -> impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])> {
1017    let mut actions = actions.iter();
1018    let mut data = data.iter();
1019
1020    std::iter::from_fn(move || {
1021        let action = &*actions.next()?[index];
1022        let data = if let Some(data) = data.next() { &data[..] } else { &[] };
1023
1024        Some((action, data))
1025    })
1026}
1027
1028fn apply_build_actions<'a, I: Any + Send>(
1029    mut item: I,
1030    mut actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1031) -> I {
1032    if let Some((action, data)) = actions.next() {
1033        let action = action
1034            .as_any()
1035            .downcast_ref::<PropertyBuildAction<I>>()
1036            .expect("property build action type did not match expected var type");
1037
1038        item = action.build(PropertyBuildActionArgs {
1039            input: item,
1040            when_conditions_data: data,
1041        });
1042    }
1043    item
1044}
1045
1046#[doc(hidden)]
1047pub fn new_dyn_var<'a, T: VarValue>(
1048    inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1049    actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1050) -> Var<T> {
1051    let item = inputs.next().expect("missing input");
1052
1053    let item = match item.downcast::<AnyWhenVarBuilder>() {
1054        Ok(builder) => builder.into_typed::<T>().build(),
1055        Err(item) => {
1056            let any = *item.downcast::<AnyVar>().expect("input did not match expected var types");
1057            any.downcast::<T>().expect("input did not match expected var types")
1058        }
1059    };
1060
1061    apply_build_actions(item, actions)
1062}
1063
1064#[doc(hidden)]
1065pub fn new_dyn_ui_node<'a>(
1066    inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1067    actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1068) -> ArcNode {
1069    let item = inputs.next().expect("missing input");
1070
1071    let item = match item.downcast::<WhenUiNodeBuilder>() {
1072        Ok(builder) => ArcNode::new(builder.build()),
1073        Err(item) => *item.downcast::<ArcNode>().expect("input did not match expected UiNode types"),
1074    };
1075
1076    apply_build_actions(item, actions)
1077}
1078
1079#[doc(hidden)]
1080pub fn new_dyn_widget_handler<'a, A: Clone + 'static>(
1081    inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1082    actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1083) -> ArcWidgetHandler<A> {
1084    let item = inputs.next().expect("missing input");
1085
1086    let item = match item.downcast::<AnyWhenArcWidgetHandlerBuilder>() {
1087        Ok(builder) => builder.build(),
1088        Err(item) => *item
1089            .downcast::<ArcWidgetHandler<A>>()
1090            .expect("input did not match expected WidgetHandler types"),
1091    };
1092
1093    apply_build_actions(item, actions)
1094}
1095
1096#[doc(hidden)]
1097pub fn new_dyn_other<'a, T: Any + Send>(
1098    inputs: &mut std::vec::IntoIter<Box<dyn Any>>,
1099    actions: impl Iterator<Item = (&'a dyn AnyPropertyBuildAction, &'a [Option<WhenBuildActionData>])>,
1100) -> T {
1101    let item = *inputs
1102        .next()
1103        .expect("missing input")
1104        .downcast::<T>()
1105        .expect("input did not match expected var type");
1106
1107    apply_build_actions(item, actions)
1108}
1109
1110/// Error value used in a reference to an [`UiNode`] property input is made in `when` expression.
1111///
1112/// Only variables and values can be referenced in `when` expression.
1113#[derive(Clone, PartialEq)]
1114pub struct UiNodeInWhenExprError;
1115impl fmt::Debug for UiNodeInWhenExprError {
1116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1117        write!(f, "{self}")
1118    }
1119}
1120impl fmt::Display for UiNodeInWhenExprError {
1121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1122        write!(f, "cannot ref `UiNode` in when expression, only var and value properties allowed")
1123    }
1124}
1125impl std::error::Error for UiNodeInWhenExprError {}
1126
1127/// Error value used in a reference to an [`WidgetHandler`] property input is made in `when` expression.
1128///
1129/// Only variables and values can be referenced in `when` expression.
1130#[derive(Clone, PartialEq)]
1131pub struct WidgetHandlerInWhenExprError;
1132impl fmt::Debug for WidgetHandlerInWhenExprError {
1133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1134        write!(f, "{self}")
1135    }
1136}
1137impl fmt::Display for WidgetHandlerInWhenExprError {
1138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1139        write!(
1140            f,
1141            "cannot ref `impl WidgetHandler<A>` in when expression, only var and value properties allowed"
1142        )
1143    }
1144}
1145impl std::error::Error for WidgetHandlerInWhenExprError {}
1146
1147/*
1148
1149 WIDGET
1150
1151*/
1152
1153/// Value that indicates the override importance of a property instance, higher overrides lower.
1154#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1155pub struct Importance(pub u32);
1156impl Importance {
1157    /// Importance of default values defined in the widget declaration.
1158    pub const WIDGET: Importance = Importance(1000);
1159    /// Importance of values defined in the widget instantiation.
1160    pub const INSTANCE: Importance = Importance(1000 * 10);
1161}
1162impl_from_and_into_var! {
1163    fn from(imp: u32) -> Importance {
1164        Importance(imp)
1165    }
1166}
1167
1168unique_id_32! {
1169    /// Unique ID of a property implementation.
1170    pub struct PropertyId;
1171}
1172zng_unique_id::impl_unique_id_bytemuck!(PropertyId);
1173impl fmt::Debug for PropertyId {
1174    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1175        f.debug_tuple("PropertyId").field(&self.get()).finish()
1176    }
1177}
1178
1179/// Unique identifier of a widget type.
1180///
1181/// Equality and hash is defined by the `type_id` only.
1182///
1183/// Widgets generated by `#[widget]` have an associated function that returns the type, `Foo::widget_type()`.
1184#[derive(Clone, Copy, Debug)]
1185#[non_exhaustive]
1186pub struct WidgetType {
1187    /// Widget type ID.
1188    pub type_id: TypeId,
1189    /// The widget public macro path.
1190    pub path: &'static str,
1191    /// Source code location.
1192    pub location: SourceLocation,
1193}
1194impl WidgetType {
1195    #[doc(hidden)]
1196    pub fn new(type_id: TypeId, path: &'static str, location: SourceLocation) -> Self {
1197        Self { type_id, path, location }
1198    }
1199
1200    /// Get the last part of the path.
1201    pub fn name(&self) -> &'static str {
1202        self.path.rsplit_once(':').map(|(_, n)| n).unwrap_or(self.path)
1203    }
1204}
1205impl PartialEq for WidgetType {
1206    fn eq(&self, other: &Self) -> bool {
1207        self.type_id == other.type_id
1208    }
1209}
1210impl Eq for WidgetType {}
1211impl std::hash::Hash for WidgetType {
1212    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1213        self.type_id.hash(state);
1214    }
1215}
1216
1217/// Represents what member and how it was accessed in a [`WhenInput`].
1218#[derive(Clone, Copy, Debug)]
1219pub enum WhenInputMember {
1220    /// Member was accessed by name.
1221    Named(&'static str),
1222    /// Member was accessed by index.
1223    Index(usize),
1224}
1225
1226/// Input var read in a `when` condition expression.
1227#[derive(Clone)]
1228pub struct WhenInput {
1229    /// Property.
1230    pub property: PropertyId,
1231    /// What member and how it was accessed for this input.
1232    pub member: WhenInputMember,
1233    /// Input var.
1234    pub var: WhenInputVar,
1235    /// Constructor that generates the default property instance.
1236    pub property_default: Option<fn() -> Box<dyn PropertyArgs>>,
1237
1238    #[doc(hidden)] // constructed by #[property] code generated in external contexts.
1239    pub _non_exhaustive: (),
1240}
1241impl fmt::Debug for WhenInput {
1242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1243        f.debug_struct("WhenInput")
1244            .field("property", &self.property)
1245            .field("member", &self.member)
1246            .finish_non_exhaustive()
1247    }
1248}
1249
1250context_local! {
1251    // ContextInitHandle used to identify the widget scope the when inputs must use
1252    static WHEN_INPUT_CONTEXT_INIT_ID: ContextInitHandle = ContextInitHandle::no_context();
1253}
1254
1255/// Represents a [`WhenInput`] variable that can be rebound.
1256#[derive(Clone)]
1257pub struct WhenInputVar {
1258    var: Arc<Mutex<Vec<(WeakContextInitHandle, AnyVar)>>>,
1259}
1260impl WhenInputVar {
1261    /// New input setter and input var.
1262    ///
1263    /// Trying to use the input var outside of the widget will panic.
1264    pub fn new<T: VarValue>() -> (Self, Var<T>) {
1265        let arc = Arc::new(Mutex::new(vec![]));
1266        (
1267            WhenInputVar { var: arc.clone() },
1268            contextual_var(move || {
1269                let mut data = arc.lock();
1270
1271                let current_id = WHEN_INPUT_CONTEXT_INIT_ID.get();
1272                let current_id = current_id.downgrade();
1273
1274                let mut r = None;
1275                data.retain(|(id, val)| {
1276                    let retain = id.is_alive();
1277                    if retain && id == &current_id {
1278                        r = Some(val.clone());
1279                    }
1280                    retain
1281                });
1282                match r {
1283                    Some(r) => r,
1284                    None => {
1285                        // value not set for this when-input in this context
1286                        if !data.is_empty() {
1287                            // has value for other contexts at least, use that to not crash
1288                            let last = data.len() - 1;
1289                            let last = &data[last];
1290                            tracing::error!(
1291                                "when input not inited for context {:?}, using value from {:?} to avoid crash",
1292                                current_id,
1293                                last.0
1294                            );
1295                            last.1.clone()
1296                        } else {
1297                            // has no value, cannot avoid crash
1298                            panic!("when input not inited for context {current_id:?}")
1299                        }
1300                    }
1301                }
1302                .downcast()
1303                .expect("incorrect when input var type")
1304            }),
1305        )
1306    }
1307
1308    fn set(&self, handle: WeakContextInitHandle, var: AnyVar) {
1309        let mut data = self.var.lock();
1310
1311        if let Some(i) = data.iter().position(|(i, _)| i == &handle) {
1312            data[i].1 = var;
1313        } else {
1314            data.push((handle, var));
1315        }
1316    }
1317}
1318
1319type WhenBuildActionData = Arc<dyn Any + Send + Sync>;
1320type WhenBuildDefaultAction = Arc<dyn Fn() -> Vec<Box<dyn AnyPropertyBuildAction>> + Send + Sync>;
1321
1322/// Data for a custom when build action associated with an [`WhenInfo`].
1323#[derive(Clone)]
1324#[non_exhaustive]
1325pub struct WhenBuildAction {
1326    /// Data for all inputs.
1327    pub data: WhenBuildActionData,
1328    /// Closure that generates the default build actions, used when the final widget has no build action instance.
1329    ///
1330    /// The closure must generate an action that behaves like it is not present and then activates when the condition data activates.
1331    ///
1332    /// If the final widget has no action and all when data for it has no default, the data is ignored.
1333    pub default_action: Option<WhenBuildDefaultAction>,
1334}
1335impl WhenBuildAction {
1336    /// New from strongly typed values.
1337    pub fn new<D, F>(data: D, default_action: F) -> Self
1338    where
1339        D: Any + Send + Sync + 'static,
1340        F: Fn() -> Vec<Box<dyn AnyPropertyBuildAction>> + Send + Sync + 'static,
1341    {
1342        Self {
1343            data: Arc::new(data),
1344            default_action: Some(Arc::new(default_action)),
1345        }
1346    }
1347
1348    /// New from data, is only used if the action is provided by another data or the widget builder.
1349    pub fn new_no_default(data: impl Any + Send + Sync + 'static) -> Self {
1350        Self {
1351            data: Arc::new(data),
1352            default_action: None,
1353        }
1354    }
1355}
1356
1357/// Represents a `when` block in a widget.
1358#[derive(Clone)]
1359#[non_exhaustive]
1360pub struct WhenInfo {
1361    /// Properties referenced in the when condition expression.
1362    ///
1363    /// They are type erased `Var<T>` instances that are *late-inited*, other variable references (`*#{var}`) are embedded in
1364    /// the build expression and cannot be modified. Note that the [`state`] sticks to the first *late-inited* vars that it uses,
1365    /// the variable only updates after clone, this cloning happens naturally when instantiating a widget more then once.
1366    ///
1367    /// [`state`]: Self::state
1368    pub inputs: Box<[WhenInput]>,
1369
1370    /// Output of the when expression.
1371    ///
1372    /// Panics if used outside of the widget context.
1373    pub state: Var<bool>,
1374
1375    /// Properties assigned in the `when` block, in the build widget they are joined with the default value and assigns
1376    /// from other `when` blocks into a single property instance set to `when_var!` inputs.
1377    pub assigns: Vec<Box<dyn PropertyArgs>>,
1378
1379    /// Data associated with the when condition in the build action.
1380    pub build_action_data: Vec<((PropertyId, &'static str), WhenBuildAction)>,
1381
1382    /// The condition expression code.
1383    pub expr: &'static str,
1384
1385    /// When declaration location.
1386    pub location: SourceLocation,
1387}
1388impl fmt::Debug for WhenInfo {
1389    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1390        struct DebugBuildActions<'a>(&'a WhenInfo);
1391        impl fmt::Debug for DebugBuildActions<'_> {
1392            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1393                f.debug_list().entries(self.0.build_action_data.iter().map(|(k, _)| k)).finish()
1394            }
1395        }
1396
1397        f.debug_struct("WhenInfo")
1398            .field("inputs", &self.inputs)
1399            .field("state", &self.state.get_debug(false))
1400            .field("assigns", &self.assigns)
1401            .field("build_action_data", &DebugBuildActions(self))
1402            .field("expr", &self.expr)
1403            .finish()
1404    }
1405}
1406impl Clone for Box<dyn PropertyArgs> {
1407    fn clone(&self) -> Self {
1408        PropertyArgs::clone_boxed(&**self)
1409    }
1410}
1411impl fmt::Debug for &dyn PropertyArgs {
1412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1413        f.debug_struct("dyn PropertyArgs")
1414            .field("property", &self.property())
1415            .finish_non_exhaustive()
1416    }
1417}
1418impl fmt::Debug for Box<dyn PropertyArgs> {
1419    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1420        f.debug_struct("dyn PropertyArgs")
1421            .field("property", &self.property())
1422            .finish_non_exhaustive()
1423    }
1424}
1425
1426#[derive(Clone)]
1427struct WidgetItemPositioned {
1428    position: NestPosition,
1429    insert_idx: u32,
1430    item: WidgetItem,
1431}
1432impl WidgetItemPositioned {
1433    fn sort_key(&self) -> (NestPosition, u32) {
1434        (self.position, self.insert_idx)
1435    }
1436}
1437
1438#[derive(Clone, Debug)]
1439struct WhenItemPositioned {
1440    importance: Importance,
1441    insert_idx: u32,
1442    when: WhenInfo,
1443}
1444impl WhenItemPositioned {
1445    fn sort_key(&self) -> (Importance, u32) {
1446        (self.importance, self.insert_idx)
1447    }
1448}
1449
1450enum WidgetItem {
1451    Property {
1452        importance: Importance,
1453        args: Box<dyn PropertyArgs>,
1454        captured: bool,
1455    },
1456    Intrinsic {
1457        name: &'static str,
1458        new: Box<dyn FnOnce(UiNode) -> UiNode + Send + Sync>,
1459    },
1460}
1461impl Clone for WidgetItem {
1462    fn clone(&self) -> Self {
1463        match self {
1464            Self::Property {
1465                importance,
1466                args,
1467                captured,
1468            } => Self::Property {
1469                importance: *importance,
1470                captured: *captured,
1471                args: args.clone(),
1472            },
1473            Self::Intrinsic { .. } => unreachable!("only WidgetBuilder clones, and it does not insert intrinsic"),
1474        }
1475    }
1476}
1477
1478// [(PropertyId, "action-key") => (Importance, Vec<{action for each input}>)]
1479type PropertyBuildActionsMap = HashMap<(PropertyId, &'static str), (Importance, Vec<Box<dyn AnyPropertyBuildAction>>)>;
1480type PropertyBuildActionsVec = Vec<((PropertyId, &'static str), (Importance, Vec<Box<dyn AnyPropertyBuildAction>>))>;
1481
1482/// Widget instance builder.
1483pub struct WidgetBuilder {
1484    widget_type: WidgetType,
1485
1486    insert_idx: u32,
1487    p: WidgetBuilderProperties,
1488    unset: HashMap<PropertyId, Importance>,
1489
1490    whens: Vec<WhenItemPositioned>,
1491    when_insert_idx: u32,
1492
1493    p_build_actions: PropertyBuildActionsMap,
1494    p_build_actions_unset: HashMap<(PropertyId, &'static str), Importance>,
1495
1496    build_actions: Vec<Arc<Mutex<dyn FnMut(&mut WidgetBuilding) + Send>>>,
1497
1498    custom_build: Option<Arc<Mutex<dyn FnMut(WidgetBuilder) -> UiNode + Send>>>,
1499}
1500impl Clone for WidgetBuilder {
1501    fn clone(&self) -> Self {
1502        Self {
1503            widget_type: self.widget_type,
1504            p: WidgetBuilderProperties { items: self.items.clone() },
1505            p_build_actions: self.p_build_actions.clone(),
1506            insert_idx: self.insert_idx,
1507            unset: self.unset.clone(),
1508            p_build_actions_unset: self.p_build_actions_unset.clone(),
1509            whens: self.whens.clone(),
1510            when_insert_idx: self.when_insert_idx,
1511            build_actions: self.build_actions.clone(),
1512            custom_build: self.custom_build.clone(),
1513        }
1514    }
1515}
1516impl fmt::Debug for WidgetBuilder {
1517    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1518        struct PropertiesDebug<'a>(&'a WidgetBuilderProperties);
1519        impl fmt::Debug for PropertiesDebug<'_> {
1520            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1521                f.debug_list().entries(self.0.properties()).finish()
1522            }
1523        }
1524        f.debug_struct("WidgetBuilder")
1525            .field("widget_type", &self.widget_type)
1526            .field("properties", &PropertiesDebug(&self.p))
1527            .field("unset", &self.unset)
1528            .field("whens", &self.whens)
1529            .field("build_actions.len", &self.build_actions.len())
1530            .field("is_custom_build", &self.is_custom_build())
1531            .finish()
1532    }
1533}
1534impl WidgetBuilder {
1535    /// New empty default.
1536    pub fn new(widget: WidgetType) -> Self {
1537        Self {
1538            widget_type: widget,
1539            p: WidgetBuilderProperties { items: Default::default() },
1540            insert_idx: 0,
1541            unset: Default::default(),
1542            whens: Default::default(),
1543            p_build_actions: Default::default(),
1544            p_build_actions_unset: Default::default(),
1545            when_insert_idx: 0,
1546            build_actions: Default::default(),
1547            custom_build: Default::default(),
1548        }
1549    }
1550
1551    /// The widget that started this builder.
1552    pub fn widget_type(&self) -> WidgetType {
1553        self.widget_type
1554    }
1555
1556    /// Insert/override a property.
1557    ///
1558    /// You can use the [`property_args!`] macro to collect args for a property.
1559    pub fn push_property(&mut self, importance: Importance, args: Box<dyn PropertyArgs>) {
1560        let pos = NestPosition::property(args.property().group);
1561        self.push_property_positioned(importance, pos, args);
1562    }
1563
1564    /// Insert property with custom nest position.
1565    pub fn push_property_positioned(&mut self, importance: Importance, position: NestPosition, args: Box<dyn PropertyArgs>) {
1566        self.push_property_positioned_impl(importance, position, args, false)
1567    }
1568    fn push_property_positioned_impl(
1569        &mut self,
1570        importance: Importance,
1571        position: NestPosition,
1572        args: Box<dyn PropertyArgs>,
1573        captured: bool,
1574    ) {
1575        let insert_idx = self.insert_idx;
1576        self.insert_idx = insert_idx.wrapping_add(1);
1577
1578        let property_id = args.id();
1579        if let Some(i) = self.p.property_index(property_id) {
1580            match &self.p.items[i].item {
1581                WidgetItem::Property { importance: imp, .. } => {
1582                    if *imp <= importance {
1583                        // override
1584                        self.p.items[i] = WidgetItemPositioned {
1585                            position,
1586                            insert_idx,
1587                            item: WidgetItem::Property {
1588                                importance,
1589                                args,
1590                                captured,
1591                            },
1592                        };
1593                    }
1594                }
1595                WidgetItem::Intrinsic { .. } => unreachable!(),
1596            }
1597        } else {
1598            if let Some(imp) = self.unset.get(&property_id)
1599                && *imp >= importance
1600            {
1601                return; // unset blocks.
1602            }
1603            self.p.items.push(WidgetItemPositioned {
1604                position,
1605                insert_idx,
1606                item: WidgetItem::Property {
1607                    importance,
1608                    args,
1609                    captured,
1610                },
1611            });
1612        }
1613    }
1614
1615    /// Insert a `when` block.
1616    pub fn push_when(&mut self, importance: Importance, mut when: WhenInfo) {
1617        let insert_idx = self.when_insert_idx;
1618        self.when_insert_idx = insert_idx.wrapping_add(1);
1619
1620        when.assigns.retain(|a| {
1621            if let Some(imp) = self.unset.get(&a.id()) {
1622                *imp < importance
1623            } else {
1624                true
1625            }
1626        });
1627
1628        if !when.assigns.is_empty() {
1629            self.whens.push(WhenItemPositioned {
1630                importance,
1631                insert_idx,
1632                when,
1633            });
1634        }
1635    }
1636
1637    /// Insert a `name = unset!;` property.
1638    pub fn push_unset(&mut self, importance: Importance, property_id: PropertyId) {
1639        let check;
1640        match self.unset.entry(property_id) {
1641            hash_map::Entry::Occupied(mut e) => {
1642                let i = e.get_mut();
1643                check = *i < importance;
1644                *i = importance;
1645            }
1646            hash_map::Entry::Vacant(e) => {
1647                check = true;
1648                e.insert(importance);
1649            }
1650        }
1651
1652        if check {
1653            if let Some(i) = self.p.property_index(property_id) {
1654                match &self.p.items[i].item {
1655                    WidgetItem::Property { importance: imp, .. } => {
1656                        if *imp <= importance {
1657                            self.p.items.swap_remove(i);
1658                        }
1659                    }
1660                    WidgetItem::Intrinsic { .. } => unreachable!(),
1661                }
1662            }
1663
1664            self.whens.retain_mut(|w| {
1665                if w.importance <= importance {
1666                    w.when.assigns.retain(|a| a.id() != property_id);
1667                    !w.when.assigns.is_empty()
1668                } else {
1669                    true
1670                }
1671            });
1672        }
1673    }
1674
1675    /// Add or override custom builder actions that are called to finalize the inputs for a property.
1676    ///
1677    /// The `importance` overrides previous build action of the same name and property. The `input_actions` vec must
1678    /// contain one action for each property input.
1679    pub fn push_property_build_action(
1680        &mut self,
1681        property_id: PropertyId,
1682        action_name: &'static str,
1683        importance: Importance,
1684        input_actions: Vec<Box<dyn AnyPropertyBuildAction>>,
1685    ) {
1686        match self.p_build_actions.entry((property_id, action_name)) {
1687            hash_map::Entry::Occupied(mut e) => {
1688                if e.get().0 < importance {
1689                    e.insert((importance, input_actions));
1690                }
1691            }
1692            hash_map::Entry::Vacant(e) => {
1693                if let Some(imp) = self.p_build_actions_unset.get(&(property_id, action_name))
1694                    && *imp >= importance
1695                {
1696                    // blocked by unset
1697                    return;
1698                }
1699                e.insert((importance, input_actions));
1700            }
1701        }
1702    }
1703
1704    /// Insert a [property build action] filter.
1705    ///
1706    /// [property build action]: Self::push_property_build_action
1707    pub fn push_unset_property_build_action(&mut self, property_id: PropertyId, action_name: &'static str, importance: Importance) {
1708        let mut check = false;
1709        match self.p_build_actions_unset.entry((property_id, action_name)) {
1710            hash_map::Entry::Occupied(mut e) => {
1711                if *e.get() < importance {
1712                    e.insert(importance);
1713                    check = true;
1714                }
1715            }
1716            hash_map::Entry::Vacant(e) => {
1717                e.insert(importance);
1718                check = true;
1719            }
1720        }
1721        if check {
1722            self.p_build_actions.retain(|_, (imp, _)| *imp > importance);
1723        }
1724    }
1725
1726    /// Remove all registered property build actions.
1727    pub fn clear_property_build_actions(&mut self) {
1728        self.p_build_actions.clear();
1729    }
1730
1731    /// Add an `action` closure that is called every time this builder or a clone of it builds a widget instance.
1732    pub fn push_build_action(&mut self, action: impl FnMut(&mut WidgetBuilding) + Send + 'static) {
1733        self.build_actions.push(Arc::new(Mutex::new(action)))
1734    }
1735
1736    /// Remove all registered build actions.
1737    pub fn clear_build_actions(&mut self) {
1738        self.build_actions.clear();
1739    }
1740
1741    /// Returns `true` if a custom build handler is registered.
1742    pub fn is_custom_build(&self) -> bool {
1743        self.custom_build.is_some()
1744    }
1745
1746    /// Set a `build` closure to run instead of [`default_build`] when [`build`] is called.
1747    ///
1748    /// Overrides the previous custom build, if any was set.
1749    ///
1750    /// [`build`]: Self::build
1751    /// [`default_build`]: Self::default_build
1752    pub fn set_custom_build(&mut self, build: impl FnMut(WidgetBuilder) -> UiNode + Send + 'static) {
1753        self.custom_build = Some(Arc::new(Mutex::new(build)));
1754    }
1755
1756    /// Remove the custom build handler, if any was set.
1757    pub fn clear_custom_build(&mut self) {
1758        self.custom_build = None;
1759    }
1760
1761    /// Apply `other` over `self`.
1762    ///
1763    /// All properties, unsets, whens, build actions and custom build of `other` are inserted in `self`,
1764    /// override importance rules apply, `other` items only replace `self` items if they have the
1765    /// same or greater importance.
1766    ///
1767    /// Note that properties of the same position index from `other` are pushed after properties of the
1768    /// same position in `self`, this means that fill properties of `other` will render *over* fill properties
1769    /// of `self`.
1770    pub fn extend(&mut self, other: WidgetBuilder) {
1771        for (id, imp) in other.unset {
1772            self.push_unset(imp, id);
1773        }
1774
1775        for ((id, name), imp) in other.p_build_actions_unset {
1776            self.push_unset_property_build_action(id, name, imp);
1777        }
1778
1779        for WidgetItemPositioned { position, item, .. } in other.p.items {
1780            match item {
1781                WidgetItem::Property {
1782                    importance,
1783                    args,
1784                    captured,
1785                } => {
1786                    self.push_property_positioned_impl(importance, position, args, captured);
1787                }
1788                WidgetItem::Intrinsic { .. } => unreachable!(),
1789            }
1790        }
1791
1792        for w in other.whens {
1793            self.push_when(w.importance, w.when);
1794        }
1795
1796        for ((id, name), (imp, action)) in other.p_build_actions {
1797            self.push_property_build_action(id, name, imp, action);
1798        }
1799
1800        for act in other.build_actions {
1801            self.build_actions.push(act);
1802        }
1803
1804        if let Some(c) = other.custom_build {
1805            self.custom_build = Some(c);
1806        }
1807    }
1808
1809    /// If any property is present in the builder.
1810    pub fn has_properties(&self) -> bool {
1811        !self.p.items.is_empty()
1812    }
1813
1814    /// If any unset filter is present in the builder.
1815    pub fn has_unsets(&self) -> bool {
1816        !self.unset.is_empty()
1817    }
1818
1819    /// If any when block is present in the builder.
1820    pub fn has_whens(&self) -> bool {
1821        !self.whens.is_empty()
1822    }
1823
1824    /// Move all `properties` to a new builder.
1825    ///
1826    /// The properties are removed from `self`, any `when` assign is also moved, properties used in [`WhenInput`] that
1827    /// affect the properties are cloned or moved into the new builder.
1828    ///
1829    /// Note that properties can depend on others in the widget contextually, this is not preserved on split-off.
1830    pub fn split_off(&mut self, properties: impl IntoIterator<Item = PropertyId>, out: &mut WidgetBuilder) {
1831        self.split_off_impl(properties.into_iter().collect(), out)
1832    }
1833    fn split_off_impl(&mut self, properties: IdSet<PropertyId>, out: &mut WidgetBuilder) {
1834        let mut found = 0;
1835
1836        // move properties
1837        let mut i = 0;
1838        while i < self.items.len() && found < properties.len() {
1839            match &self.items[i].item {
1840                WidgetItem::Property { args, .. } if properties.contains(&args.id()) => match self.items.swap_remove(i) {
1841                    WidgetItemPositioned {
1842                        position,
1843                        item: WidgetItem::Property { importance, args, .. },
1844                        ..
1845                    } => {
1846                        out.push_property_positioned(importance, position, args);
1847                        found += 1;
1848                    }
1849                    _ => unreachable!(),
1850                },
1851                _ => {
1852                    i += 1;
1853                    continue;
1854                }
1855            }
1856        }
1857
1858        i = 0;
1859        while i < self.whens.len() {
1860            // move when assigns
1861            let mut ai = 0;
1862            let mut moved_assigns = vec![];
1863            while ai < self.whens[i].when.assigns.len() {
1864                if properties.contains(&self.whens[i].when.assigns[ai].id()) {
1865                    let args = self.whens[i].when.assigns.remove(ai);
1866                    moved_assigns.push(args);
1867                } else {
1868                    ai += 1;
1869                }
1870            }
1871
1872            if !moved_assigns.is_empty() {
1873                let out_imp;
1874                let out_when;
1875                if self.whens[i].when.assigns.is_empty() {
1876                    // moved all assigns from block, move block
1877                    let WhenItemPositioned { importance, mut when, .. } = self.whens.remove(i);
1878                    when.assigns = moved_assigns;
1879
1880                    out_imp = importance;
1881                    out_when = when;
1882                } else {
1883                    // when block still used, clone block header for moved assigns.
1884                    let WhenItemPositioned { importance, when, .. } = &self.whens[i];
1885                    out_imp = *importance;
1886                    out_when = WhenInfo {
1887                        inputs: when.inputs.clone(),
1888                        state: when.state.clone(),
1889                        assigns: moved_assigns,
1890                        build_action_data: when.build_action_data.clone(),
1891                        expr: when.expr,
1892                        location: when.location,
1893                    };
1894
1895                    i += 1;
1896                };
1897
1898                // clone when input properties that are "manually" set.
1899                for input in out_when.inputs.iter() {
1900                    if let Some(i) = self.property_index(input.property) {
1901                        match &self.items[i] {
1902                            WidgetItemPositioned {
1903                                position,
1904                                item: WidgetItem::Property { importance, args, .. },
1905                                ..
1906                            } => {
1907                                out.push_property_positioned(*importance, *position, args.clone());
1908                            }
1909                            _ => unreachable!(),
1910                        }
1911                    }
1912                }
1913
1914                out.push_when(out_imp, out_when);
1915            } else {
1916                i += 1;
1917            }
1918        }
1919
1920        // move unsets
1921        for id in properties {
1922            if let Some(imp) = self.unset.remove(&id) {
1923                out.push_unset(imp, id);
1924            }
1925        }
1926    }
1927
1928    /// Instantiate the widget.
1929    ///
1930    /// If a custom build is set it is run, unless it is already running, otherwise the [`default_build`] is called.
1931    ///
1932    /// [`default_build`]: Self::default_build
1933    pub fn build(self) -> UiNode {
1934        if let Some(custom) = self.custom_build.clone() {
1935            match custom.try_lock() {
1936                Some(mut c) => c(self),
1937                None => self.default_build(),
1938            }
1939        } else {
1940            self.default_build()
1941        }
1942    }
1943
1944    /// Instantiate the widget.
1945    ///
1946    /// Runs all build actions, but ignores custom build.
1947    pub fn default_build(self) -> UiNode {
1948        #[cfg(feature = "inspector")]
1949        let builder = self.clone();
1950
1951        let mut building = WidgetBuilding {
1952            #[cfg(feature = "inspector")]
1953            builder: Some(builder),
1954            #[cfg(feature = "trace_widget")]
1955            trace_widget: true,
1956            #[cfg(feature = "trace_wgt_item")]
1957            trace_wgt_item: true,
1958
1959            widget_type: self.widget_type,
1960            p: self.p,
1961            child: None,
1962        };
1963
1964        let mut p_build_actions = self.p_build_actions.into_iter().collect();
1965
1966        let mut when_init_context_handle = None;
1967
1968        if !self.whens.is_empty() {
1969            let handle = ContextInitHandle::new();
1970            building.build_whens(self.whens, handle.downgrade(), &mut p_build_actions);
1971            when_init_context_handle = Some(handle);
1972        }
1973
1974        if !p_build_actions.is_empty() {
1975            building.build_p_actions(p_build_actions);
1976        }
1977
1978        for action in self.build_actions {
1979            (action.lock())(&mut building);
1980        }
1981
1982        building.build(when_init_context_handle)
1983    }
1984}
1985impl ops::Deref for WidgetBuilder {
1986    type Target = WidgetBuilderProperties;
1987
1988    fn deref(&self) -> &Self::Target {
1989        &self.p
1990    }
1991}
1992impl ops::DerefMut for WidgetBuilder {
1993    fn deref_mut(&mut self) -> &mut Self::Target {
1994        &mut self.p
1995    }
1996}
1997
1998/// Represents a finalizing [`WidgetBuilder`].
1999///
2000/// Widgets can register a [build action] to get access to this, it provides an opportunity
2001/// to remove or capture the final properties of a widget, after they have all been resolved and `when` assigns generated.
2002/// Build actions can also define the child node, intrinsic nodes and a custom builder.
2003///
2004/// [build action]: WidgetBuilder::push_build_action
2005pub struct WidgetBuilding {
2006    #[cfg(feature = "inspector")]
2007    builder: Option<WidgetBuilder>,
2008    #[cfg(feature = "trace_widget")]
2009    trace_widget: bool,
2010    #[cfg(feature = "trace_wgt_item")]
2011    trace_wgt_item: bool,
2012
2013    widget_type: WidgetType,
2014    p: WidgetBuilderProperties,
2015    child: Option<UiNode>,
2016}
2017impl WidgetBuilding {
2018    /// The widget that started this builder.
2019    pub fn widget_type(&self) -> WidgetType {
2020        self.widget_type
2021    }
2022
2023    /// If an innermost node is defined.
2024    ///
2025    /// If `false` by the end of build the [`FillUiNode`] is used as the innermost node.
2026    pub fn has_child(&self) -> bool {
2027        self.child.is_some()
2028    }
2029
2030    /// Set/replace the innermost node of the widget.
2031    pub fn set_child(&mut self, node: impl IntoUiNode) {
2032        self.child = Some(node.into_node());
2033    }
2034
2035    /// Don't insert the inspector node and inspector metadata on build.
2036    ///
2037    /// The inspector metadata is inserted by default when `feature="inspector"` is active.
2038    #[cfg(feature = "inspector")]
2039    pub fn disable_inspector(&mut self) {
2040        self.builder = None;
2041    }
2042
2043    /// Don't insert the widget trace node on build.
2044    ///
2045    /// The trace node is inserted by default when `feature="trace_widget"` is active.
2046    #[cfg(feature = "trace_widget")]
2047    pub fn disable_trace_widget(&mut self) {
2048        self.trace_widget = false;
2049    }
2050
2051    /// Don't insert property/intrinsic trace nodes on build.
2052    ///
2053    /// The trace nodes is inserted by default when `feature="trace_wgt_item"` is active.
2054    #[cfg(feature = "trace_wgt_item")]
2055    pub fn disable_trace_wgt_item(&mut self) {
2056        self.trace_wgt_item = false;
2057    }
2058
2059    /// Insert intrinsic node, that is a core functionality node of the widget that cannot be overridden.
2060    ///
2061    /// The `name` is used for inspector/trace only, intrinsic nodes are not deduplicated.
2062    pub fn push_intrinsic(
2063        &mut self,
2064        group: NestGroup,
2065        name: &'static str,
2066        intrinsic: impl FnOnce(UiNode) -> UiNode + Send + Sync + 'static,
2067    ) {
2068        self.push_intrinsic_positioned(NestPosition::intrinsic(group), name, intrinsic)
2069    }
2070
2071    /// Insert intrinsic node with custom nest position.
2072    ///
2073    /// The `name` is used for inspector/trace only, intrinsic nodes are not deduplicated.
2074    pub fn push_intrinsic_positioned(
2075        &mut self,
2076        position: NestPosition,
2077        name: &'static str,
2078        intrinsic: impl FnOnce(UiNode) -> UiNode + Send + Sync + 'static,
2079    ) {
2080        self.items.push(WidgetItemPositioned {
2081            position,
2082            insert_idx: u32::MAX,
2083            item: WidgetItem::Intrinsic {
2084                name,
2085                new: Box::new(intrinsic),
2086            },
2087        });
2088    }
2089
2090    /// Removes the property.
2091    ///
2092    /// Note that if the property can already be captured by another widget component.
2093    pub fn remove_property(&mut self, property_id: PropertyId) -> Option<BuilderProperty> {
2094        if let Some(i) = self.property_index(property_id) {
2095            match self.items.swap_remove(i) {
2096                WidgetItemPositioned {
2097                    position,
2098                    item:
2099                        WidgetItem::Property {
2100                            importance,
2101                            args,
2102                            captured,
2103                        },
2104                    ..
2105                } => Some(BuilderProperty {
2106                    importance,
2107                    position,
2108                    args,
2109                    captured,
2110                }),
2111                _ => unreachable!(),
2112            }
2113        } else {
2114            None
2115        }
2116    }
2117
2118    /// Flags the property as captured and returns a reference to it.
2119    ///
2120    /// Note that captured properties are not instantiated in the final build, but they also are not removed like *unset*.
2121    /// A property can be "captured" more then once, and if the `"inspector"` feature is enabled they can be inspected.
2122    pub fn capture_property(&mut self, property_id: PropertyId) -> Option<BuilderPropertyRef<'_>> {
2123        self.capture_property_impl(property_id)
2124    }
2125
2126    /// Flags the property as captured and downcast the input var.
2127    pub fn capture_var<T>(&mut self, property_id: PropertyId) -> Option<Var<T>>
2128    where
2129        T: VarValue,
2130    {
2131        let p = self.capture_property(property_id)?;
2132        let var = p.args.downcast_var::<T>(0).clone();
2133        Some(var)
2134    }
2135
2136    /// Flags the property as captured and downcast the input var, or calls `or_else` to generate a fallback.
2137    pub fn capture_var_or_else<T, F>(&mut self, property_id: PropertyId, or_else: impl FnOnce() -> F) -> Var<T>
2138    where
2139        T: VarValue,
2140        F: IntoVar<T>,
2141    {
2142        match self.capture_var::<T>(property_id) {
2143            Some(var) => var,
2144            None => or_else().into_var(),
2145        }
2146    }
2147
2148    /// Flags the property as captured and downcast the input var, returns a new one with the default value.
2149    pub fn capture_var_or_default<T>(&mut self, property_id: PropertyId) -> Var<T>
2150    where
2151        T: VarValue + Default,
2152    {
2153        self.capture_var_or_else(property_id, T::default)
2154    }
2155
2156    /// Flags the property as captured and get the input node.
2157    pub fn capture_ui_node(&mut self, property_id: PropertyId) -> Option<UiNode> {
2158        let p = self.capture_property(property_id)?;
2159        let node = p.args.ui_node(0).take_on_init();
2160        Some(node)
2161    }
2162
2163    /// Flags the property as captured and get the input node, or calls `or_else` to generate a fallback node.
2164    pub fn capture_ui_node_or_else(&mut self, property_id: PropertyId, or_else: impl FnOnce() -> UiNode) -> UiNode {
2165        match self.capture_ui_node(property_id) {
2166            Some(u) => u,
2167            None => or_else(),
2168        }
2169    }
2170
2171    /// Flags the property as captured and get the input node, or [`UiNode::nil`] if the property is not found.
2172    pub fn capture_ui_node_or_nil(&mut self, property_id: PropertyId) -> UiNode {
2173        self.capture_ui_node_or_else(property_id, UiNode::nil)
2174    }
2175
2176    /// Flags the property as captured and downcast the input handler.
2177    pub fn capture_widget_handler<A: Clone + 'static>(&mut self, property_id: PropertyId) -> Option<ArcWidgetHandler<A>> {
2178        let p = self.capture_property(property_id)?;
2179        let handler = p.args.downcast_handler::<A>(0).clone();
2180        Some(handler)
2181    }
2182
2183    fn build_whens(
2184        &mut self,
2185        mut whens: Vec<WhenItemPositioned>,
2186        when_init_context_id: WeakContextInitHandle,
2187        build_actions: &mut PropertyBuildActionsVec,
2188    ) {
2189        whens.sort_unstable_by_key(|w| w.sort_key());
2190
2191        struct Input<'a> {
2192            input: &'a WhenInput,
2193            item_idx: usize,
2194        }
2195        let mut inputs = vec![];
2196
2197        struct Assign {
2198            item_idx: usize,
2199            builder: Vec<Box<dyn Any>>,
2200            when_count: usize,
2201            /// map of key:action set in the property, in at least one when, and value:Vec of data for each when in order and
2202            /// Option of default action.
2203            actions_data: HashMap<&'static str, (Vec<Option<WhenBuildActionData>>, Option<WhenBuildDefaultAction>)>,
2204        }
2205        let mut assigns = IdMap::default();
2206
2207        // rev so that the last when overrides others, the WhenVar returns the first true condition.
2208        'when: for WhenItemPositioned { when, .. } in whens.iter().rev() {
2209            // bind inputs.
2210            let valid_inputs = inputs.len();
2211            let valid_items = self.p.items.len();
2212            for input in when.inputs.iter() {
2213                if let Some(i) = self.property_index(input.property) {
2214                    inputs.push(Input { input, item_idx: i })
2215                } else if let Some(default) = input.property_default {
2216                    let args = default();
2217                    self.p.items.push(WidgetItemPositioned {
2218                        position: NestPosition::property(args.property().group),
2219                        insert_idx: u32::MAX,
2220                        item: WidgetItem::Property {
2221                            importance: Importance::WIDGET,
2222                            args,
2223                            captured: false,
2224                        },
2225                    });
2226                    inputs.push(Input {
2227                        input,
2228                        item_idx: self.p.items.len() - 1,
2229                    });
2230                } else {
2231                    inputs.truncate(valid_inputs);
2232                    self.p.items.truncate(valid_items);
2233                    continue 'when;
2234                }
2235            }
2236
2237            let mut any_assign = false;
2238            // collect assigns.
2239            'assign: for assign in when.assigns.iter() {
2240                let id = assign.id();
2241                let assign_info;
2242                let i;
2243                if let Some(idx) = self.property_index(id) {
2244                    assign_info = assign.property();
2245                    i = idx;
2246                } else if let Some(default) = assign.property().default {
2247                    let args = default();
2248                    assign_info = args.property();
2249                    i = self.p.items.len();
2250                    self.p.items.push(WidgetItemPositioned {
2251                        position: NestPosition::property(args.property().group),
2252                        insert_idx: u32::MAX,
2253                        item: WidgetItem::Property {
2254                            importance: Importance::WIDGET,
2255                            args,
2256                            captured: false,
2257                        },
2258                    });
2259                } else {
2260                    tracing::warn!(
2261                        "property `{}` ignored, it is only set in `when` block and has no default value",
2262                        assign.property().name
2263                    );
2264                    continue;
2265                }
2266
2267                any_assign = true;
2268
2269                let default_args = match &self.items[i].item {
2270                    WidgetItem::Property { args, .. } => args,
2271                    WidgetItem::Intrinsic { .. } => unreachable!(),
2272                };
2273                let info = default_args.property();
2274
2275                for (default_info, assign_info) in info.inputs.iter().zip(assign_info.inputs.iter()) {
2276                    if default_info.ty != assign_info.ty {
2277                        // can happen with generic properties.
2278                        continue 'assign;
2279                    }
2280                }
2281
2282                let entry = match assigns.entry(id) {
2283                    IdEntry::Occupied(e) => e.into_mut(),
2284                    IdEntry::Vacant(e) => e.insert(Assign {
2285                        item_idx: i,
2286                        builder: info
2287                            .inputs
2288                            .iter()
2289                            .enumerate()
2290                            .map(|(i, input)| match input.kind {
2291                                InputKind::Var => Box::new(AnyWhenVarBuilder::new(default_args.var(i).clone())) as _,
2292                                InputKind::UiNode => Box::new(WhenUiNodeBuilder::new(default_args.ui_node(i).take_on_init())) as _,
2293                                InputKind::WidgetHandler => {
2294                                    Box::new(AnyWhenArcWidgetHandlerBuilder::new(default_args.widget_handler(i).clone_boxed())) as _
2295                                }
2296                                InputKind::Value => panic!("can only assign vars in when blocks"),
2297                            })
2298                            .collect(),
2299                        when_count: 0,
2300                        actions_data: Default::default(),
2301                    }),
2302                };
2303                entry.when_count += 1;
2304
2305                for (i, (input, entry)) in info.inputs.iter().zip(entry.builder.iter_mut()).enumerate() {
2306                    match input.kind {
2307                        InputKind::Var => {
2308                            let entry = entry.downcast_mut::<AnyWhenVarBuilder>().unwrap();
2309                            let value = assign.var(i).clone();
2310                            entry.push(when.state.clone(), value);
2311                        }
2312                        InputKind::UiNode => {
2313                            let entry = entry.downcast_mut::<WhenUiNodeBuilder>().unwrap();
2314                            let node = assign.ui_node(i).take_on_init();
2315                            entry.push(when.state.clone(), node);
2316                        }
2317                        InputKind::WidgetHandler => {
2318                            let entry = entry.downcast_mut::<AnyWhenArcWidgetHandlerBuilder>().unwrap();
2319                            let handler = assign.widget_handler(i).clone_boxed();
2320                            entry.push(when.state.clone(), handler);
2321                        }
2322                        InputKind::Value => panic!("cannot assign `Value` in when blocks"),
2323                    }
2324                }
2325
2326                for ((property_id, action_key), action) in &when.build_action_data {
2327                    if *property_id == id {
2328                        match entry.actions_data.entry(*action_key) {
2329                            hash_map::Entry::Occupied(mut e) => {
2330                                let e = e.get_mut();
2331                                for _ in e.0.len()..(entry.when_count - 1) {
2332                                    e.0.push(None);
2333                                }
2334                                e.0.push(Some(action.data.clone()));
2335                                if action.default_action.is_some() && e.1.is_none() {
2336                                    e.1.clone_from(&action.default_action);
2337                                }
2338                            }
2339                            hash_map::Entry::Vacant(e) => {
2340                                let mut a = Vec::with_capacity(entry.when_count);
2341                                for _ in 0..(entry.when_count - 1) {
2342                                    a.push(None);
2343                                }
2344                                a.push(Some(action.data.clone()));
2345                                e.insert((a, action.default_action.clone()));
2346                            }
2347                        }
2348                    }
2349                }
2350            }
2351
2352            if !any_assign {
2353                inputs.truncate(valid_inputs);
2354                self.p.items.truncate(valid_items);
2355            }
2356        }
2357
2358        for Input { input, item_idx } in inputs {
2359            let args = match &self.items[item_idx].item {
2360                WidgetItem::Property { args, .. } => args,
2361                WidgetItem::Intrinsic { .. } => unreachable!(),
2362            };
2363            let info = args.property();
2364
2365            let member_i = match input.member {
2366                WhenInputMember::Named(name) => info.input_idx(name).expect("when ref named input not found"),
2367                WhenInputMember::Index(i) => i,
2368            };
2369
2370            let actual = match info.inputs[member_i].kind {
2371                InputKind::Var => args.var(member_i).clone(),
2372                InputKind::Value => any_const_var(args.value(member_i).clone_boxed()),
2373                _ => panic!("can only ref var or values in when expr"),
2374            };
2375            input.var.set(when_init_context_id.clone(), actual);
2376        }
2377
2378        for (
2379            _,
2380            Assign {
2381                item_idx,
2382                builder,
2383                when_count,
2384                mut actions_data,
2385            },
2386        ) in assigns
2387        {
2388            let args = match &mut self.items[item_idx].item {
2389                WidgetItem::Property { args, .. } => args,
2390                WidgetItem::Intrinsic { .. } => unreachable!(),
2391            };
2392
2393            let mut actions = vec![];
2394            let mut b_actions_data = vec![];
2395            if !build_actions.is_empty() {
2396                let p_id = args.id();
2397                while let Some(i) = build_actions.iter().position(|((id, _), _)| *id == p_id) {
2398                    let ((_, action_key), (_, a)) = build_actions.swap_remove(i);
2399                    actions.push(a);
2400
2401                    if let Some(data) = actions_data.remove(action_key) {
2402                        let mut data = data.clone();
2403                        for _ in data.0.len()..when_count {
2404                            data.0.push(None);
2405                        }
2406                        b_actions_data.push(data.0);
2407                    }
2408                }
2409            }
2410
2411            for (_, (mut data, default)) in actions_data {
2412                if let Some(default) = default {
2413                    let action = default();
2414                    for _ in data.len()..when_count {
2415                        data.push(None);
2416                    }
2417
2418                    actions.push(action);
2419                    b_actions_data.push(data);
2420                }
2421            }
2422
2423            *args = (args.property().new)(PropertyNewArgs {
2424                args: builder,
2425                build_actions: actions,
2426                build_actions_when_data: b_actions_data,
2427            });
2428        }
2429    }
2430
2431    fn build_p_actions(&mut self, mut build_actions: PropertyBuildActionsVec) {
2432        while !build_actions.is_empty() {
2433            let ((p_id, _), (_, a)) = build_actions.swap_remove(0);
2434            let mut actions = vec![a];
2435
2436            while let Some(i) = build_actions.iter().position(|((id, _), _)| *id == p_id) {
2437                let (_, (_, a)) = build_actions.swap_remove(i);
2438                actions.push(a);
2439            }
2440
2441            if let Some(i) = self.property_index(p_id) {
2442                match &mut self.items[i].item {
2443                    WidgetItem::Property { args, .. } => *args = args.new_build(actions, vec![]),
2444                    WidgetItem::Intrinsic { .. } => unreachable!(),
2445                }
2446            }
2447        }
2448    }
2449
2450    fn build(mut self, when_init_context_handle: Option<ContextInitHandle>) -> UiNode {
2451        // sort by group, index and insert index.
2452        self.items.sort_unstable_by_key(|b| b.sort_key());
2453
2454        #[cfg(feature = "inspector")]
2455        let mut inspector_items = Vec::with_capacity(self.p.items.len());
2456
2457        let mut node = self.child.take().unwrap_or_else(|| FillUiNode.into_node());
2458        for WidgetItemPositioned { position, item, .. } in self.p.items.into_iter().rev() {
2459            match item {
2460                WidgetItem::Property { args, captured, .. } => {
2461                    if !captured {
2462                        #[cfg(debug_assertions)]
2463                        {
2464                            let p = args.property();
2465                            if p.capture {
2466                                tracing::error!(
2467                                    "capture only property `{}` is not captured in `{}!`, it will have no effect",
2468                                    p.name,
2469                                    self.widget_type.name()
2470                                );
2471                            }
2472                        }
2473
2474                        node = args.instantiate(node);
2475
2476                        #[cfg(feature = "trace_wgt_item")]
2477                        if self.trace_wgt_item {
2478                            let name = args.property().name;
2479                            node = node.trace(move |mtd| crate::update::UpdatesTrace::property_span(name, mtd.mtd_name()));
2480                        }
2481                    }
2482
2483                    #[cfg(feature = "inspector")]
2484                    {
2485                        if args.property().inputs.iter().any(|i| matches!(i.kind, InputKind::Var)) {
2486                            node = crate::widget::inspector::actualize_var_info(node, args.id());
2487                        }
2488
2489                        inspector_items.push(crate::widget::inspector::InstanceItem::Property { args, captured });
2490                    }
2491                }
2492                #[allow(unused_variables)] // depends on cfg
2493                WidgetItem::Intrinsic { new, name } => {
2494                    node = new(node);
2495                    #[cfg(feature = "trace_wgt_item")]
2496                    if self.trace_wgt_item {
2497                        node = node.trace(move |mtd| crate::update::UpdatesTrace::intrinsic_span(name, mtd.mtd_name()));
2498                    }
2499
2500                    #[cfg(feature = "inspector")]
2501                    inspector_items.push(crate::widget::inspector::InstanceItem::Intrinsic {
2502                        group: position.group,
2503                        name,
2504                    });
2505
2506                    #[cfg(not(feature = "inspector"))]
2507                    let _ = position;
2508                }
2509            }
2510        }
2511
2512        #[cfg(feature = "inspector")]
2513        if let Some(builder) = self.builder {
2514            node = crate::widget::inspector::insert_widget_builder_info(
2515                node,
2516                crate::widget::inspector::InspectorInfo {
2517                    builder,
2518                    items: inspector_items.into_boxed_slice(),
2519                    actual_vars: crate::widget::inspector::InspectorActualVars::default(),
2520                },
2521            );
2522        }
2523
2524        #[cfg(feature = "trace_widget")]
2525        if self.trace_widget {
2526            let name = self.widget_type.name();
2527            node = node.trace(move |op| crate::update::UpdatesTrace::widget_span(crate::widget::WIDGET.id(), name, op.mtd_name()));
2528        }
2529
2530        // ensure `when` reuse works, by forcing input refresh on (re)init.
2531        node = with_new_context_init_id(node);
2532
2533        if let Some(handle) = when_init_context_handle {
2534            // ensure shared/cloned when input expressions work.
2535            let mut handle = Some(Arc::new(handle));
2536            node = crate::widget::node::match_node(node, move |c, op| {
2537                WHEN_INPUT_CONTEXT_INIT_ID.with_context(&mut handle, || c.op(op));
2538            });
2539        }
2540
2541        node
2542    }
2543}
2544impl ops::Deref for WidgetBuilding {
2545    type Target = WidgetBuilderProperties;
2546
2547    fn deref(&self) -> &Self::Target {
2548        &self.p
2549    }
2550}
2551impl ops::DerefMut for WidgetBuilding {
2552    fn deref_mut(&mut self) -> &mut Self::Target {
2553        &mut self.p
2554    }
2555}
2556
2557/// Represents a property removed from [`WidgetBuilding`].
2558#[derive(Debug)]
2559#[non_exhaustive]
2560pub struct BuilderProperty {
2561    /// Property importance at the time of removal.
2562    pub importance: Importance,
2563    /// Property group and index at the time of removal.
2564    pub position: NestPosition,
2565    /// Property args.
2566    pub args: Box<dyn PropertyArgs>,
2567    /// If the property was *captured* before removal.
2568    pub captured: bool,
2569}
2570
2571/// Represents a property in [`WidgetBuilder`] or [`WidgetBuilding`].
2572#[derive(Debug)]
2573#[non_exhaustive]
2574pub struct BuilderPropertyRef<'a> {
2575    /// Property current importance.
2576    pub importance: Importance,
2577    /// Property current group and index.
2578    pub position: NestPosition,
2579    /// Property args.
2580    pub args: &'a dyn PropertyArgs,
2581    /// If the property was *captured*.
2582    ///
2583    /// This can only be `true` in [`WidgetBuilding`].
2584    pub captured: bool,
2585}
2586
2587/// Represents a mutable reference to property in [`WidgetBuilder`] or [`WidgetBuilding`].
2588#[derive(Debug)]
2589#[non_exhaustive]
2590pub struct BuilderPropertyMut<'a> {
2591    /// Property current importance.
2592    pub importance: &'a mut Importance,
2593    /// Property current group and index.
2594    pub position: &'a mut NestPosition,
2595    /// Property args.
2596    pub args: &'a mut Box<dyn PropertyArgs>,
2597    /// If the property was *captured*.
2598    ///
2599    /// This can only be `true` in [`WidgetBuilding`].
2600    pub captured: &'a mut bool,
2601}
2602
2603/// Direct property access in [`WidgetBuilder`] and [`WidgetBuilding`].
2604pub struct WidgetBuilderProperties {
2605    items: Vec<WidgetItemPositioned>,
2606}
2607impl WidgetBuilderProperties {
2608    /// Reference the property, if it is present.
2609    pub fn property(&self, property_id: PropertyId) -> Option<BuilderPropertyRef<'_>> {
2610        match self.property_index(property_id) {
2611            Some(i) => match &self.items[i].item {
2612                WidgetItem::Property {
2613                    importance,
2614                    args,
2615                    captured,
2616                } => Some(BuilderPropertyRef {
2617                    importance: *importance,
2618                    position: self.items[i].position,
2619                    args: &**args,
2620                    captured: *captured,
2621                }),
2622                WidgetItem::Intrinsic { .. } => unreachable!(),
2623            },
2624            None => None,
2625        }
2626    }
2627
2628    /// Modify the property, if it is present.
2629    pub fn property_mut(&mut self, property_id: PropertyId) -> Option<BuilderPropertyMut<'_>> {
2630        match self.property_index(property_id) {
2631            Some(i) => match &mut self.items[i] {
2632                WidgetItemPositioned {
2633                    position,
2634                    item:
2635                        WidgetItem::Property {
2636                            importance,
2637                            args,
2638                            captured,
2639                        },
2640                    ..
2641                } => Some(BuilderPropertyMut {
2642                    importance,
2643                    position,
2644                    args,
2645                    captured,
2646                }),
2647                _ => unreachable!(),
2648            },
2649            None => None,
2650        }
2651    }
2652
2653    /// Iterate over the current properties.
2654    ///
2655    /// The properties may not be sorted in the correct order if the builder has never built.
2656    pub fn properties(&self) -> impl Iterator<Item = BuilderPropertyRef<'_>> {
2657        self.items.iter().filter_map(|it| match &it.item {
2658            WidgetItem::Intrinsic { .. } => None,
2659            WidgetItem::Property {
2660                importance,
2661                args,
2662                captured,
2663            } => Some(BuilderPropertyRef {
2664                importance: *importance,
2665                position: it.position,
2666                args: &**args,
2667                captured: *captured,
2668            }),
2669        })
2670    }
2671
2672    /// iterate over mutable references to the current properties.
2673    pub fn properties_mut(&mut self) -> impl Iterator<Item = BuilderPropertyMut<'_>> {
2674        self.items.iter_mut().filter_map(|it| match &mut it.item {
2675            WidgetItem::Intrinsic { .. } => None,
2676            WidgetItem::Property {
2677                importance,
2678                args,
2679                captured,
2680            } => Some(BuilderPropertyMut {
2681                importance,
2682                position: &mut it.position,
2683                args,
2684                captured,
2685            }),
2686        })
2687    }
2688
2689    /// Flags the property as captured and downcast the input value.
2690    ///
2691    /// Unlike other property kinds you can capture values in the [`WidgetBuilder`], note that the value may not
2692    /// the final value, unless you are capturing on build.
2693    ///
2694    /// Other property kinds can only be captured in [`WidgetBuilding`] as
2695    /// their values strongly depend on the final `when` blocks that are only applied after building starts.
2696    pub fn capture_value<T>(&mut self, property_id: PropertyId) -> Option<T>
2697    where
2698        T: VarValue,
2699    {
2700        let p = self.capture_property_impl(property_id)?;
2701        let value = p.args.downcast_value::<T>(0).clone();
2702        Some(value)
2703    }
2704
2705    /// Flags the property as captured and downcast the input value, or calls `or_else` to generate the value.
2706    pub fn capture_value_or_else<T>(&mut self, property_id: PropertyId, or_else: impl FnOnce() -> T) -> T
2707    where
2708        T: VarValue,
2709    {
2710        match self.capture_value(property_id) {
2711            Some(v) => v,
2712            None => or_else(),
2713        }
2714    }
2715
2716    /// Flags the property as captured and downcast the input value, or returns the default value.
2717    pub fn capture_value_or_default<T>(&mut self, property_id: PropertyId) -> T
2718    where
2719        T: VarValue + Default,
2720    {
2721        self.capture_value_or_else(property_id, T::default)
2722    }
2723
2724    fn capture_property_impl(&mut self, property_id: PropertyId) -> Option<BuilderPropertyRef<'_>> {
2725        if let Some(i) = self.property_index(property_id) {
2726            match &mut self.items[i] {
2727                WidgetItemPositioned {
2728                    position,
2729                    item:
2730                        WidgetItem::Property {
2731                            importance,
2732                            args,
2733                            captured,
2734                        },
2735                    ..
2736                } => {
2737                    *captured = true;
2738                    Some(BuilderPropertyRef {
2739                        importance: *importance,
2740                        position: *position,
2741                        args: &**args,
2742                        captured: *captured,
2743                    })
2744                }
2745                _ => unreachable!(),
2746            }
2747        } else {
2748            None
2749        }
2750    }
2751
2752    fn property_index(&self, property_id: PropertyId) -> Option<usize> {
2753        self.items.iter().position(|it| match &it.item {
2754            WidgetItem::Property { args, .. } => args.id() == property_id,
2755            WidgetItem::Intrinsic { .. } => false,
2756        })
2757    }
2758}
2759
2760/// Represents any [`PropertyBuildAction<I>`].
2761pub trait AnyPropertyBuildAction: crate::private::Sealed + Any + Send + Sync {
2762    /// As any.
2763    fn as_any(&self) -> &dyn Any;
2764
2765    /// Clone the action into a new box.
2766    fn clone_boxed(&self) -> Box<dyn AnyPropertyBuildAction>;
2767}
2768
2769/// Arguments for [`PropertyBuildAction<I>`].
2770#[non_exhaustive]
2771pub struct PropertyBuildActionArgs<'a, I: Any + Send> {
2772    /// The property input value.
2773    pub input: I,
2774    /// The [`WhenBuildAction::data`] for each when assign that affects `input` in the order that `input` was generated.
2775    ///
2776    /// Items are `None` for when assigns that do not have associated build action data.
2777    pub when_conditions_data: &'a [Option<WhenBuildActionData>],
2778}
2779
2780/// Represents a custom build action targeting a property input that is applied after `when` is build.
2781///
2782/// The type `I` depends on the input kind:
2783///
2784/// The expected types for each [`InputKind`] are:
2785///
2786/// | Kind                | Expected Type
2787/// |---------------------|-------------------------------------------------
2788/// | [`Var`]             | `Var<T>`
2789/// | [`Value`]           | `T`
2790/// | [`UiNode`]          | `ArcNode<BoxedUiNode>`
2791/// | [`WidgetHandler`]   | `ArcWidgetHandler<A>`
2792///
2793/// [`Var`]: InputKind::Var
2794/// [`Value`]: InputKind::Value
2795/// [`UiNode`]: InputKind::UiNode
2796/// [`WidgetHandler`]: InputKind::WidgetHandler
2797pub struct PropertyBuildAction<I: Any + Send>(Arc<Mutex<dyn FnMut(PropertyBuildActionArgs<I>) -> I + Send>>);
2798impl<I: Any + Send> crate::private::Sealed for PropertyBuildAction<I> {}
2799impl<I: Any + Send> Clone for PropertyBuildAction<I> {
2800    fn clone(&self) -> Self {
2801        Self(self.0.clone())
2802    }
2803}
2804impl<I: Any + Send> AnyPropertyBuildAction for PropertyBuildAction<I> {
2805    fn clone_boxed(&self) -> Box<dyn AnyPropertyBuildAction> {
2806        Box::new(self.clone())
2807    }
2808
2809    fn as_any(&self) -> &dyn Any {
2810        self
2811    }
2812}
2813impl<I: Any + Send> PropertyBuildAction<I> {
2814    /// New build action.
2815    pub fn new(build: impl FnMut(PropertyBuildActionArgs<I>) -> I + Send + 'static) -> Self {
2816        Self(Arc::new(Mutex::new(build)))
2817    }
2818
2819    /// New build action that just pass the input.
2820    pub fn no_op() -> Self {
2821        Self::new(|i| i.input)
2822    }
2823
2824    /// Run the build action on a input.
2825    pub fn build(&self, args: PropertyBuildActionArgs<I>) -> I {
2826        (self.0.lock())(args)
2827    }
2828}
2829impl Clone for Box<dyn AnyPropertyBuildAction> {
2830    fn clone(&self) -> Self {
2831        self.clone_boxed()
2832    }
2833}
2834
2835/// Represents the strong types of each input of a property.
2836///
2837/// # Examples
2838///
2839/// The example uses [`property_input_types!`] to collect the types and compares it to a manually generated types. Note
2840/// that the type is a tuple even if there is only one input.
2841///
2842/// ```
2843/// # use zng_app::{*, widget::{node::*, builder::*, property}};
2844/// # use zng_var::*;
2845/// # use std::any::Any;
2846/// #[property(CONTEXT)]
2847/// pub fn foo(child: impl IntoUiNode, bar: impl IntoVar<bool>) -> UiNode {
2848///     # child.into_node()
2849/// }
2850///
2851/// # fn main() {
2852/// assert_eq!(
2853///     property_input_types!(foo).type_id(),
2854///     PropertyInputTypes::<(Var<bool>,)>::unit().type_id(),
2855/// );
2856/// # }
2857/// ```
2858///
2859/// You can use the collected types in advanced code generation, such as attribute proc-macros targeting property assigns in widgets.
2860/// The next example demonstrates a trait that uses auto-deref to convert a trait bound to a `bool`:
2861///
2862/// ```
2863/// # use zng_app::{*, widget::{node::*, builder::*, property}};
2864/// # use zng_var::*;
2865/// #[property(CONTEXT)]
2866/// pub fn foo(child: impl IntoUiNode, bar: impl IntoVar<bool>) -> UiNode {
2867///     # child.into_node()
2868/// }
2869///
2870/// trait SingleBoolVar {
2871///     fn is_single_bool_var(self) -> bool;
2872/// }
2873///
2874/// // match
2875/// impl<'a> SingleBoolVar for &'a PropertyInputTypes<(Var<bool>,)> {
2876///     fn is_single_bool_var(self) -> bool {
2877///         true
2878///     }
2879/// }
2880///
2881/// // fallback impl
2882/// impl<T: Send + 'static> SingleBoolVar for PropertyInputTypes<T> {
2883///     fn is_single_bool_var(self) -> bool {
2884///         false
2885///     }
2886/// }
2887///
2888/// # fn main() {
2889/// assert!((&property_input_types!(foo)).is_single_bool_var());
2890/// # }
2891/// ```
2892///
2893/// Learn more about how this trick works and limitations
2894/// [here](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md).
2895pub struct PropertyInputTypes<Tuple>(std::marker::PhantomData<Tuple>);
2896impl<Tuple> PropertyInputTypes<Tuple> {
2897    /// Unit value.
2898    pub const fn unit() -> Self {
2899        Self(std::marker::PhantomData)
2900    }
2901}
2902impl<Tuple> Clone for PropertyInputTypes<Tuple> {
2903    fn clone(&self) -> Self {
2904        *self
2905    }
2906}
2907impl<Tuple> Copy for PropertyInputTypes<Tuple> {}
2908// SAFETY: PhantomData
2909unsafe impl<Tuple> Send for PropertyInputTypes<Tuple> {}
2910unsafe impl<Tuple> Sync for PropertyInputTypes<Tuple> {}