zng_app/
widget.rs

1//! Widget, UI node API.
2
3pub mod base;
4pub mod border;
5pub mod builder;
6pub mod info;
7pub mod inspector;
8pub mod node;
9
10mod easing;
11pub use easing::*;
12
13use atomic::Atomic;
14use parking_lot::{Mutex, RwLock};
15use std::{
16    borrow::Cow,
17    pin::Pin,
18    sync::{Arc, atomic::Ordering::Relaxed},
19};
20use zng_app_context::context_local;
21use zng_clone_move::clmv;
22use zng_handle::Handle;
23use zng_layout::unit::{DipPoint, DipToPx as _, Layout1d, Layout2d, Px, PxPoint, PxTransform};
24use zng_state_map::{OwnedStateMap, StateId, StateMapMut, StateMapRef, StateValue};
25use zng_task::UiTask;
26use zng_txt::{Txt, formatx};
27use zng_var::{AnyVar, BoxAnyVarValue, ResponseVar, Var, VarHandle, VarHandles, VarValue};
28use zng_view_api::display_list::ReuseRange;
29
30use crate::{
31    event::{Event, EventArgs, EventHandle, EventHandles},
32    handler::{APP_HANDLER, AppWeakHandle, Handler, HandlerExt as _, HandlerResult},
33    update::{LayoutUpdates, RenderUpdates, UPDATES, UpdateFlags, UpdateOp, UpdatesTrace},
34    window::WINDOW,
35};
36
37use self::info::{WidgetBorderInfo, WidgetBoundsInfo, WidgetInfo};
38
39// proc-macros used internally during widget creation.
40#[doc(hidden)]
41pub use zng_app_proc_macros::{property_impl, property_meta, widget_new};
42
43pub use zng_app_proc_macros::{property, widget, widget_mixin};
44
45/// <span data-del-macro-root></span> Sets properties and when condition on a widget builder.
46///
47/// # Examples
48///
49/// ```
50/// # use zng_app::{*, widget::{base::*, node::*, widget, property}};
51/// # use zng_var::*;
52/// # #[property(CONTEXT)] pub fn enabled(child: impl IntoUiNode, enabled: impl IntoVar<bool>) -> UiNode { child.into_node() }
53/// # #[widget($crate::Wgt)]
54/// # pub struct Wgt(WidgetBase);
55/// # fn main() {
56/// # let flag = true;
57/// #
58/// let mut wgt = Wgt::widget_new();
59///
60/// if flag {
61///     widget_set! {
62///         &mut wgt;
63///         enabled = false;
64///     }
65/// }
66///
67/// widget_set! {
68///     &mut wgt;
69///     id = "wgt";
70/// }
71///
72/// let wgt = wgt.widget_build();
73/// # }
74/// ```
75///
76/// In the example above the widget will always build with custom `id`, but only will set `enabled = false` when `flag` is `true`.
77///
78/// Note that properties are designed to have a default *neutral* value that behaves as if unset, in the example case you could more easily write:
79///
80/// ```
81/// # zng_app::enable_widget_macros!();
82/// # use zng_app::{*, widget::{node::*, base::*, widget, property}};
83/// # use zng_color::*;
84/// # use zng_var::*;
85/// # #[widget($crate::Wgt)] pub struct Wgt(WidgetBase);
86/// # #[property(CONTEXT)] pub fn enabled(child: impl IntoUiNode, enabled: impl IntoVar<bool>) -> UiNode { child.into_node() }
87/// # fn main() {
88/// # let flag = true;
89/// let wgt = Wgt! {
90///     enabled = !flag;
91///     id = "wgt";
92/// };
93/// # }
94/// ```
95///
96/// You should use this macro only in contexts where a widget will be build in steps, or in very hot code paths where a widget
97/// has many properties and only some will be non-default per instance.
98///
99/// # Property Assign
100///
101/// Properties can be assigned using the `property = value;` syntax, this expands to a call to the property method, either
102/// directly implemented on the widget or from a trait.
103///
104/// ```
105/// # use zng_app::{*, widget::{node::*, property}};
106/// # use zng_color::*;
107/// # use zng_var::*;
108/// # use zng_layout::unit::*;
109/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
110/// # fn main() {
111/// # let wgt = zng_app::widget::base::WidgetBase! {
112/// id = "name";
113/// background_color = colors::BLUE;
114/// # }; }
115/// ```
116///
117/// The example above is equivalent to:
118///
119/// ```
120/// # use zng_app::{*, widget::{node::*, property}};
121/// # use zng_color::*;
122/// # use zng_var::*;
123/// # use zng_layout::unit::*;
124/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
125/// # fn main() {
126/// # let mut wgt = zng_app::widget::base::WidgetBase::widget_new();
127/// wgt.id("name");
128/// wgt.background_color(colors::BLUE);
129/// # }
130/// ```
131///
132/// Note that `id` is an intrinsic property inherited from [`WidgetBase`], but `background_color` is an extension property declared
133/// by a [`property`] function. Extension properties require `&mut self` access to the widget, intrinsic properties only require `&self`,
134/// this is done so that IDEs that use a different style for mutable methods highlight the properties that are not intrinsic to the widget.
135///
136/// ## Path Assign
137///
138/// A full or partial path can be used to specify exactly what extension property will be set:
139///
140/// ```
141/// # use zng_app::{*, widget::{node::*, property}};
142/// # use zng_color::*;
143/// # use zng_var::*;
144/// # use zng_layout::unit::*;
145/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
146/// # fn main() {
147/// # let wgt = zng_app::widget::base::WidgetBase! {
148/// self::background_color = colors::BLUE;
149/// # }; }
150/// ```
151///
152/// In the example above `self::background_color` specify that an extension property that is imported in the `self` module must be set,
153/// even if the widget gets an intrinsic `background_color` property the extension property will still be used.
154///
155/// The example above is equivalent to:
156///
157/// ```
158/// # use zng_app::{*, widget::{node::*, property}};
159/// # use zng_color::*;
160/// # use zng_var::*;
161/// # use zng_layout::unit::*;
162/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
163/// # fn main() {
164/// # let mut wgt = zng_app::widget::base::WidgetBase::widget_new();
165/// self::background_color::background_color(&mut wgt, colors::BLUE);
166/// # }
167/// ```
168///
169/// ## Named Assign
170///
171/// Properties can have multiple parameters, multiple parameters can be set using the struct init syntax:
172///
173/// ```rust,no_fmt
174/// # use zng_app::{*, widget::{node::*, property}};
175/// # use zng_color::*;
176/// # use zng_var::*;
177/// # use zng_layout::unit::*;
178/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
179/// # fn main() {
180/// # let wgt = zng_app::widget::base::WidgetBase! {
181/// border = {
182///     widths: 1,
183///     sides: colors::RED,
184/// };
185/// # }; }
186/// ```
187///
188/// Note that just like in struct init the parameters don't need to be in order:
189///
190/// ```rust,no_fmt
191/// # use zng_app::{*, widget::{node::*, property}};
192/// # use zng_color::*;
193/// # use zng_var::*;
194/// # use zng_layout::unit::*;
195/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
196/// # fn main() {
197/// # let wgt = zng_app::widget::base::WidgetBase! {
198/// border = {
199///     sides: colors::RED,
200///     widths: 1,
201/// };
202/// # }; }
203/// ```
204///
205/// Internally each property method has auxiliary methods that validate the member names and construct the property using sorted params, therefore
206/// accepting any parameter order. Note each parameter is evaluated in the order they appear, even if they are assigned in a different order after.
207///
208/// ```rust,no_fmt
209/// # use zng_app::{*, widget::{node::*, property}};
210/// # use zng_color::*;
211/// # use zng_var::*;
212/// # use zng_layout::unit::*;
213/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
214/// # fn main() {
215/// let mut eval_order = vec![];
216///
217/// # let wgt = zng_app::widget::base::WidgetBase! {
218/// border = {
219///     sides: {
220///         eval_order.push("sides");
221///         colors::RED
222///     },
223///     widths: {
224///         eval_order.push("widths");
225///         1
226///     },
227/// };
228/// # };
229///
230/// assert_eq!(eval_order, vec!["sides", "widths"]);
231/// # }
232/// ```
233///
234/// ## Unnamed Assign Multiple
235///
236/// Properties with multiple parameters don't need to be set using the named syntax:
237///
238/// ```rust,no_fmt
239/// # use zng_app::{*, widget::{node::*, property}};
240/// # use zng_color::*;
241/// # use zng_var::*;
242/// # use zng_layout::unit::*;
243/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
244/// # fn main() {
245/// # let wgt = zng_app::widget::base::WidgetBase! {
246/// border = 1, colors::RED;
247/// # }; }
248/// ```
249///
250/// The example above is equivalent to:
251///
252/// ```
253/// # use zng_app::{*, widget::{node::*, property}};
254/// # use zng_color::*;
255/// # use zng_var::*;
256/// # use zng_layout::unit::*;
257/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
258/// # fn main() {
259/// # let mut wgt = zng_app::widget::base::WidgetBase::widget_new();
260/// wgt.border(1, colors::RED);
261/// # }
262/// ```
263///
264/// ## Shorthand Assign
265///
266/// Is a variable with the same name as a property is in context the `= name` can be omitted:
267///
268/// ```
269/// # use zng_app::{*, widget::{node::*, property}};
270/// # use zng_color::*;
271/// # use zng_var::*;
272/// # use zng_layout::unit::*;
273/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
274/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
275/// # fn main() {
276/// let id = "name";
277/// let background_color = colors::BLUE;
278/// let widths = 1;
279///
280/// let wgt = zng_app::widget::base::WidgetBase! {
281///     id;
282///     self::background_color;
283///     border = {
284///         widths,
285///         sides: colors::RED,
286///     };
287/// };
288/// # }
289/// ```
290///
291/// Note that the shorthand syntax also works for path properties and parameter names.
292///
293/// The above is equivalent to:
294///
295/// ```
296/// # use zng_app::{*, widget::{node::*, property}};
297/// # use zng_color::*;
298/// # use zng_var::*;
299/// # use zng_layout::unit::*;
300/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
301/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
302/// # fn main() {
303/// let id = "name";
304/// let background_color = colors::BLUE;
305/// let widths = 1;
306///
307/// let wgt = zng_app::widget::base::WidgetBase! {
308///     id = id;
309///     self::background_color = background_color;
310///     border = {
311///         widths: widths,
312///         sides: colors::RED,
313///     };
314/// };
315/// # }
316/// ```
317///
318/// # Property Unset
319///
320/// All properties can be assigned to an special value `unset!`, that *removes* a property, when the widget is build the
321/// unset property will not be instantiated:
322///
323/// ```rust,no_fmt
324/// # use zng_app::{*, widget::{node::*, property}};
325/// # use zng_color::*;
326/// # use zng_var::*;
327/// # use zng_layout::unit::*;
328/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
329/// # fn main() {
330/// # let wgt = zng_app::widget::base::WidgetBase! {
331/// border = unset!;
332/// # }; }
333/// ```
334///
335/// The example above is equivalent to:
336///
337/// ```
338/// # use zng_app::{*, widget::{node::*, property}};
339/// # use zng_color::*;
340/// # use zng_var::*;
341/// # use zng_layout::unit::*;
342/// # #[property(CONTEXT)] pub fn border(child: impl IntoUiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
343/// # fn main() {
344/// # let mut wgt = zng_app::widget::base::WidgetBase::widget_new();
345/// wgt.unset_border();
346/// # }
347/// ```
348///
349/// Each property method generates an auxiliary `unset_property` method, the unset is registered in the widget builder using the current
350/// importance, in `widget_intrinsic` they only unset already inherited default assigns, in instances it unsets all inherited or
351/// previous assigns, see [`WidgetBuilder::push_unset`] for more details.
352///
353/// # Generic Properties
354///
355/// Generic properties need a *turbofish* annotation on assign:
356///
357/// ```rust,no_fmt
358/// # use zng_app::{*, widget::{node::*, property}};
359/// # use zng_color::*;
360/// # use zng_var::*;
361/// # use zng_layout::unit::*;
362/// # #[property(CONTEXT)] pub fn value<T: VarValue>(child: impl IntoUiNode, value: impl IntoVar<T>) -> UiNode { child.into_node() }
363/// #
364/// # fn main() {
365/// # let wgt = zng_app::widget::base::WidgetBase! {
366/// value::<f32> = 1.0;
367/// # };}
368/// ```
369///
370/// # When
371///
372/// Conditional property assigns can be setup using `when` blocks. A `when` block has a `bool` expression and property assigns,
373/// when the expression is `true` each property has the assigned value, unless it is overridden by a later `when` block.
374///
375/// ```rust,no_fmt
376/// # use zng_app::{*, widget::{node::*, property}};
377/// # use zng_color::*;
378/// # use zng_var::*;
379/// # use zng_layout::unit::*;
380/// # #[property(CONTEXT)] pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode { child.into_node() }
381/// # #[property(EVENT)] pub fn is_pressed(child: impl IntoUiNode, state: impl IntoVar<bool>) -> UiNode { child.into_node() }
382/// # fn main() {
383/// # let _scope = APP.minimal();
384/// # let wgt = zng_app::widget::base::WidgetBase! {
385/// background_color = colors::RED;
386///
387/// when *#is_pressed {
388///     background_color = colors::GREEN;
389/// }
390/// # }; }
391/// ```
392///
393/// ## When Condition
394///
395/// The `when` block defines a condition expression, in the example above this is `*#is_pressed`. The expression can be any Rust expression
396/// that results in a [`bool`] value, you can reference properties in it using the `#` token followed by the property name or path and you
397/// can reference variables in it using the `#{var}` syntax. If a property or var is referenced the `when` block is dynamic, updating all
398/// assigned properties when the expression result changes.
399///
400/// ### Property Reference
401///
402/// The most common `when` expression reference is a property, in the example above the `is_pressed` property is instantiated for the widget
403/// and it controls when the background is set to green. Note that a reference to the value is inserted in the expression
404/// so an extra deref `*` is required. A property can also be referenced with a path, `#properties::is_pressed` also works.
405///
406/// The syntax seen so far is actually a shorthand way to reference the first input of a property, the full syntax is `#is_pressed.0` or
407/// `#is_pressed.state`. You can use the extended syntax to reference inputs of properties with more than one input, the input can be
408/// reference by tuple-style index or by name. Note that if the value it self is a tuple or `struct` you need to use the extended syntax
409/// to reference a member of the value, `#foo.0.0` or `#foo.0.name`. Methods have no ambiguity, `#foo.name()` is the same as `#foo.0.name()`.
410///
411/// Not all properties can be referenced in `when` conditions, only inputs of type `impl IntoVar<T>` and `impl IntoValue<T>` are
412/// allowed, attempting to reference a different kind of input generates a compile error.
413///
414/// ### Variable Reference
415///
416/// Other variable can also be referenced, context variables or any locally declared variable can be referenced. Like with properties
417/// the variable value is inserted in the expression as a reference so you may need to deref in case the var is a simple [`Copy`] value.
418///
419/// ```rust,no_fmt
420/// # use zng_app::{*, widget::{node::*, property, self}};
421/// # use zng_color::*;
422/// # use zng_var::*;
423/// # use zng_layout::unit::*;
424/// #
425/// # #[property(FILL)]
426/// # pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode {
427/// #   let _ = color;
428/// #   child.into_node()
429/// # }
430/// #
431/// context_var! {
432///     pub static FOO_VAR: Vec<&'static str> = vec![];
433///     pub static BAR_VAR: bool = false;
434/// }
435///
436/// # fn main() {
437/// # let _scope = APP.minimal();
438/// # let wgt = widget::base::WidgetBase! {
439/// background_color = colors::RED;
440/// when !*#{BAR_VAR} && #{FOO_VAR}.contains(&"green") {
441///     background_color = colors::GREEN;
442/// }
443/// # };}
444/// ```
445///
446/// ## When Assigns
447///
448/// Inside the `when` block a list of property assigns is expected, most properties can be assigned, but `impl IntoValue<T>` properties cannot,
449/// you also cannot `unset!` in when assigns, a compile time error happens if the property cannot be assigned.
450///
451/// On instantiation a single instance of the property will be generated, the parameters will track the when expression state and update
452/// to the value assigned when it is `true`. When no block is `true` the value assigned to the property outside `when` blocks is used, or the property default value. When more then one block is `true` the *last* one sets the value.
453///
454/// ### Default Values
455///
456/// A when assign can be defined by a property without setting a default value, during instantiation if the property declaration has
457/// a default value it is used, or if the property was later assigned a value it is used as *default*, if it is not possible to generate
458/// a default value the property is not instantiated and the when assign is not used.
459///
460/// The same apply for properties referenced in the condition expression, note that all `is_state` properties have a default value so
461/// it is more rare that a default value is not available. If a condition property cannot be generated the entire when block is ignored.
462///
463/// [`WidgetBase`]: struct@crate::widget::base::WidgetBase
464/// [`WidgetBuilder::push_unset`]: crate::widget::builder::WidgetBuilder::push_unset
465#[macro_export]
466macro_rules! widget_set {
467    (
468        $(#[$skip:meta])*
469        $($invalid:ident)::+ = $($tt:tt)*
470    ) => {
471        compile_error!{
472            "expected `&mut <wgt>;` at the beginning"
473        }
474    };
475    (
476        $(#[$skip:meta])*
477        when = $($invalid:tt)*
478    ) => {
479        compile_error!{
480            "expected `&mut <wgt>;` at the beginning"
481        }
482    };
483    (
484        $wgt_mut:ident;
485        $($tt:tt)*
486    ) => {
487        $crate::widget::widget_set! {
488            &mut *$wgt_mut;
489            $($tt)*
490        }
491    };
492    (
493        $wgt_borrow_mut:expr;
494        $($tt:tt)*
495    ) => {
496        $crate::widget::widget_new! {
497            new {
498                let wgt__ = $wgt_borrow_mut;
499            }
500            build { }
501            set { $($tt)* }
502        }
503    };
504}
505#[doc(inline)]
506pub use widget_set;
507
508/// <span data-del-macro-root></span> Implement a property on the widget to strongly associate it with the widget.
509///
510/// Widget implemented properties can be used on the widget without needing to be imported, they also show in
511/// the widget documentation page. As a general rule only properties that are captured by the widget, or only work with the widget,
512/// or have an special meaning in the widget are implemented like this, standalone properties that can be used in
513/// any widget are not implemented.
514///
515/// Note that you can also implement a property for a widget in the property declaration using the
516/// `impl(Widget)` directive in the [`property`] macro.
517///
518/// # Syntax
519///
520/// The macro syntax is one or more impl declarations, each declaration can have docs followed by the implementation
521/// visibility, usually `pub`, followed by the path to the property function, followed by a parenthesized list of
522/// the function input arguments, terminated by semicolon.
523///
524/// `pub path::to::property(input: impl IntoVar<bool>);`
525///
526/// # Examples
527///
528/// The example below declares a widget and uses this macro to implements the `align` property for the widget.
529///
530/// ```
531/// # fn main() { }
532/// # use zng_app::widget::{*, node::{UiNode, IntoUiNode}, base::WidgetBase};
533/// # use zng_layout::unit::Align;
534/// # use zng_var::IntoVar;
535/// # mod zng { use super::*; pub mod widget { use super::*; #[zng_app::widget::property(LAYOUT)] pub fn align(child: impl IntoUiNode, align: impl IntoVar<Align>) -> UiNode { child.into_node() } } }
536/// #
537/// #[widget($crate::MyWgt)]
538/// pub struct MyWgt(WidgetBase);
539///
540/// impl MyWgt {
541///     widget_impl! {
542///         /// Docs for the property in the widget.
543///         pub zng::widget::align(align: impl IntoVar<Align>);
544///     }
545/// }
546/// ```
547#[macro_export]
548macro_rules! widget_impl {
549    (
550        $(
551            $(#[$attr:meta])*
552            $vis:vis $($property:ident)::+ ($($arg:ident : $arg_ty:ty)*);
553        )+
554    ) => {
555        $(
556            $crate::widget::property_impl! {
557                attrs { $(#[$attr])* }
558                vis { $vis }
559                path { $($property)::* }
560                args { $($arg:$arg_ty),* }
561            }
562        )+
563    }
564}
565#[doc(inline)]
566pub use widget_impl;
567
568zng_unique_id::unique_id_64! {
569    /// Unique ID of a widget.
570    ///
571    /// # Name
572    ///
573    /// IDs are only unique for the same process.
574    /// You can associate a [`name`] with an ID to give it a persistent identifier.
575    ///
576    /// [`name`]: WidgetId::name
577    pub struct WidgetId;
578}
579zng_unique_id::impl_unique_id_name!(WidgetId);
580zng_unique_id::impl_unique_id_fmt!(WidgetId);
581zng_unique_id::impl_unique_id_bytemuck!(WidgetId);
582
583zng_var::impl_from_and_into_var! {
584    /// Calls [`WidgetId::named`].
585    fn from(name: &'static str) -> WidgetId {
586        WidgetId::named(name)
587    }
588    /// Calls [`WidgetId::named`].
589    fn from(name: String) -> WidgetId {
590        WidgetId::named(name)
591    }
592    /// Calls [`WidgetId::named`].
593    fn from(name: Cow<'static, str>) -> WidgetId {
594        WidgetId::named(name)
595    }
596    /// Calls [`WidgetId::named`].
597    fn from(name: char) -> WidgetId {
598        WidgetId::named(name)
599    }
600    /// Calls [`WidgetId::named`].
601    fn from(name: Txt) -> WidgetId {
602        WidgetId::named(name)
603    }
604    fn from(id: WidgetId) -> zng_view_api::access::AccessNodeId {
605        zng_view_api::access::AccessNodeId(id.get())
606    }
607
608    fn from(some: WidgetId) -> Option<WidgetId>;
609}
610impl serde::Serialize for WidgetId {
611    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
612    where
613        S: serde::Serializer,
614    {
615        let name = self.name();
616        if name.is_empty() {
617            use serde::ser::Error;
618            return Err(S::Error::custom("cannot serialize unnamed `WidgetId`"));
619        }
620        name.serialize(serializer)
621    }
622}
623impl<'de> serde::Deserialize<'de> for WidgetId {
624    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
625    where
626        D: serde::Deserializer<'de>,
627    {
628        let name = Txt::deserialize(deserializer)?;
629        Ok(WidgetId::named(name))
630    }
631}
632
633/// Defines how widget update requests inside [`WIDGET::with_context`] are handled.
634#[derive(Debug, Clone, Copy, PartialEq, Eq)]
635pub enum WidgetUpdateMode {
636    /// All updates flagged during the closure call are discarded, previous pending
637    /// requests are retained.
638    ///
639    /// This mode is used by [`UiNodeOp::Measure`].
640    ///
641    /// [`UiNodeOp::Measure`]: crate::widget::node::UiNodeOp::Measure
642    Ignore,
643    /// All updates flagged after the closure call are retained and propagate to the parent widget flags.
644    ///
645    /// This is the mode is used for all [`UiNodeOp`] delegation, except measure.
646    ///
647    /// [`UiNodeOp`]: crate::widget::node::UiNodeOp
648    Bubble,
649}
650
651/// Current context widget.
652///
653/// # Panics
654///
655/// Most of the methods on this service panic if not called inside a widget context.
656pub struct WIDGET;
657impl WIDGET {
658    /// Returns `true` if called inside a widget.
659    pub fn is_in_widget(&self) -> bool {
660        !WIDGET_CTX.is_default()
661    }
662
663    /// Get the widget ID, if called inside a widget.
664    pub fn try_id(&self) -> Option<WidgetId> {
665        if self.is_in_widget() { Some(WIDGET_CTX.get().id) } else { None }
666    }
667
668    /// Gets a text with detailed path to the current widget.
669    ///
670    /// This can be used to quickly identify the current widget during debug, the path printout will contain
671    /// the widget types if the inspector metadata is found for the widget.
672    ///
673    /// This method does not panic if called outside of a widget.
674    pub fn trace_path(&self) -> Txt {
675        if let Some(w_id) = WINDOW.try_id() {
676            if let Some(id) = self.try_id() {
677                let tree = WINDOW.info();
678                if let Some(wgt) = tree.get(id) {
679                    wgt.trace_path()
680                } else {
681                    formatx!("{w_id:?}//<no-info>/{id:?}")
682                }
683            } else {
684                formatx!("{w_id:?}//<no-widget>")
685            }
686        } else if let Some(id) = self.try_id() {
687            formatx!("<no-window>//{id:?}")
688        } else {
689            Txt::from_str("<no-widget>")
690        }
691    }
692
693    /// Gets a text with a detailed widget id.
694    ///
695    /// This can be used to quickly identify the current widget during debug, the printout will contain the widget
696    /// type if the inspector metadata is found for the widget.
697    ///
698    /// This method does not panic if called outside of a widget.
699    pub fn trace_id(&self) -> Txt {
700        if let Some(id) = self.try_id() {
701            if WINDOW.try_id().is_some() {
702                let tree = WINDOW.info();
703                if let Some(wgt) = tree.get(id) {
704                    wgt.trace_id()
705                } else {
706                    formatx!("{id:?}")
707                }
708            } else {
709                formatx!("{id:?}")
710            }
711        } else {
712            Txt::from("<no-widget>")
713        }
714    }
715
716    /// Get the widget ID.
717    pub fn id(&self) -> WidgetId {
718        WIDGET_CTX.get().id
719    }
720
721    /// Gets the widget info.
722    pub fn info(&self) -> WidgetInfo {
723        WINDOW.info().get(WIDGET.id()).expect("widget info not init")
724    }
725
726    /// Widget bounds, updated every layout.
727    pub fn bounds(&self) -> WidgetBoundsInfo {
728        WIDGET_CTX.get().bounds.lock().clone()
729    }
730
731    /// Widget border, updated every layout.
732    pub fn border(&self) -> WidgetBorderInfo {
733        WIDGET_CTX.get().border.lock().clone()
734    }
735
736    /// Gets the parent widget or `None` if is root.
737    ///
738    /// Panics if not called inside a widget.
739    pub fn parent_id(&self) -> Option<WidgetId> {
740        WIDGET_CTX.get().parent_id.load(Relaxed)
741    }
742
743    /// Schedule an [`UpdateOp`] for the current widget.
744    pub fn update_op(&self, op: UpdateOp) -> &Self {
745        match op {
746            UpdateOp::Update => self.update(),
747            UpdateOp::Info => self.update_info(),
748            UpdateOp::Layout => self.layout(),
749            UpdateOp::Render => self.render(),
750            UpdateOp::RenderUpdate => self.render_update(),
751        }
752    }
753
754    fn update_impl(&self, flag: UpdateFlags) -> &Self {
755        let _ = WIDGET_CTX.get().flags.fetch_update(Relaxed, Relaxed, |mut f| {
756            if !f.contains(flag) {
757                f.insert(flag);
758                Some(f)
759            } else {
760                None
761            }
762        });
763        self
764    }
765
766    /// Schedule an update for the current widget.
767    ///
768    /// After the current update the app-extensions, parent window and widgets will update again.
769    pub fn update(&self) -> &Self {
770        UpdatesTrace::log_update();
771        self.update_impl(UpdateFlags::UPDATE)
772    }
773
774    /// Schedule an info rebuild for the current widget.
775    ///
776    /// After all requested updates apply the parent window and widgets will re-build the info tree.
777    pub fn update_info(&self) -> &Self {
778        UpdatesTrace::log_info();
779        self.update_impl(UpdateFlags::INFO)
780    }
781
782    /// Schedule a re-layout for the current widget.
783    ///
784    /// After all requested updates apply the parent window and widgets will re-layout.
785    pub fn layout(&self) -> &Self {
786        UpdatesTrace::log_layout();
787        self.update_impl(UpdateFlags::LAYOUT)
788    }
789
790    /// Schedule a re-render for the current widget.
791    ///
792    /// After all requested updates and layouts apply the parent window and widgets will re-render.
793    ///
794    /// This also overrides any pending [`render_update`] request.
795    ///
796    /// [`render_update`]: Self::render_update
797    pub fn render(&self) -> &Self {
798        UpdatesTrace::log_render();
799        self.update_impl(UpdateFlags::RENDER)
800    }
801
802    /// Schedule a frame update for the current widget.
803    ///
804    /// After all requested updates and layouts apply the parent window and widgets will update the frame.
805    ///
806    /// This request is supplanted by any [`render`] request.
807    ///
808    /// [`render`]: Self::render
809    pub fn render_update(&self) -> &Self {
810        UpdatesTrace::log_render();
811        self.update_impl(UpdateFlags::RENDER_UPDATE)
812    }
813
814    /// Flags the widget to re-init after the current update returns.
815    ///
816    /// The widget responds to this request differently depending on the node method that calls it:
817    ///
818    /// * [`UiNode::init`] and [`UiNode::deinit`]: Request is ignored, removed.
819    /// * [`UiNode::event`]: If the widget is pending a reinit, it is reinited first, then the event is propagated to child nodes.
820    ///   If a reinit is requested during event handling the widget is reinited immediately after the event handler.
821    /// * [`UiNode::update`]: If the widget is pending a reinit, it is reinited and the update ignored.
822    ///   If a reinit is requested during update the widget is reinited immediately after the update.
823    /// * Other methods: Reinit request is flagged and an [`UiNode::update`] is requested for the widget.
824    ///
825    /// [`UiNode::init`]: crate::widget::node::UiNode::init
826    /// [`UiNode::deinit`]: crate::widget::node::UiNode::deinit
827    /// [`UiNode::event`]: crate::widget::node::UiNode::event
828    /// [`UiNode::update`]: crate::widget::node::UiNode::update
829    pub fn reinit(&self) {
830        let _ = WIDGET_CTX.get().flags.fetch_update(Relaxed, Relaxed, |mut f| {
831            if !f.contains(UpdateFlags::REINIT) {
832                f.insert(UpdateFlags::REINIT);
833                Some(f)
834            } else {
835                None
836            }
837        });
838    }
839
840    /// Calls `f` with a read lock on the current widget state map.
841    pub fn with_state<R>(&self, f: impl FnOnce(StateMapRef<WIDGET>) -> R) -> R {
842        f(WIDGET_CTX.get().state.read().borrow())
843    }
844
845    /// Calls `f` with a write lock on the current widget state map.
846    pub fn with_state_mut<R>(&self, f: impl FnOnce(StateMapMut<WIDGET>) -> R) -> R {
847        f(WIDGET_CTX.get().state.write().borrow_mut())
848    }
849
850    /// Get the widget state `id`, if it is set.
851    pub fn get_state<T: StateValue + Clone>(&self, id: impl Into<StateId<T>>) -> Option<T> {
852        let id = id.into();
853        self.with_state(|s| s.get_clone(id))
854    }
855
856    /// Require the widget state `id`.
857    ///
858    /// Panics if the `id` is not set.
859    pub fn req_state<T: StateValue + Clone>(&self, id: impl Into<StateId<T>>) -> T {
860        let id = id.into();
861        self.with_state(|s| s.req(id).clone())
862    }
863
864    /// Set the widget state `id` to `value`.
865    ///
866    /// Returns the previous set value.
867    pub fn set_state<T: StateValue>(&self, id: impl Into<StateId<T>>, value: impl Into<T>) -> Option<T> {
868        let id = id.into();
869        let value = value.into();
870        self.with_state_mut(|mut s| s.set(id, value))
871    }
872
873    /// Sets the widget state `id` without value.
874    ///
875    /// Returns if the state `id` was already flagged.
876    pub fn flag_state(&self, id: impl Into<StateId<()>>) -> bool {
877        let id = id.into();
878        self.with_state_mut(|mut s| s.flag(id))
879    }
880
881    /// Calls `init` and sets `id` if it is not already set in the widget.
882    pub fn init_state<T: StateValue>(&self, id: impl Into<StateId<T>>, init: impl FnOnce() -> T) {
883        let id = id.into();
884        self.with_state_mut(|mut s| {
885            s.entry(id).or_insert_with(init);
886        });
887    }
888
889    /// Sets the `id` to the default value if it is not already set.
890    pub fn init_state_default<T: StateValue + Default>(&self, id: impl Into<StateId<T>>) {
891        self.init_state(id.into(), Default::default)
892    }
893
894    /// Returns `true` if the `id` is set or flagged in the widget.
895    pub fn contains_state<T: StateValue>(&self, id: impl Into<StateId<T>>) -> bool {
896        let id = id.into();
897        self.with_state(|s| s.contains(id))
898    }
899
900    /// Subscribe to receive [`UpdateOp`] when the `var` changes.
901    pub fn sub_var_op(&self, op: UpdateOp, var: &AnyVar) -> &Self {
902        let w = WIDGET_CTX.get();
903        let s = var.subscribe(op, w.id);
904
905        // function to avoid generics code bloat
906        fn push(w: Arc<WidgetCtxData>, s: VarHandle) {
907            if WIDGET_HANDLES_CTX.is_default() {
908                w.handles.var_handles.lock().push(s);
909            } else {
910                WIDGET_HANDLES_CTX.get().var_handles.lock().push(s);
911            }
912        }
913        push(w, s);
914
915        self
916    }
917
918    /// Subscribe to receive [`UpdateOp`] when the `var` changes and `predicate` approves the new value.
919    ///
920    /// Note that the `predicate` does not run in the widget context, it runs on the app context.
921    pub fn sub_var_op_when<T: VarValue>(
922        &self,
923        op: UpdateOp,
924        var: &Var<T>,
925        predicate: impl Fn(&T) -> bool + Send + Sync + 'static,
926    ) -> &Self {
927        let w = WIDGET_CTX.get();
928        let s = var.subscribe_when(op, w.id, predicate);
929
930        // function to avoid generics code bloat
931        fn push(w: Arc<WidgetCtxData>, s: VarHandle) {
932            if WIDGET_HANDLES_CTX.is_default() {
933                w.handles.var_handles.lock().push(s);
934            } else {
935                WIDGET_HANDLES_CTX.get().var_handles.lock().push(s);
936            }
937        }
938        push(w, s);
939
940        self
941    }
942
943    /// Subscribe to receive updates when the `var` changes.
944    pub fn sub_var(&self, var: &AnyVar) -> &Self {
945        self.sub_var_op(UpdateOp::Update, var)
946    }
947    /// Subscribe to receive updates when the `var` changes and the `predicate` approves the new value.
948    ///
949    /// Note that the `predicate` does not run in the widget context, it runs on the app context.
950    pub fn sub_var_when<T: VarValue>(&self, var: &Var<T>, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> &Self {
951        self.sub_var_op_when(UpdateOp::Update, var, predicate)
952    }
953
954    /// Subscribe to receive info rebuild requests when the `var` changes.
955    pub fn sub_var_info(&self, var: &AnyVar) -> &Self {
956        self.sub_var_op(UpdateOp::Info, var)
957    }
958    /// Subscribe to receive info rebuild requests when the `var` changes and the `predicate` approves the new value.
959    ///
960    /// Note that the `predicate` does not run in the widget context, it runs on the app context.
961    pub fn sub_var_info_when<T: VarValue>(&self, var: &Var<T>, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> &Self {
962        self.sub_var_op_when(UpdateOp::Info, var, predicate)
963    }
964
965    /// Subscribe to receive layout requests when the `var` changes.
966    pub fn sub_var_layout(&self, var: &AnyVar) -> &Self {
967        self.sub_var_op(UpdateOp::Layout, var)
968    }
969    /// Subscribe to receive layout requests when the `var` changes and the `predicate` approves the new value.
970    ///
971    /// Note that the `predicate` does not run in the widget context, it runs on the app context.
972    pub fn sub_var_layout_when<T: VarValue>(&self, var: &Var<T>, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> &Self {
973        self.sub_var_op_when(UpdateOp::Layout, var, predicate)
974    }
975
976    /// Subscribe to receive render requests when the `var` changes.
977    pub fn sub_var_render(&self, var: &AnyVar) -> &Self {
978        self.sub_var_op(UpdateOp::Render, var)
979    }
980    /// Subscribe to receive render requests when the `var` changes and the `predicate` approves the new value.
981    ///
982    /// Note that the `predicate` does not run in the widget context, it runs on the app context.
983    pub fn sub_var_render_when<T: VarValue>(&self, var: &Var<T>, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> &Self {
984        self.sub_var_op_when(UpdateOp::Render, var, predicate)
985    }
986
987    /// Subscribe to receive render update requests when the `var` changes.
988    pub fn sub_var_render_update(&self, var: &AnyVar) -> &Self {
989        self.sub_var_op(UpdateOp::RenderUpdate, var)
990    }
991    /// Subscribe to receive render update requests when the `var` changes and the `predicate` approves the new value.
992    ///
993    /// Note that the `predicate` does not run in the widget context, it runs on the app context.
994    pub fn sub_var_render_update_when<T: VarValue>(&self, var: &Var<T>, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> &Self {
995        self.sub_var_op_when(UpdateOp::RenderUpdate, var, predicate)
996    }
997
998    /// Subscribe to receive events from `event` when the event targets this widget.
999    pub fn sub_event<A: EventArgs>(&self, event: &Event<A>) -> &Self {
1000        let w = WIDGET_CTX.get();
1001        let s = event.subscribe(w.id);
1002
1003        // function to avoid generics code bloat
1004        fn push(w: Arc<WidgetCtxData>, s: EventHandle) {
1005            if WIDGET_HANDLES_CTX.is_default() {
1006                w.handles.event_handles.lock().push(s);
1007            } else {
1008                WIDGET_HANDLES_CTX.get().event_handles.lock().push(s);
1009            }
1010        }
1011        push(w, s);
1012
1013        self
1014    }
1015
1016    /// Hold the event `handle` until the widget is deinited.
1017    pub fn push_event_handle(&self, handle: EventHandle) {
1018        if WIDGET_HANDLES_CTX.is_default() {
1019            WIDGET_CTX.get().handles.event_handles.lock().push(handle);
1020        } else {
1021            WIDGET_HANDLES_CTX.get().event_handles.lock().push(handle);
1022        }
1023    }
1024
1025    /// Hold the event `handles` until the widget is deinited.
1026    pub fn push_event_handles(&self, handles: EventHandles) {
1027        if WIDGET_HANDLES_CTX.is_default() {
1028            WIDGET_CTX.get().handles.event_handles.lock().extend(handles);
1029        } else {
1030            WIDGET_HANDLES_CTX.get().event_handles.lock().extend(handles);
1031        }
1032    }
1033
1034    /// Hold the var `handle` until the widget is deinited.
1035    pub fn push_var_handle(&self, handle: VarHandle) {
1036        if WIDGET_HANDLES_CTX.is_default() {
1037            WIDGET_CTX.get().handles.var_handles.lock().push(handle);
1038        } else {
1039            WIDGET_HANDLES_CTX.get().var_handles.lock().push(handle);
1040        }
1041    }
1042
1043    /// Hold the var `handles` until the widget is deinited.
1044    pub fn push_var_handles(&self, handles: VarHandles) {
1045        if WIDGET_HANDLES_CTX.is_default() {
1046            WIDGET_CTX.get().handles.var_handles.lock().extend(handles);
1047        } else {
1048            WIDGET_HANDLES_CTX.get().var_handles.lock().extend(handles);
1049        }
1050    }
1051
1052    /// Transform point in the window space to the widget inner bounds.
1053    pub fn win_point_to_wgt(&self, point: DipPoint) -> Option<PxPoint> {
1054        let wgt_info = WIDGET.info();
1055        wgt_info
1056            .inner_transform()
1057            .inverse()?
1058            .transform_point(point.to_px(wgt_info.tree().scale_factor()))
1059    }
1060
1061    /// Gets the transform from the window space to the widget inner bounds.
1062    pub fn win_to_wgt(&self) -> Option<PxTransform> {
1063        WIDGET.info().inner_transform().inverse()
1064    }
1065
1066    /// Calls `f` with an override target for var and event subscription handles.
1067    ///
1068    /// By default when vars and events are subscribed using the methods of this service the
1069    /// subscriptions live until the widget is deinited. This method intersects these
1070    /// subscriptions, registering then in `handles` instead.
1071    pub fn with_handles<R>(&self, handles: &mut WidgetHandlesCtx, f: impl FnOnce() -> R) -> R {
1072        WIDGET_HANDLES_CTX.with_context(&mut handles.0, f)
1073    }
1074
1075    /// Calls `f` while the widget is set to `ctx`.
1076    ///
1077    /// If `update_mode` is [`WidgetUpdateMode::Bubble`] the update flags requested for the `ctx` after `f` will be copied to the
1078    /// caller widget context, otherwise they are ignored.
1079    ///
1080    /// This method can be used to manually define a widget context, note that widgets already define their own context.
1081    #[inline(always)]
1082    pub fn with_context<R>(&self, ctx: &mut WidgetCtx, update_mode: WidgetUpdateMode, f: impl FnOnce() -> R) -> R {
1083        struct Restore<'a> {
1084            update_mode: WidgetUpdateMode,
1085            parent_id: Option<WidgetId>,
1086            prev_flags: UpdateFlags,
1087            ctx: &'a mut WidgetCtx,
1088        }
1089        impl<'a> Restore<'a> {
1090            fn new(ctx: &'a mut WidgetCtx, update_mode: WidgetUpdateMode) -> Self {
1091                let parent_id = WIDGET.try_id();
1092
1093                if let Some(ctx) = ctx.0.as_mut() {
1094                    ctx.parent_id.store(parent_id, Relaxed);
1095                } else {
1096                    unreachable!()
1097                }
1098
1099                let prev_flags = match update_mode {
1100                    WidgetUpdateMode::Ignore => ctx.0.as_mut().unwrap().flags.load(Relaxed),
1101                    WidgetUpdateMode::Bubble => UpdateFlags::empty(),
1102                };
1103
1104                Self {
1105                    update_mode,
1106                    parent_id,
1107                    prev_flags,
1108                    ctx,
1109                }
1110            }
1111        }
1112        impl<'a> Drop for Restore<'a> {
1113            fn drop(&mut self) {
1114                let ctx = match self.ctx.0.as_mut() {
1115                    Some(c) => c,
1116                    None => return, // can happen in case of panic
1117                };
1118
1119                match self.update_mode {
1120                    WidgetUpdateMode::Ignore => {
1121                        ctx.flags.store(self.prev_flags, Relaxed);
1122                    }
1123                    WidgetUpdateMode::Bubble => {
1124                        let wgt_flags = ctx.flags.load(Relaxed);
1125
1126                        if let Some(parent) = self.parent_id.map(|_| WIDGET_CTX.get()) {
1127                            let propagate = wgt_flags
1128                                & (UpdateFlags::UPDATE
1129                                    | UpdateFlags::INFO
1130                                    | UpdateFlags::LAYOUT
1131                                    | UpdateFlags::RENDER
1132                                    | UpdateFlags::RENDER_UPDATE);
1133
1134                            let _ = parent.flags.fetch_update(Relaxed, Relaxed, |mut u| {
1135                                if !u.contains(propagate) {
1136                                    u.insert(propagate);
1137                                    Some(u)
1138                                } else {
1139                                    None
1140                                }
1141                            });
1142                            ctx.parent_id.store(None, Relaxed);
1143                        } else if let Some(window_id) = WINDOW.try_id() {
1144                            // is at root, register `UPDATES`
1145                            UPDATES.update_flags_root(wgt_flags, window_id, ctx.id);
1146                            // some builders don't clear the root widget flags like they do for other widgets.
1147                            ctx.flags.store(wgt_flags & UpdateFlags::REINIT, Relaxed);
1148                        } else {
1149                            // used outside window
1150                            UPDATES.update_flags(wgt_flags, ctx.id);
1151                            ctx.flags.store(UpdateFlags::empty(), Relaxed);
1152                        }
1153                    }
1154                }
1155            }
1156        }
1157
1158        let mut _restore = Restore::new(ctx, update_mode);
1159        WIDGET_CTX.with_context(&mut _restore.ctx.0, f)
1160    }
1161    /// Calls `f` while no widget is available in the context.
1162    #[inline(always)]
1163    pub fn with_no_context<R>(&self, f: impl FnOnce() -> R) -> R {
1164        WIDGET_CTX.with_default(f)
1165    }
1166
1167    #[cfg(any(test, doc, feature = "test_util"))]
1168    pub(crate) fn test_root_updates(&self) {
1169        let ctx = WIDGET_CTX.get();
1170        // is at root, register `UPDATES`
1171        UPDATES.update_flags_root(ctx.flags.load(Relaxed), WINDOW.id(), ctx.id);
1172        // some builders don't clear the root widget flags like they do for other widgets.
1173        ctx.flags.store(UpdateFlags::empty(), Relaxed);
1174    }
1175
1176    pub(crate) fn layout_is_pending(&self, layout_widgets: &LayoutUpdates) -> bool {
1177        let ctx = WIDGET_CTX.get();
1178        ctx.flags.load(Relaxed).contains(UpdateFlags::LAYOUT) || layout_widgets.delivery_list().enter_widget(ctx.id)
1179    }
1180
1181    /// Remove update flag and returns if it intersected.
1182    pub(crate) fn take_update(&self, flag: UpdateFlags) -> bool {
1183        let mut r = false;
1184        let _ = WIDGET_CTX.get().flags.fetch_update(Relaxed, Relaxed, |mut f| {
1185            if f.intersects(flag) {
1186                r = true;
1187                f.remove(flag);
1188                Some(f)
1189            } else {
1190                None
1191            }
1192        });
1193        r
1194    }
1195
1196    /// Current pending updates.
1197    #[cfg(debug_assertions)]
1198    pub(crate) fn pending_update(&self) -> UpdateFlags {
1199        WIDGET_CTX.get().flags.load(Relaxed)
1200    }
1201
1202    /// Remove the render reuse range if render was not invalidated on this widget.
1203    pub(crate) fn take_render_reuse(&self, render_widgets: &RenderUpdates, render_update_widgets: &RenderUpdates) -> Option<ReuseRange> {
1204        let ctx = WIDGET_CTX.get();
1205        let mut try_reuse = true;
1206
1207        // take RENDER, RENDER_UPDATE
1208        let _ = ctx.flags.fetch_update(Relaxed, Relaxed, |mut f| {
1209            if f.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE) {
1210                try_reuse = false;
1211                f.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1212                Some(f)
1213            } else {
1214                None
1215            }
1216        });
1217
1218        if try_reuse && !render_widgets.delivery_list().enter_widget(ctx.id) && !render_update_widgets.delivery_list().enter_widget(ctx.id)
1219        {
1220            ctx.render_reuse.lock().take()
1221        } else {
1222            None
1223        }
1224    }
1225
1226    pub(crate) fn set_render_reuse(&self, range: Option<ReuseRange>) {
1227        *WIDGET_CTX.get().render_reuse.lock() = range;
1228    }
1229}
1230
1231context_local! {
1232    pub(crate) static WIDGET_CTX: WidgetCtxData = WidgetCtxData::no_context();
1233    static WIDGET_HANDLES_CTX: WidgetHandlesCtxData = WidgetHandlesCtxData::dummy();
1234}
1235
1236/// Defines the backing data of [`WIDGET`].
1237///
1238/// Each widget owns this data and calls [`WIDGET.with_context`] to delegate to it's child node.
1239///
1240/// [`WIDGET.with_context`]: WIDGET::with_context
1241pub struct WidgetCtx(Option<Arc<WidgetCtxData>>);
1242impl WidgetCtx {
1243    /// New widget context.
1244    pub fn new(id: WidgetId) -> Self {
1245        Self(Some(Arc::new(WidgetCtxData {
1246            parent_id: Atomic::new(None),
1247            id,
1248            flags: Atomic::new(UpdateFlags::empty()),
1249            state: RwLock::new(OwnedStateMap::default()),
1250            handles: WidgetHandlesCtxData::dummy(),
1251            bounds: Mutex::new(WidgetBoundsInfo::default()),
1252            border: Mutex::new(WidgetBorderInfo::default()),
1253            render_reuse: Mutex::new(None),
1254        })))
1255    }
1256
1257    /// Drops all var and event handles, clears all state.
1258    ///
1259    /// If `retain_state` is enabled the state will not be cleared and can still read.
1260    pub fn deinit(&mut self, retain_state: bool) {
1261        let ctx = self.0.as_mut().unwrap();
1262        ctx.handles.var_handles.lock().clear();
1263        ctx.handles.event_handles.lock().clear();
1264        ctx.flags.store(UpdateFlags::empty(), Relaxed);
1265        *ctx.render_reuse.lock() = None;
1266
1267        if !retain_state {
1268            ctx.state.write().clear();
1269        }
1270    }
1271
1272    /// Returns `true` if reinit was requested for the widget.
1273    ///
1274    /// Note that widget implementers must use [`take_reinit`] to fulfill the request.
1275    ///
1276    /// [`take_reinit`]: Self::take_reinit
1277    pub fn is_pending_reinit(&self) -> bool {
1278        self.0.as_ref().unwrap().flags.load(Relaxed).contains(UpdateFlags::REINIT)
1279    }
1280
1281    /// Returns `true` if an [`WIDGET.reinit`] request was made.
1282    ///
1283    /// Unlike other requests, the widget implement must re-init immediately.
1284    ///
1285    /// [`WIDGET.reinit`]: WIDGET::reinit
1286    pub fn take_reinit(&mut self) -> bool {
1287        let ctx = self.0.as_mut().unwrap();
1288
1289        let mut flags = ctx.flags.load(Relaxed);
1290        let r = flags.contains(UpdateFlags::REINIT);
1291        if r {
1292            flags.remove(UpdateFlags::REINIT);
1293            ctx.flags.store(flags, Relaxed);
1294        }
1295
1296        r
1297    }
1298
1299    /// Gets the widget id.
1300    pub fn id(&self) -> WidgetId {
1301        self.0.as_ref().unwrap().id
1302    }
1303    /// Gets the widget bounds.
1304    pub fn bounds(&self) -> WidgetBoundsInfo {
1305        self.0.as_ref().unwrap().bounds.lock().clone()
1306    }
1307
1308    /// Gets the widget borders.
1309    pub fn border(&self) -> WidgetBorderInfo {
1310        self.0.as_ref().unwrap().border.lock().clone()
1311    }
1312
1313    /// Call `f` with an exclusive lock to the widget state.
1314    pub fn with_state<R>(&mut self, f: impl FnOnce(&mut OwnedStateMap<WIDGET>) -> R) -> R {
1315        f(&mut self.0.as_mut().unwrap().state.write())
1316    }
1317
1318    /// Clone a reference to the widget context.
1319    ///
1320    /// This must be used only if the widget implementation is split.
1321    pub fn share(&mut self) -> Self {
1322        Self(self.0.clone())
1323    }
1324}
1325
1326pub(crate) struct WidgetCtxData {
1327    parent_id: Atomic<Option<WidgetId>>,
1328    pub(crate) id: WidgetId,
1329    flags: Atomic<UpdateFlags>,
1330    state: RwLock<OwnedStateMap<WIDGET>>,
1331    handles: WidgetHandlesCtxData,
1332    pub(crate) bounds: Mutex<WidgetBoundsInfo>,
1333    border: Mutex<WidgetBorderInfo>,
1334    render_reuse: Mutex<Option<ReuseRange>>,
1335}
1336impl WidgetCtxData {
1337    #[track_caller]
1338    fn no_context() -> Self {
1339        panic!("no widget in context")
1340    }
1341}
1342
1343struct WidgetHandlesCtxData {
1344    var_handles: Mutex<VarHandles>,
1345    event_handles: Mutex<EventHandles>,
1346}
1347
1348impl WidgetHandlesCtxData {
1349    const fn dummy() -> Self {
1350        Self {
1351            var_handles: Mutex::new(VarHandles::dummy()),
1352            event_handles: Mutex::new(EventHandles::dummy()),
1353        }
1354    }
1355}
1356
1357/// Defines the backing data for [`WIDGET.with_handles`].
1358///
1359/// [`WIDGET.with_handles`]: WIDGET::with_handles
1360pub struct WidgetHandlesCtx(Option<Arc<WidgetHandlesCtxData>>);
1361impl WidgetHandlesCtx {
1362    /// New empty.
1363    pub fn new() -> Self {
1364        Self(Some(Arc::new(WidgetHandlesCtxData::dummy())))
1365    }
1366
1367    /// Drop all handles.
1368    pub fn clear(&mut self) {
1369        let h = self.0.as_ref().unwrap();
1370        h.var_handles.lock().clear();
1371        h.event_handles.lock().clear();
1372    }
1373}
1374impl Default for WidgetHandlesCtx {
1375    fn default() -> Self {
1376        Self::new()
1377    }
1378}
1379
1380/// Extension method to subscribe any widget to a variable.
1381///
1382/// Also see [`WIDGET`] methods for the primary way to subscribe from inside a widget.
1383pub trait AnyVarSubscribe {
1384    /// Register the widget to receive an [`UpdateOp`] when this variable is new.
1385    ///
1386    /// Variables without the [`NEW`] capability return [`VarHandle::dummy`].
1387    ///
1388    /// [`NEW`]: zng_var::VarCapability::NEW
1389    /// [`VarHandle::dummy`]: zng_var::VarHandle
1390    fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle;
1391}
1392impl AnyVarSubscribe for AnyVar {
1393    fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle {
1394        if !self.capabilities().is_const() {
1395            self.hook(move |_| {
1396                UPDATES.update_op(op, widget_id);
1397                true
1398            })
1399        } else {
1400            VarHandle::dummy()
1401        }
1402    }
1403}
1404
1405/// Extension methods to subscribe any widget to a variable or app handlers to a variable.
1406///
1407/// Also see [`WIDGET`] methods for the primary way to subscribe from inside a widget.
1408pub trait VarSubscribe<T: VarValue>: AnyVarSubscribe {
1409    /// Register the widget to receive an [`UpdateOp`] when this variable is new and the `predicate` approves the new value.
1410    ///
1411    /// Variables without the [`NEW`] capability return [`VarHandle::dummy`].
1412    ///
1413    /// [`NEW`]: zng_var::VarCapability::NEW
1414    /// [`VarHandle::dummy`]: zng_var::VarHandle
1415    fn subscribe_when(&self, op: UpdateOp, widget_id: WidgetId, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> VarHandle;
1416
1417    /// Add a preview `handler` that is called every time this variable updates,
1418    /// the handler is called before UI update.
1419    ///
1420    /// Note that the handler runs on the app context, all [`ContextVar<T>`] used inside will have the default value.
1421    ///
1422    /// [`ContextVar<T>`]: zng_var::ContextVar
1423    fn on_pre_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1424
1425    /// Add a `handler` that is called every time this variable updates,
1426    /// the handler is called after UI update.
1427    ///
1428    /// Note that the handler runs on the app context, all [`ContextVar<T>`] used inside will have the default value.
1429    ///
1430    /// [`ContextVar<T>`]: zng_var::ContextVar
1431    fn on_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1432}
1433impl<T: VarValue> AnyVarSubscribe for Var<T> {
1434    fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle {
1435        self.as_any().subscribe(op, widget_id)
1436    }
1437}
1438impl<T: VarValue> VarSubscribe<T> for Var<T> {
1439    fn subscribe_when(&self, op: UpdateOp, widget_id: WidgetId, predicate: impl Fn(&T) -> bool + Send + Sync + 'static) -> VarHandle {
1440        self.hook(move |a| {
1441            if let Some(a) = a.downcast_value::<T>() {
1442                if predicate(a) {
1443                    UPDATES.update_op(op, widget_id);
1444                }
1445                true
1446            } else {
1447                false
1448            }
1449        })
1450    }
1451
1452    fn on_pre_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle {
1453        var_on_new(self, handler, true)
1454    }
1455
1456    fn on_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle {
1457        var_on_new(self, handler, false)
1458    }
1459}
1460
1461/// Extension methods to subscribe app handlers to a response variable.
1462pub trait ResponseVarSubscribe<T: VarValue> {
1463    /// Add a `handler` that is called once when the response is received,
1464    /// the handler is called before all other UI updates.
1465    ///
1466    /// The handler is not called if already [`is_done`], in this case a dummy handle is returned.
1467    ///
1468    /// [`is_done`]: ResponseVar::is_done
1469    fn on_pre_rsp(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1470
1471    /// Add a `handler` that is called once when the response is received,
1472    /// the handler is called after all other UI updates.
1473    ///
1474    /// The handler is not called if already [`is_done`], in this case a dummy handle is returned.
1475    ///
1476    /// [`is_done`]: ResponseVar::is_done
1477    fn on_rsp(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1478}
1479impl<T: VarValue> ResponseVarSubscribe<T> for ResponseVar<T> {
1480    fn on_pre_rsp(&self, mut handler: Handler<OnVarArgs<T>>) -> VarHandle {
1481        if self.is_done() {
1482            return VarHandle::dummy();
1483        }
1484
1485        self.on_pre_new(Box::new(move |args| {
1486            if let zng_var::Response::Done(value) = &args.value {
1487                APP_HANDLER.unsubscribe();
1488                handler(&OnVarArgs::new(value.clone(), args.tags.clone()))
1489            } else {
1490                HandlerResult::Done
1491            }
1492        }))
1493    }
1494
1495    fn on_rsp(&self, mut handler: Handler<OnVarArgs<T>>) -> VarHandle {
1496        if self.is_done() {
1497            return VarHandle::dummy();
1498        }
1499
1500        self.on_new(Box::new(move |args| {
1501            if let zng_var::Response::Done(value) = &args.value {
1502                APP_HANDLER.unsubscribe();
1503                handler(&OnVarArgs::new(value.clone(), args.tags.clone()))
1504            } else {
1505                HandlerResult::Done
1506            }
1507        }))
1508    }
1509}
1510
1511fn var_on_new<T>(var: &Var<T>, handler: Handler<OnVarArgs<T>>, is_preview: bool) -> VarHandle
1512where
1513    T: VarValue,
1514{
1515    if var.capabilities().is_const() {
1516        return VarHandle::dummy();
1517    }
1518
1519    let handler = handler.into_arc();
1520    let (inner_handle_owner, inner_handle) = Handle::new(());
1521    var.hook(move |args| {
1522        if inner_handle_owner.is_dropped() {
1523            return false;
1524        }
1525
1526        let handle = inner_handle.downgrade();
1527        let value = args.value().clone();
1528        let tags: Vec<_> = args.tags().to_vec();
1529
1530        let update_once: Handler<crate::update::UpdateArgs> = Box::new(clmv!(handler, |_| {
1531            APP_HANDLER.unsubscribe(); // once
1532            APP_HANDLER.with(handle.clone_boxed(), is_preview, || {
1533                handler.call(&OnVarArgs::new(value.clone(), tags.clone()))
1534            })
1535        }));
1536
1537        if is_preview {
1538            UPDATES.on_pre_update(update_once).perm();
1539        } else {
1540            UPDATES.on_update(update_once).perm();
1541        }
1542        true
1543    })
1544}
1545
1546/// Arguments for a var event handler.
1547#[non_exhaustive]
1548pub struct OnVarArgs<T: VarValue> {
1549    /// The new value.
1550    pub value: T,
1551    /// Custom tag objects that where set when the value was modified.
1552    pub tags: Vec<BoxAnyVarValue>,
1553}
1554impl<T: VarValue> OnVarArgs<T> {
1555    /// New from value and custom modify tags.
1556    pub fn new(value: T, tags: Vec<BoxAnyVarValue>) -> Self {
1557        Self { value, tags }
1558    }
1559
1560    /// Reference all custom tag values of type `T`.
1561    pub fn downcast_tags<Ta: VarValue>(&self) -> impl Iterator<Item = &Ta> + '_ {
1562        self.tags.iter().filter_map(|t| (*t).downcast_ref::<Ta>())
1563    }
1564}
1565impl<T: VarValue> Clone for OnVarArgs<T> {
1566    fn clone(&self) -> Self {
1567        Self {
1568            value: self.value.clone(),
1569            tags: self.tags.iter().map(|t| (*t).clone_boxed()).collect(),
1570        }
1571    }
1572}
1573
1574/// Extension methods to layout var values.
1575pub trait VarLayout<T: VarValue> {
1576    /// Compute the pixel value in the current [`LAYOUT`] context.
1577    ///
1578    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1579    fn layout(&self) -> T::Px
1580    where
1581        T: Layout2d;
1582
1583    /// Compute the pixel value in the current [`LAYOUT`] context with `default`.
1584    ///
1585    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1586    fn layout_dft(&self, default: T::Px) -> T::Px
1587    where
1588        T: Layout2d;
1589
1590    /// Compute the pixel value in the current [`LAYOUT`] context ***x*** axis.
1591    ///
1592    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1593    fn layout_x(&self) -> Px
1594    where
1595        T: Layout1d;
1596
1597    /// Compute the pixel value in the current [`LAYOUT`] context ***y*** axis.
1598    ///
1599    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1600    fn layout_y(&self) -> Px
1601    where
1602        T: Layout1d;
1603
1604    /// Compute the pixel value in the current [`LAYOUT`] context ***z*** axis.
1605    ///
1606    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1607    fn layout_z(&self) -> Px
1608    where
1609        T: Layout1d;
1610
1611    /// Compute the pixel value in the current [`LAYOUT`] context ***x*** axis with `default`.
1612    ///
1613    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1614    fn layout_dft_x(&self, default: Px) -> Px
1615    where
1616        T: Layout1d;
1617
1618    /// Compute the pixel value in the current [`LAYOUT`] context ***y*** axis with `default`.
1619    ///
1620    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1621    fn layout_dft_y(&self, default: Px) -> Px
1622    where
1623        T: Layout1d;
1624
1625    /// Compute the pixel value in the current [`LAYOUT`] context ***z*** axis with `default`.
1626    ///
1627    /// [`LAYOUT`]: zng_layout::context::LAYOUT
1628    fn layout_dft_z(&self, default: Px) -> Px
1629    where
1630        T: Layout1d;
1631}
1632impl<T: VarValue> VarLayout<T> for Var<T> {
1633    fn layout(&self) -> <T>::Px
1634    where
1635        T: Layout2d,
1636    {
1637        self.with(|s| s.layout())
1638    }
1639
1640    fn layout_dft(&self, default: <T>::Px) -> <T>::Px
1641    where
1642        T: Layout2d,
1643    {
1644        self.with(move |s| s.layout_dft(default))
1645    }
1646
1647    fn layout_x(&self) -> Px
1648    where
1649        T: Layout1d,
1650    {
1651        self.with(|s| s.layout_x())
1652    }
1653
1654    fn layout_y(&self) -> Px
1655    where
1656        T: Layout1d,
1657    {
1658        self.with(|s| s.layout_y())
1659    }
1660
1661    fn layout_z(&self) -> Px
1662    where
1663        T: Layout1d,
1664    {
1665        self.with(|s| s.layout_z())
1666    }
1667
1668    fn layout_dft_x(&self, default: Px) -> Px
1669    where
1670        T: Layout1d,
1671    {
1672        self.with(move |s| s.layout_dft_x(default))
1673    }
1674
1675    fn layout_dft_y(&self, default: Px) -> Px
1676    where
1677        T: Layout1d,
1678    {
1679        self.with(move |s| s.layout_dft_y(default))
1680    }
1681
1682    fn layout_dft_z(&self, default: Px) -> Px
1683    where
1684        T: Layout1d,
1685    {
1686        self.with(move |s| s.layout_dft_z(default))
1687    }
1688}
1689
1690/// Integrate [`UiTask`] with widget updates.
1691pub trait UiTaskWidget<R> {
1692    /// Create a UI bound future executor.
1693    ///
1694    /// The `task` is inert and must be polled using [`update`] to start, and it must be polled every
1695    /// [`UiNode::update`] after that, in widgets the `target` can be set so that the update requests are received.
1696    ///
1697    /// [`update`]: UiTask::update
1698    /// [`UiNode::update`]: crate::widget::node::UiNode::update
1699    /// [`UiNode::info`]: crate::widget::node::UiNode::info
1700    fn new<F>(target: Option<WidgetId>, task: impl IntoFuture<IntoFuture = F>) -> Self
1701    where
1702        F: Future<Output = R> + Send + 'static;
1703
1704    /// Like [`new`], from an already boxed and pinned future.
1705    ///
1706    /// [`new`]: UiTaskWidget::new
1707    fn new_boxed(target: Option<WidgetId>, task: Pin<Box<dyn Future<Output = R> + Send + 'static>>) -> Self;
1708}
1709impl<R> UiTaskWidget<R> for UiTask<R> {
1710    fn new<F>(target: Option<WidgetId>, task: impl IntoFuture<IntoFuture = F>) -> Self
1711    where
1712        F: Future<Output = R> + Send + 'static,
1713    {
1714        UiTask::new_raw(UPDATES.waker(target), task)
1715    }
1716
1717    fn new_boxed(target: Option<WidgetId>, task: Pin<Box<dyn Future<Output = R> + Send + 'static>>) -> Self {
1718        UiTask::new_raw_boxed(UPDATES.waker(target), task)
1719    }
1720}