zng_app/widget/
builder.rs

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