Skip to main content

zng_app/widget/
builder.rs

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