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 std::{
15 borrow::Cow,
16 pin::Pin,
17 sync::{Arc, atomic::Ordering::Relaxed},
18};
19use zng_app_context::context_local;
20use zng_clone_move::clmv;
21use zng_handle::Handle;
22use zng_layout::unit::{DipPoint, DipToPx as _, Layout1d, Layout2d, Px, PxPoint, PxTransform};
23use zng_state_map::{OwnedStateMap, StateId, StateMapMut, StateMapRef, StateValue};
24use zng_task::UiTask;
25use zng_task::parking_lot::{Mutex, RwLock};
26use zng_txt::{Txt, formatx};
27use zng_var::{AnyVar, BoxAnyVarValue, ResponseVar, VARS, Var, VarHandle, VarHandles, VarHookArgs, VarUpdateId, VarValue};
28use zng_view_api::display_list::ReuseRange;
29
30use crate::{
31 event::{AnyEvent, Event, EventArgs},
32 handler::{APP_HANDLER, AppWeakHandle, Handler, 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/// # Attributes
464///
465/// Property assigns can be annotated with attributes, the `cfg` and lint attributes (`allow`, `warn`, etc.) are copied to the expanded
466/// code. Other attributes are transferred to a special token stream with metadata about the property assign, with the expectation they
467/// are custom proc-macro attributes that operate on property assigns.
468///
469/// An example of custom attribute is `#[easing]`, it provides animation transitions between the default and `when` assigns. Custom
470/// attribute implementers must parse data in a specific format, see the `struct PropertyAssignAttributeData` source code in the
471/// `zng-app-proc-macros` crate.
472///
473/// [`WidgetBase`]: struct@crate::widget::base::WidgetBase
474/// [`WidgetBuilder::push_unset`]: crate::widget::builder::WidgetBuilder::push_unset
475#[macro_export]
476macro_rules! widget_set {
477 (
478 $(#[$skip:meta])*
479 $($invalid:ident)::+ = $($tt:tt)*
480 ) => {
481 compile_error!{
482 "expected `&mut <wgt>;` at the beginning"
483 }
484 };
485 (
486 $(#[$skip:meta])*
487 when = $($invalid:tt)*
488 ) => {
489 compile_error!{
490 "expected `&mut <wgt>;` at the beginning"
491 }
492 };
493 (
494 $wgt_mut:ident;
495 $($tt:tt)*
496 ) => {
497 $crate::widget::widget_set! {
498 &mut *$wgt_mut;
499 $($tt)*
500 }
501 };
502 (
503 $wgt_borrow_mut:expr;
504 $($tt:tt)*
505 ) => {
506 $crate::widget::widget_new! {
507 new {
508 let wgt__ = $wgt_borrow_mut;
509 }
510 build { }
511 set { $($tt)* }
512 }
513 };
514}
515#[doc(inline)]
516pub use widget_set;
517
518/// <span data-del-macro-root></span> Implement a property on the widget to strongly associate it with the widget.
519///
520/// Widget implemented properties can be used on the widget without needing to be imported, they also show in
521/// the widget documentation page. As a general rule only properties that are captured by the widget, or only work with the widget,
522/// or have an special meaning in the widget are implemented like this, standalone properties that can be used in
523/// any widget are not implemented.
524///
525/// Note that you can also implement a property for a widget in the property declaration using the
526/// `impl(Widget)` directive in the [`property`] macro.
527///
528/// # Syntax
529///
530/// The macro syntax is one or more impl declarations, each declaration can have docs followed by the implementation
531/// visibility, usually `pub`, followed by the path to the property function, followed by a parenthesized list of
532/// the function input arguments, terminated by semicolon.
533///
534/// `pub path::to::property(input: impl IntoVar<bool>);`
535///
536/// # Examples
537///
538/// The example below declares a widget and uses this macro to implements the `align` property for the widget.
539///
540/// ```
541/// # fn main() { }
542/// # use zng_app::widget::{*, node::{UiNode, IntoUiNode}, base::WidgetBase};
543/// # use zng_layout::unit::Align;
544/// # use zng_var::IntoVar;
545/// # 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() } } }
546/// #
547/// #[widget($crate::MyWgt)]
548/// pub struct MyWgt(WidgetBase);
549///
550/// impl MyWgt {
551/// widget_impl! {
552/// /// Docs for the property in the widget.
553/// pub zng::widget::align(align: impl IntoVar<Align>);
554/// }
555/// }
556/// ```
557#[macro_export]
558macro_rules! widget_impl {
559 (
560 $(
561 $(#[$attr:meta])*
562 $vis:vis $($property:ident)::+ ($($arg:ident : $arg_ty:ty)*);
563 )+
564 ) => {
565 $(
566 $crate::widget::property_impl! {
567 attrs { $(#[$attr])* }
568 vis { $vis }
569 path { $($property)::* }
570 args { $($arg:$arg_ty),* }
571 }
572 )+
573 }
574}
575#[doc(inline)]
576pub use widget_impl;
577
578zng_unique_id::unique_id_64! {
579 /// Unique ID of a widget.
580 ///
581 /// # Name
582 ///
583 /// IDs are only unique for the same process.
584 /// You can associate a [`name`] with an ID to give it a persistent identifier.
585 ///
586 /// [`name`]: WidgetId::name
587 pub struct WidgetId;
588}
589zng_unique_id::impl_unique_id_name!(WidgetId);
590zng_unique_id::impl_unique_id_fmt!(WidgetId);
591zng_unique_id::impl_unique_id_bytemuck!(WidgetId);
592
593zng_var::impl_from_and_into_var! {
594 /// Calls [`WidgetId::named`].
595 fn from(name: &'static str) -> WidgetId {
596 WidgetId::named(name)
597 }
598 /// Calls [`WidgetId::named`].
599 fn from(name: String) -> WidgetId {
600 WidgetId::named(name)
601 }
602 /// Calls [`WidgetId::named`].
603 fn from(name: Cow<'static, str>) -> WidgetId {
604 WidgetId::named(name)
605 }
606 /// Calls [`WidgetId::named`].
607 fn from(name: char) -> WidgetId {
608 WidgetId::named(name)
609 }
610 /// Calls [`WidgetId::named`].
611 fn from(name: Txt) -> WidgetId {
612 WidgetId::named(name)
613 }
614 fn from(id: WidgetId) -> zng_view_api::access::AccessNodeId {
615 zng_view_api::access::AccessNodeId(id.get())
616 }
617
618 fn from(some: WidgetId) -> Option<WidgetId>;
619}
620impl serde::Serialize for WidgetId {
621 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
622 where
623 S: serde::Serializer,
624 {
625 let name = self.name();
626 if name.is_empty() {
627 use serde::ser::Error;
628 return Err(S::Error::custom("cannot serialize unnamed `WidgetId`"));
629 }
630 name.serialize(serializer)
631 }
632}
633impl<'de> serde::Deserialize<'de> for WidgetId {
634 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
635 where
636 D: serde::Deserializer<'de>,
637 {
638 let name = Txt::deserialize(deserializer)?;
639 Ok(WidgetId::named(name))
640 }
641}
642
643/// Defines how widget update requests inside [`WIDGET::with_context`] are handled.
644#[derive(Debug, Clone, Copy, PartialEq, Eq)]
645pub enum WidgetUpdateMode {
646 /// All updates flagged during the closure call are discarded, previous pending
647 /// requests are retained.
648 ///
649 /// This mode is used by [`UiNodeOp::Measure`].
650 ///
651 /// [`UiNodeOp::Measure`]: crate::widget::node::UiNodeOp::Measure
652 Ignore,
653 /// All updates flagged after the closure call are retained and propagate to the parent widget flags.
654 ///
655 /// This is the mode is used for all [`UiNodeOp`] delegation, except measure.
656 ///
657 /// [`UiNodeOp`]: crate::widget::node::UiNodeOp
658 Bubble,
659}
660
661/// Current context widget.
662///
663/// # Panics
664///
665/// Most of the methods on this service panic if not called inside a widget context.
666pub struct WIDGET;
667impl WIDGET {
668 /// Returns `true` if called inside a widget.
669 pub fn is_in_widget(&self) -> bool {
670 !WIDGET_CTX.is_default()
671 }
672
673 /// Get the widget ID, if called inside a widget.
674 pub fn try_id(&self) -> Option<WidgetId> {
675 if self.is_in_widget() { Some(WIDGET_CTX.get().id) } else { None }
676 }
677
678 /// Get the widget info, if called inside a widget and the widget has already inited info.
679 pub fn try_info(&self) -> Option<WidgetInfo> {
680 if let Some(id) = self.try_id()
681 && let Some(info) = WINDOW.try_info()
682 {
683 return info.get(id);
684 }
685 None
686 }
687
688 /// Gets a text with detailed path to the current widget.
689 ///
690 /// This can be used to quickly identify the current widget during debug, the path printout will contain
691 /// the widget types if the inspector metadata is found for the widget.
692 ///
693 /// This method does not panic if called outside of a widget.
694 pub fn trace_path(&self) -> Txt {
695 if let Some(w_id) = WINDOW.try_id() {
696 if let Some(id) = self.try_id() {
697 let tree = WINDOW.info();
698 if let Some(wgt) = tree.get(id) {
699 wgt.trace_path()
700 } else {
701 formatx!("{w_id:?}//<no-info>/{id:?}")
702 }
703 } else {
704 formatx!("{w_id:?}//<no-widget>")
705 }
706 } else if let Some(id) = self.try_id() {
707 formatx!("<no-window>//{id:?}")
708 } else {
709 Txt::from_str("<no-widget>")
710 }
711 }
712
713 /// Gets a text with a detailed widget id.
714 ///
715 /// This can be used to quickly identify the current widget during debug, the printout will contain the widget
716 /// type if the inspector metadata is found for the widget.
717 ///
718 /// This method does not panic if called outside of a widget.
719 pub fn trace_id(&self) -> Txt {
720 if let Some(id) = self.try_id() {
721 if WINDOW.try_id().is_some() {
722 let tree = WINDOW.info();
723 if let Some(wgt) = tree.get(id) {
724 wgt.trace_id()
725 } else {
726 formatx!("{id:?}")
727 }
728 } else {
729 formatx!("{id:?}")
730 }
731 } else {
732 Txt::from("<no-widget>")
733 }
734 }
735
736 /// Get the widget ID.
737 pub fn id(&self) -> WidgetId {
738 WIDGET_CTX.get().id
739 }
740
741 /// Gets the widget info.
742 #[must_use] // easy to confuse with update_info
743 pub fn info(&self) -> WidgetInfo {
744 WINDOW.info().get(WIDGET.id()).expect("widget info not init")
745 }
746
747 /// Widget bounds, updated every layout.
748 pub fn bounds(&self) -> WidgetBoundsInfo {
749 WIDGET_CTX.get().bounds.lock().clone()
750 }
751
752 /// Widget border, updated every layout.
753 pub fn border(&self) -> WidgetBorderInfo {
754 WIDGET_CTX.get().border.lock().clone()
755 }
756
757 /// Gets the parent widget or `None` if is root.
758 ///
759 /// Panics if not called inside a widget.
760 pub fn parent_id(&self) -> Option<WidgetId> {
761 WIDGET_CTX.get().parent_id.load(Relaxed)
762 }
763
764 /// Schedule an [`UpdateOp`] for the current widget.
765 pub fn update_op(&self, op: UpdateOp) -> &Self {
766 match op {
767 UpdateOp::Update => self.update(),
768 UpdateOp::Info => self.update_info(),
769 UpdateOp::Layout => self.layout(),
770 UpdateOp::Render => self.render(),
771 UpdateOp::RenderUpdate => self.render_update(),
772 }
773 }
774
775 fn update_impl(&self, flag: UpdateFlags) -> &Self {
776 let _ = WIDGET_CTX.get().flags.fetch_update(Relaxed, Relaxed, |mut f| {
777 if !f.contains(flag) {
778 f.insert(flag);
779 Some(f)
780 } else {
781 None
782 }
783 });
784 self
785 }
786
787 /// Schedule an update for the current widget.
788 ///
789 /// After the current update the app-extensions, parent window and widgets will update again.
790 pub fn update(&self) -> &Self {
791 UpdatesTrace::log_update();
792 self.update_impl(UpdateFlags::UPDATE)
793 }
794
795 /// Schedule an info rebuild for the current widget.
796 ///
797 /// After all requested updates apply the parent window and widgets will re-build the info tree.
798 pub fn update_info(&self) -> &Self {
799 UpdatesTrace::log_info();
800 self.update_impl(UpdateFlags::INFO)
801 }
802
803 /// Schedule a re-layout for the current widget.
804 ///
805 /// After all requested updates apply the parent window and widgets will re-layout.
806 pub fn layout(&self) -> &Self {
807 UpdatesTrace::log_layout();
808 self.update_impl(UpdateFlags::LAYOUT)
809 }
810
811 /// Schedule a re-render for the current widget.
812 ///
813 /// After all requested updates and layouts apply the parent window and widgets will re-render.
814 ///
815 /// This also overrides any pending [`render_update`] request.
816 ///
817 /// [`render_update`]: Self::render_update
818 pub fn render(&self) -> &Self {
819 UpdatesTrace::log_render();
820 self.update_impl(UpdateFlags::RENDER)
821 }
822
823 /// Schedule a frame update for the current widget.
824 ///
825 /// After all requested updates and layouts apply the parent window and widgets will update the frame.
826 ///
827 /// This request is supplanted by any [`render`] request.
828 ///
829 /// [`render`]: Self::render
830 pub fn render_update(&self) -> &Self {
831 UpdatesTrace::log_render();
832 self.update_impl(UpdateFlags::RENDER_UPDATE)
833 }
834
835 /// Flags the widget to re-init after the current update returns.
836 ///
837 /// The widget responds to this request differently depending on the node method that calls it:
838 ///
839 /// * [`UiNode::init`] and [`UiNode::deinit`]: Request is ignored, removed.
840 /// * [`UiNode::update`]: If the widget is pending a reinit, it is reinited and the update ignored.
841 /// If a reinit is requested during update the widget is reinited immediately after the update.
842 /// * Other methods: Reinit request is flagged and an [`UiNode::update`] is requested for the widget.
843 ///
844 /// [`UiNode::init`]: crate::widget::node::UiNode::init
845 /// [`UiNode::deinit`]: crate::widget::node::UiNode::deinit
846 /// [`UiNode::update`]: crate::widget::node::UiNode::update
847 pub fn reinit(&self) {
848 let _ = WIDGET_CTX.get().flags.fetch_update(Relaxed, Relaxed, |mut f| {
849 if !f.contains(UpdateFlags::REINIT) {
850 f.insert(UpdateFlags::REINIT);
851 Some(f)
852 } else {
853 None
854 }
855 });
856 }
857
858 /// Calls `f` with a read lock on the current widget state map.
859 pub fn with_state<R>(&self, f: impl FnOnce(StateMapRef<WIDGET>) -> R) -> R {
860 f(WIDGET_CTX.get().state.read().borrow())
861 }
862
863 /// Calls `f` with a write lock on the current widget state map.
864 pub fn with_state_mut<R>(&self, f: impl FnOnce(StateMapMut<WIDGET>) -> R) -> R {
865 f(WIDGET_CTX.get().state.write().borrow_mut())
866 }
867
868 /// Get the widget state `id`, if it is set.
869 pub fn get_state<T: StateValue + Clone>(&self, id: impl Into<StateId<T>>) -> Option<T> {
870 let id = id.into();
871 self.with_state(|s| s.get_clone(id))
872 }
873
874 /// Require the widget state `id`.
875 ///
876 /// Panics if the `id` is not set.
877 pub fn req_state<T: StateValue + Clone>(&self, id: impl Into<StateId<T>>) -> T {
878 let id = id.into();
879 self.with_state(|s| s.req(id).clone())
880 }
881
882 /// Set the widget state `id` to `value`.
883 ///
884 /// Returns the previous set value.
885 pub fn set_state<T: StateValue>(&self, id: impl Into<StateId<T>>, value: impl Into<T>) -> Option<T> {
886 let id = id.into();
887 let value = value.into();
888 self.with_state_mut(|mut s| s.set(id, value))
889 }
890
891 /// Sets the widget state `id` without value.
892 ///
893 /// Returns if the state `id` was already flagged.
894 pub fn flag_state(&self, id: impl Into<StateId<()>>) -> bool {
895 let id = id.into();
896 self.with_state_mut(|mut s| s.flag(id))
897 }
898
899 /// Calls `init` and sets `id` if it is not already set in the widget.
900 pub fn init_state<T: StateValue>(&self, id: impl Into<StateId<T>>, init: impl FnOnce() -> T) {
901 let id = id.into();
902 self.with_state_mut(|mut s| {
903 s.entry(id).or_insert_with(init);
904 });
905 }
906
907 /// Sets the `id` to the default value if it is not already set.
908 pub fn init_state_default<T: StateValue + Default>(&self, id: impl Into<StateId<T>>) {
909 self.init_state(id.into(), Default::default)
910 }
911
912 /// Returns `true` if the `id` is set or flagged in the widget.
913 pub fn contains_state<T: StateValue>(&self, id: impl Into<StateId<T>>) -> bool {
914 let id = id.into();
915 self.with_state(|s| s.contains(id))
916 }
917
918 /// Subscribe to receive [`UpdateOp`] when the `var` changes.
919 pub fn sub_var_op(&self, op: UpdateOp, var: &AnyVar) -> &Self {
920 let w = WIDGET_CTX.get();
921 let s = var.subscribe(op, w.id);
922
923 // function to avoid generics code bloat
924 fn push(w: Arc<WidgetCtxData>, s: VarHandle) {
925 if WIDGET_HANDLES_CTX.is_default() {
926 w.handles.handles.lock().0.push(s);
927 } else {
928 WIDGET_HANDLES_CTX.get().handles.lock().0.push(s);
929 }
930 }
931 push(w, s);
932
933 self
934 }
935
936 /// Subscribe to receive [`UpdateOp`] when the `var` changes and `predicate` approves the new value.
937 ///
938 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
939 pub fn sub_var_op_when<T: VarValue>(
940 &self,
941 op: UpdateOp,
942 var: &Var<T>,
943 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
944 ) -> &Self {
945 let w = WIDGET_CTX.get();
946 let s = var.subscribe_when(op, w.id, predicate);
947
948 // function to avoid generics code bloat
949 fn push(w: Arc<WidgetCtxData>, s: VarHandle) {
950 if WIDGET_HANDLES_CTX.is_default() {
951 w.handles.handles.lock().0.push(s);
952 } else {
953 WIDGET_HANDLES_CTX.get().handles.lock().0.push(s);
954 }
955 }
956 push(w, s);
957
958 self
959 }
960
961 /// Subscribe to receive updates when the `var` changes.
962 pub fn sub_var(&self, var: &AnyVar) -> &Self {
963 self.sub_var_op(UpdateOp::Update, var)
964 }
965 /// Subscribe to receive updates when the `var` changes and the `predicate` approves the new value.
966 ///
967 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
968 pub fn sub_var_when<T: VarValue>(
969 &self,
970 var: &Var<T>,
971 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
972 ) -> &Self {
973 self.sub_var_op_when(UpdateOp::Update, var, predicate)
974 }
975
976 /// Subscribe to receive info rebuild requests when the `var` changes.
977 pub fn sub_var_info(&self, var: &AnyVar) -> &Self {
978 self.sub_var_op(UpdateOp::Info, var)
979 }
980 /// Subscribe to receive info rebuild 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_info_when<T: VarValue>(
984 &self,
985 var: &Var<T>,
986 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
987 ) -> &Self {
988 self.sub_var_op_when(UpdateOp::Info, var, predicate)
989 }
990
991 /// Subscribe to receive layout requests when the `var` changes.
992 pub fn sub_var_layout(&self, var: &AnyVar) -> &Self {
993 self.sub_var_op(UpdateOp::Layout, var)
994 }
995 /// Subscribe to receive layout requests when the `var` changes and the `predicate` approves the new value.
996 ///
997 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
998 pub fn sub_var_layout_when<T: VarValue>(
999 &self,
1000 var: &Var<T>,
1001 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
1002 ) -> &Self {
1003 self.sub_var_op_when(UpdateOp::Layout, var, predicate)
1004 }
1005
1006 /// Subscribe to receive render requests when the `var` changes.
1007 pub fn sub_var_render(&self, var: &AnyVar) -> &Self {
1008 self.sub_var_op(UpdateOp::Render, var)
1009 }
1010 /// Subscribe to receive render requests when the `var` changes and the `predicate` approves the new value.
1011 ///
1012 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1013 pub fn sub_var_render_when<T: VarValue>(
1014 &self,
1015 var: &Var<T>,
1016 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
1017 ) -> &Self {
1018 self.sub_var_op_when(UpdateOp::Render, var, predicate)
1019 }
1020
1021 /// Subscribe to receive render update requests when the `var` changes.
1022 pub fn sub_var_render_update(&self, var: &AnyVar) -> &Self {
1023 self.sub_var_op(UpdateOp::RenderUpdate, var)
1024 }
1025 /// Subscribe to receive render update requests when the `var` changes and the `predicate` approves the new value.
1026 ///
1027 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1028 pub fn sub_var_render_update_when<T: VarValue>(
1029 &self,
1030 var: &Var<T>,
1031 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
1032 ) -> &Self {
1033 self.sub_var_op_when(UpdateOp::RenderUpdate, var, predicate)
1034 }
1035
1036 /// Subscribe to receive [`UpdateOp`] when the `event` notifies.
1037 pub fn sub_event_op(&self, op: UpdateOp, event: &AnyEvent) -> &Self {
1038 let w = WIDGET_CTX.get();
1039 let s = event.subscribe(op, w.id);
1040
1041 // function to avoid generics code bloat
1042 fn push(w: Arc<WidgetCtxData>, s: VarHandle) {
1043 if WIDGET_HANDLES_CTX.is_default() {
1044 w.handles.handles.lock().0.push(s);
1045 } else {
1046 WIDGET_HANDLES_CTX.get().handles.lock().0.push(s);
1047 }
1048 }
1049 push(w, s);
1050
1051 self
1052 }
1053
1054 /// Subscribe to receive [`UpdateOp`] when the `event` notifies and `predicate` approves the args.
1055 ///
1056 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1057 pub fn sub_event_op_when<A: EventArgs>(
1058 &self,
1059 op: UpdateOp,
1060 event: &Event<A>,
1061 predicate: impl Fn(&A) -> bool + Send + Sync + 'static,
1062 ) -> &Self {
1063 let w = WIDGET_CTX.get();
1064 let s = event.subscribe_when(op, w.id, predicate);
1065
1066 // function to avoid generics code bloat
1067 fn push(w: Arc<WidgetCtxData>, s: VarHandle) {
1068 if WIDGET_HANDLES_CTX.is_default() {
1069 w.handles.handles.lock().0.push(s);
1070 } else {
1071 WIDGET_HANDLES_CTX.get().handles.lock().0.push(s);
1072 }
1073 }
1074 push(w, s);
1075
1076 self
1077 }
1078
1079 /// Subscribe to receive updates when the `event` notifies.
1080 pub fn sub_event(&self, event: &AnyEvent) -> &Self {
1081 self.sub_event_op(UpdateOp::Update, event)
1082 }
1083 /// Subscribe to receive updates when the `event` notifies and the `predicate` approves the args.
1084 ///
1085 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1086 pub fn sub_event_when<A: EventArgs>(&self, event: &Event<A>, predicate: impl Fn(&A) -> bool + Send + Sync + 'static) -> &Self {
1087 self.sub_event_op_when(UpdateOp::Update, event, predicate)
1088 }
1089
1090 /// Subscribe to receive info rebuild requests when the `event` notifies.
1091 pub fn sub_event_info(&self, event: &AnyEvent) -> &Self {
1092 self.sub_event_op(UpdateOp::Info, event)
1093 }
1094 /// Subscribe to receive info rebuild requests when the `event` notifies and the `predicate` approves the args.
1095 ///
1096 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1097 pub fn sub_event_info_when<A: EventArgs>(&self, event: &Event<A>, predicate: impl Fn(&A) -> bool + Send + Sync + 'static) -> &Self {
1098 self.sub_event_op_when(UpdateOp::Info, event, predicate)
1099 }
1100
1101 /// Subscribe to receive layout requests when the `event` notifies.
1102 pub fn sub_event_layout(&self, event: &AnyEvent) -> &Self {
1103 self.sub_event_op(UpdateOp::Layout, event)
1104 }
1105 /// Subscribe to receive layout requests when the `event` notifies and the `predicate` approves the args.
1106 ///
1107 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1108 pub fn sub_event_layout_when<A: EventArgs>(&self, event: &Event<A>, predicate: impl Fn(&A) -> bool + Send + Sync + 'static) -> &Self {
1109 self.sub_event_op_when(UpdateOp::Layout, event, predicate)
1110 }
1111
1112 /// Subscribe to receive render requests when the `event` notifies.
1113 pub fn sub_event_render(&self, event: &AnyEvent) -> &Self {
1114 self.sub_event_op(UpdateOp::Render, event)
1115 }
1116 /// Subscribe to receive render requests when the `event` notifies and the `predicate` approves the args.
1117 ///
1118 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1119 pub fn sub_event_render_when<A: EventArgs>(&self, event: &Event<A>, predicate: impl Fn(&A) -> bool + Send + Sync + 'static) -> &Self {
1120 self.sub_event_op_when(UpdateOp::Render, event, predicate)
1121 }
1122
1123 /// Subscribe to receive render update requests when the `event` notifies.
1124 pub fn sub_event_render_update(&self, event: &AnyEvent) -> &Self {
1125 self.sub_event_op(UpdateOp::RenderUpdate, event)
1126 }
1127 /// Subscribe to receive render update requests when the `event` notifies and the `predicate` approves the args.
1128 ///
1129 /// Note that the `predicate` does not run in the widget context, it runs on the app context.
1130 pub fn sub_event_render_update_when<A: EventArgs>(
1131 &self,
1132 event: &Event<A>,
1133 predicate: impl Fn(&A) -> bool + Send + Sync + 'static,
1134 ) -> &Self {
1135 self.sub_event_op_when(UpdateOp::RenderUpdate, event, predicate)
1136 }
1137
1138 /// Hold the var `handle` until the widget is deinited.
1139 pub fn push_var_handle(&self, handle: VarHandle) {
1140 if WIDGET_HANDLES_CTX.is_default() {
1141 WIDGET_CTX.get().handles.handles.lock().0.push(handle);
1142 } else {
1143 WIDGET_HANDLES_CTX.get().handles.lock().0.push(handle);
1144 }
1145 }
1146
1147 /// Hold the var `handles` until the widget is deinited.
1148 pub fn push_var_handles(&self, handles: VarHandles) {
1149 if WIDGET_HANDLES_CTX.is_default() {
1150 WIDGET_CTX.get().handles.handles.lock().0.extend(handles);
1151 } else {
1152 WIDGET_HANDLES_CTX.get().handles.lock().0.extend(handles);
1153 }
1154 }
1155
1156 /// Hold the `handle` until the widget is deinited.
1157 #[doc(alias = "hold")]
1158 pub fn push_any_handle(&self, handle: impl std::any::Any + Send + 'static) {
1159 let handle: Box<dyn std::any::Any + Send> = Box::new(handle);
1160 match handle.downcast::<VarHandle>() {
1161 Ok(h) => self.push_var_handle(*h),
1162 Err(h) => match h.downcast::<Box<dyn std::any::Any + Send>>() {
1163 Ok(h) => self.push_any_handle_impl(*h),
1164 Err(h) => self.push_any_handle_impl(h),
1165 },
1166 }
1167 }
1168 fn push_any_handle_impl(&self, handle: Box<dyn std::any::Any + Send + 'static>) {
1169 if WIDGET_HANDLES_CTX.is_default() {
1170 WIDGET_CTX.get().handles.handles.lock().1.push(handle);
1171 } else {
1172 WIDGET_HANDLES_CTX.get().handles.lock().1.push(handle);
1173 }
1174 }
1175
1176 /// Transform point in the window space to the widget inner bounds.
1177 pub fn win_point_to_wgt(&self, point: DipPoint) -> Option<PxPoint> {
1178 let wgt_info = WIDGET.info();
1179 wgt_info
1180 .inner_transform()
1181 .inverse()?
1182 .transform_point(point.to_px(wgt_info.tree().scale_factor()))
1183 }
1184
1185 /// Gets the transform from the window space to the widget inner bounds.
1186 pub fn win_to_wgt(&self) -> Option<PxTransform> {
1187 WIDGET.info().inner_transform().inverse()
1188 }
1189
1190 /// Calls `f` with an override target for var and event subscription handles.
1191 ///
1192 /// By default when vars and events are subscribed using the methods of this service the
1193 /// subscriptions live until the widget is deinited. This method intersects these
1194 /// subscriptions, registering then in `handles` instead.
1195 pub fn with_handles<R>(&self, handles: &mut WidgetHandlesCtx, f: impl FnOnce() -> R) -> R {
1196 WIDGET_HANDLES_CTX.with_context(&mut handles.0, f)
1197 }
1198
1199 /// Calls `f` while the widget is set to `ctx`.
1200 ///
1201 /// If `update_mode` is [`WidgetUpdateMode::Bubble`] the update flags requested for the `ctx` after `f` will be copied to the
1202 /// caller widget context, otherwise they are ignored.
1203 ///
1204 /// This method can be used to manually define a widget context, note that widgets already define their own context.
1205 #[inline(always)]
1206 pub fn with_context<R>(&self, ctx: &mut WidgetCtx, update_mode: WidgetUpdateMode, f: impl FnOnce() -> R) -> R {
1207 struct Restore<'a> {
1208 update_mode: WidgetUpdateMode,
1209 parent_id: Option<WidgetId>,
1210 prev_flags: UpdateFlags,
1211 ctx: &'a mut WidgetCtx,
1212 }
1213 impl<'a> Restore<'a> {
1214 fn new(ctx: &'a mut WidgetCtx, update_mode: WidgetUpdateMode) -> Self {
1215 let parent_id = WIDGET.try_id();
1216
1217 if let Some(ctx) = ctx.0.as_mut() {
1218 ctx.parent_id.store(parent_id, Relaxed);
1219 } else {
1220 unreachable!()
1221 }
1222
1223 let prev_flags = match update_mode {
1224 WidgetUpdateMode::Ignore => ctx.0.as_mut().unwrap().flags.load(Relaxed),
1225 WidgetUpdateMode::Bubble => UpdateFlags::empty(),
1226 };
1227
1228 Self {
1229 update_mode,
1230 parent_id,
1231 prev_flags,
1232 ctx,
1233 }
1234 }
1235 }
1236 impl<'a> Drop for Restore<'a> {
1237 fn drop(&mut self) {
1238 let ctx = match self.ctx.0.as_mut() {
1239 Some(c) => c,
1240 None => return, // can happen in case of panic
1241 };
1242
1243 match self.update_mode {
1244 WidgetUpdateMode::Ignore => {
1245 ctx.flags.store(self.prev_flags, Relaxed);
1246 }
1247 WidgetUpdateMode::Bubble => {
1248 let wgt_flags = ctx.flags.load(Relaxed);
1249
1250 if let Some(parent) = self.parent_id.map(|_| WIDGET_CTX.get()) {
1251 let propagate = wgt_flags
1252 & (UpdateFlags::UPDATE
1253 | UpdateFlags::INFO
1254 | UpdateFlags::LAYOUT
1255 | UpdateFlags::RENDER
1256 | UpdateFlags::RENDER_UPDATE);
1257
1258 let _ = parent.flags.fetch_update(Relaxed, Relaxed, |mut u| {
1259 if !u.contains(propagate) {
1260 u.insert(propagate);
1261 Some(u)
1262 } else {
1263 None
1264 }
1265 });
1266 ctx.parent_id.store(None, Relaxed);
1267 } else if let Some(window_id) = WINDOW.try_id() {
1268 // is at root, register `UPDATES`
1269 UPDATES.update_flags_root(wgt_flags, window_id, ctx.id);
1270 // some builders don't clear the root widget flags like they do for other widgets.
1271 ctx.flags.store(wgt_flags & UpdateFlags::REINIT, Relaxed);
1272 } else {
1273 // used outside window
1274 UPDATES.update_flags(wgt_flags, ctx.id);
1275 ctx.flags.store(UpdateFlags::empty(), Relaxed);
1276 }
1277 }
1278 }
1279 }
1280 }
1281
1282 let mut _restore = Restore::new(ctx, update_mode);
1283 WIDGET_CTX.with_context(&mut _restore.ctx.0, f)
1284 }
1285 /// Calls `f` while no widget is available in the context.
1286 #[inline(always)]
1287 pub fn with_no_context<R>(&self, f: impl FnOnce() -> R) -> R {
1288 WIDGET_CTX.with_default(f)
1289 }
1290
1291 #[cfg(any(test, doc, feature = "test_util"))]
1292 pub(crate) fn test_root_updates(&self) {
1293 let ctx = WIDGET_CTX.get();
1294 // is at root, register `UPDATES`
1295 UPDATES.update_flags_root(ctx.flags.load(Relaxed), WINDOW.id(), ctx.id);
1296 // some builders don't clear the root widget flags like they do for other widgets.
1297 ctx.flags.store(UpdateFlags::empty(), Relaxed);
1298 }
1299
1300 pub(crate) fn layout_is_pending(&self, layout_widgets: &LayoutUpdates) -> bool {
1301 let ctx = WIDGET_CTX.get();
1302 ctx.flags.load(Relaxed).contains(UpdateFlags::LAYOUT) || layout_widgets.delivery_list().enter_widget(ctx.id)
1303 }
1304
1305 /// Remove update flag and returns if it intersected.
1306 pub(crate) fn take_update(&self, flag: UpdateFlags) -> bool {
1307 let mut r = false;
1308 let _ = WIDGET_CTX.get().flags.fetch_update(Relaxed, Relaxed, |mut f| {
1309 if f.intersects(flag) {
1310 r = true;
1311 f.remove(flag);
1312 Some(f)
1313 } else {
1314 None
1315 }
1316 });
1317 r
1318 }
1319
1320 /// Current pending updates.
1321 #[cfg(debug_assertions)]
1322 pub(crate) fn pending_update(&self) -> UpdateFlags {
1323 WIDGET_CTX.get().flags.load(Relaxed)
1324 }
1325
1326 /// Remove the render reuse range if render was not invalidated on this widget.
1327 pub(crate) fn take_render_reuse(&self, render_widgets: &RenderUpdates, render_update_widgets: &RenderUpdates) -> Option<ReuseRange> {
1328 let ctx = WIDGET_CTX.get();
1329 let mut try_reuse = true;
1330
1331 // take RENDER, RENDER_UPDATE
1332 let _ = ctx.flags.fetch_update(Relaxed, Relaxed, |mut f| {
1333 if f.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE) {
1334 try_reuse = false;
1335 f.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1336 Some(f)
1337 } else {
1338 None
1339 }
1340 });
1341
1342 if try_reuse && !render_widgets.delivery_list().enter_widget(ctx.id) && !render_update_widgets.delivery_list().enter_widget(ctx.id)
1343 {
1344 ctx.render_reuse.lock().take()
1345 } else {
1346 None
1347 }
1348 }
1349
1350 pub(crate) fn set_render_reuse(&self, range: Option<ReuseRange>) {
1351 *WIDGET_CTX.get().render_reuse.lock() = range;
1352 }
1353}
1354
1355context_local! {
1356 pub(crate) static WIDGET_CTX: WidgetCtxData = WidgetCtxData::no_context();
1357 static WIDGET_HANDLES_CTX: WidgetHandlesCtxData = WidgetHandlesCtxData::dummy();
1358}
1359
1360/// Defines the backing data of [`WIDGET`].
1361///
1362/// Each widget owns this data and calls [`WIDGET.with_context`] to delegate to it's child node.
1363///
1364/// [`WIDGET.with_context`]: WIDGET::with_context
1365pub struct WidgetCtx(Option<Arc<WidgetCtxData>>);
1366impl WidgetCtx {
1367 /// New widget context.
1368 pub fn new(id: WidgetId) -> Self {
1369 Self(Some(Arc::new(WidgetCtxData {
1370 parent_id: Atomic::new(None),
1371 id,
1372 flags: Atomic::new(UpdateFlags::empty()),
1373 state: RwLock::new(OwnedStateMap::default()),
1374 handles: WidgetHandlesCtxData::dummy(),
1375 bounds: Mutex::new(WidgetBoundsInfo::default()),
1376 border: Mutex::new(WidgetBorderInfo::default()),
1377 render_reuse: Mutex::new(None),
1378 })))
1379 }
1380
1381 /// Drops all var and event handles, clears all state.
1382 ///
1383 /// If `retain_state` is enabled the state will not be cleared and can still read.
1384 pub fn deinit(&mut self, retain_state: bool) {
1385 let ctx = self.0.as_mut().unwrap();
1386 {
1387 let mut h = ctx.handles.handles.lock();
1388 h.0.clear();
1389 h.1.clear();
1390 }
1391 ctx.flags.store(UpdateFlags::empty(), Relaxed);
1392 *ctx.render_reuse.lock() = None;
1393
1394 if !retain_state {
1395 ctx.state.write().clear();
1396 }
1397 }
1398
1399 /// Returns `true` if reinit was requested for the widget.
1400 ///
1401 /// Note that widget implementers must use [`take_reinit`] to fulfill the request.
1402 ///
1403 /// [`take_reinit`]: Self::take_reinit
1404 pub fn is_pending_reinit(&self) -> bool {
1405 self.0.as_ref().unwrap().flags.load(Relaxed).contains(UpdateFlags::REINIT)
1406 }
1407
1408 /// Returns `true` if an [`WIDGET.reinit`] request was made.
1409 ///
1410 /// Unlike other requests, the widget implement must re-init immediately.
1411 ///
1412 /// [`WIDGET.reinit`]: WIDGET::reinit
1413 pub fn take_reinit(&mut self) -> bool {
1414 let ctx = self.0.as_mut().unwrap();
1415
1416 let mut flags = ctx.flags.load(Relaxed);
1417 let r = flags.contains(UpdateFlags::REINIT);
1418 if r {
1419 flags.remove(UpdateFlags::REINIT);
1420 ctx.flags.store(flags, Relaxed);
1421 }
1422
1423 r
1424 }
1425
1426 /// Gets the widget id.
1427 pub fn id(&self) -> WidgetId {
1428 self.0.as_ref().unwrap().id
1429 }
1430 /// Gets the widget bounds.
1431 pub fn bounds(&self) -> WidgetBoundsInfo {
1432 self.0.as_ref().unwrap().bounds.lock().clone()
1433 }
1434
1435 /// Gets the widget borders.
1436 pub fn border(&self) -> WidgetBorderInfo {
1437 self.0.as_ref().unwrap().border.lock().clone()
1438 }
1439
1440 /// Call `f` with an exclusive lock to the widget state.
1441 pub fn with_state<R>(&mut self, f: impl FnOnce(&mut OwnedStateMap<WIDGET>) -> R) -> R {
1442 f(&mut self.0.as_mut().unwrap().state.write())
1443 }
1444
1445 /// Clone a reference to the widget context.
1446 ///
1447 /// This must be used only if the widget implementation is split.
1448 pub fn share(&mut self) -> Self {
1449 Self(self.0.clone())
1450 }
1451}
1452
1453pub(crate) struct WidgetCtxData {
1454 parent_id: Atomic<Option<WidgetId>>,
1455 pub(crate) id: WidgetId,
1456 flags: Atomic<UpdateFlags>,
1457 state: RwLock<OwnedStateMap<WIDGET>>,
1458 handles: WidgetHandlesCtxData,
1459 pub(crate) bounds: Mutex<WidgetBoundsInfo>,
1460 border: Mutex<WidgetBorderInfo>,
1461 render_reuse: Mutex<Option<ReuseRange>>,
1462}
1463impl WidgetCtxData {
1464 #[track_caller]
1465 fn no_context() -> Self {
1466 panic!("no widget in context")
1467 }
1468}
1469
1470struct WidgetHandlesCtxData {
1471 handles: Mutex<(VarHandles, Vec<Box<dyn std::any::Any + Send + 'static>>)>,
1472}
1473
1474impl WidgetHandlesCtxData {
1475 const fn dummy() -> Self {
1476 Self {
1477 handles: Mutex::new((VarHandles::dummy(), vec![])),
1478 }
1479 }
1480}
1481
1482/// Defines the backing data for [`WIDGET.with_handles`].
1483///
1484/// [`WIDGET.with_handles`]: WIDGET::with_handles
1485pub struct WidgetHandlesCtx(Option<Arc<WidgetHandlesCtxData>>);
1486impl WidgetHandlesCtx {
1487 /// New empty.
1488 pub fn new() -> Self {
1489 Self(Some(Arc::new(WidgetHandlesCtxData::dummy())))
1490 }
1491
1492 /// Drop all handles.
1493 pub fn clear(&mut self) {
1494 let h = self.0.as_ref().unwrap();
1495 let mut h = h.handles.lock();
1496 h.0.clear();
1497 h.1.clear();
1498 }
1499}
1500impl Default for WidgetHandlesCtx {
1501 fn default() -> Self {
1502 Self::new()
1503 }
1504}
1505
1506/// Extension method to subscribe any widget to a variable.
1507///
1508/// Also see [`WIDGET`] methods for the primary way to subscribe from inside a widget.
1509pub trait AnyVarSubscribe {
1510 /// Register the widget to receive an [`UpdateOp`] when this variable is new.
1511 ///
1512 /// Variables without the [`NEW`] capability return [`VarHandle::dummy`].
1513 ///
1514 /// [`NEW`]: zng_var::VarCapability::NEW
1515 /// [`VarHandle::dummy`]: zng_var::VarHandle
1516 fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle;
1517}
1518impl AnyVarSubscribe for AnyVar {
1519 fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle {
1520 if !self.capabilities().is_const() {
1521 self.hook(move |_| {
1522 UPDATES.update_op(op, widget_id);
1523 true
1524 })
1525 } else {
1526 VarHandle::dummy()
1527 }
1528 }
1529}
1530
1531/// Extension methods to subscribe any widget to a variable or app handlers to a variable.
1532///
1533/// Also see [`WIDGET`] methods for the primary way to subscribe from inside a widget.
1534pub trait VarSubscribe<T: VarValue>: AnyVarSubscribe {
1535 /// Register the widget to receive an [`UpdateOp`] when this variable is new and the `predicate` approves the new value.
1536 ///
1537 /// Variables without the [`NEW`] capability return [`VarHandle::dummy`].
1538 ///
1539 /// [`NEW`]: zng_var::VarCapability::NEW
1540 /// [`VarHandle::dummy`]: zng_var::VarHandle
1541 fn subscribe_when(
1542 &self,
1543 op: UpdateOp,
1544 widget_id: WidgetId,
1545 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
1546 ) -> VarHandle;
1547
1548 /// Add a preview `handler` that is called every time this variable updates,
1549 /// the handler is called before UI update.
1550 ///
1551 /// Note that the handler runs on the app context, all [`ContextVar<T>`] used inside will have the default value.
1552 ///
1553 /// [`ContextVar<T>`]: zng_var::ContextVar
1554 fn on_pre_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1555
1556 /// Add a `handler` that is called every time this variable updates,
1557 /// the handler is called after UI update.
1558 ///
1559 /// Note that the handler runs on the app context, all [`ContextVar<T>`] used inside will have the default value.
1560 ///
1561 /// [`ContextVar<T>`]: zng_var::ContextVar
1562 fn on_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1563}
1564impl<T: VarValue> AnyVarSubscribe for Var<T> {
1565 fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle {
1566 self.as_any().subscribe(op, widget_id)
1567 }
1568}
1569impl<T: VarValue> VarSubscribe<T> for Var<T> {
1570 fn subscribe_when(
1571 &self,
1572 op: UpdateOp,
1573 widget_id: WidgetId,
1574 predicate: impl Fn(&VarHookArgs<'_, T>) -> bool + Send + Sync + 'static,
1575 ) -> VarHandle {
1576 self.hook(move |a| {
1577 if predicate(a) {
1578 UPDATES.update_op(op, widget_id);
1579 }
1580 true
1581 })
1582 }
1583
1584 fn on_pre_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle {
1585 var_on_new(self, handler, true)
1586 }
1587
1588 fn on_new(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle {
1589 var_on_new(self, handler, false)
1590 }
1591}
1592
1593/// Extension methods to subscribe app handlers to a response variable.
1594pub trait ResponseVarSubscribe<T: VarValue> {
1595 /// Add a `handler` that is called once when the response is received,
1596 /// the handler is called before all other UI updates.
1597 ///
1598 /// The handler is not called if already [`is_done`], in this case a dummy handle is returned.
1599 ///
1600 /// [`is_done`]: ResponseVar::is_done
1601 fn on_pre_rsp(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1602
1603 /// Add a `handler` that is called once when the response is received,
1604 /// the handler is called after all other UI updates.
1605 ///
1606 /// The handler is not called if already [`is_done`], in this case a dummy handle is returned.
1607 ///
1608 /// [`is_done`]: ResponseVar::is_done
1609 fn on_rsp(&self, handler: Handler<OnVarArgs<T>>) -> VarHandle;
1610}
1611impl<T: VarValue> ResponseVarSubscribe<T> for ResponseVar<T> {
1612 fn on_pre_rsp(&self, mut handler: Handler<OnVarArgs<T>>) -> VarHandle {
1613 if self.is_done() {
1614 return VarHandle::dummy();
1615 }
1616
1617 self.on_pre_new(Box::new(move |args| {
1618 if let zng_var::Response::Done(value) = &args.value {
1619 APP_HANDLER.unsubscribe();
1620 handler(&OnVarArgs::new(value.clone(), args.tags.clone()))
1621 } else {
1622 HandlerResult::Done
1623 }
1624 }))
1625 }
1626
1627 fn on_rsp(&self, mut handler: Handler<OnVarArgs<T>>) -> VarHandle {
1628 if self.is_done() {
1629 return VarHandle::dummy();
1630 }
1631
1632 self.on_new(Box::new(move |args| {
1633 if let zng_var::Response::Done(value) = &args.value {
1634 APP_HANDLER.unsubscribe();
1635 handler(&OnVarArgs::new(value.clone(), args.tags.clone()))
1636 } else {
1637 HandlerResult::Done
1638 }
1639 }))
1640 }
1641}
1642
1643fn var_on_new<T>(var: &Var<T>, mut handler: Handler<OnVarArgs<T>>, is_preview: bool) -> VarHandle
1644where
1645 T: VarValue,
1646{
1647 if var.capabilities().is_const() {
1648 return VarHandle::dummy();
1649 }
1650
1651 var_on_new_any(
1652 var,
1653 Arc::new(Mutex::new(
1654 move |any_value: BoxAnyVarValue, tags: Vec<BoxAnyVarValue>| -> HandlerResult {
1655 handler(&OnVarArgs::new(any_value.downcast().unwrap(), tags))
1656 },
1657 )),
1658 is_preview,
1659 )
1660}
1661fn var_on_new_any(
1662 var: &AnyVar,
1663 handler: Arc<Mutex<dyn FnMut(BoxAnyVarValue, Vec<BoxAnyVarValue>) -> HandlerResult + Send + 'static>>,
1664 is_preview: bool,
1665) -> VarHandle {
1666 let (inner_handle_owner, inner_handle) = Handle::new(());
1667 let mut update = VarUpdateId::never();
1668 var.hook(move |args| {
1669 if inner_handle_owner.is_dropped() {
1670 return false;
1671 }
1672
1673 // already scheduled update for this cycle
1674 let u = VARS.update_id();
1675 if update == u {
1676 return true;
1677 }
1678 update = u;
1679
1680 let handle = inner_handle.downgrade();
1681 let mut value = Some(args.value().clone_boxed());
1682 let mut tags: Vec<_> = args.tags().to_vec();
1683
1684 let update_once: Handler<crate::update::UpdateArgs> = Box::new(clmv!(handler, |_| {
1685 APP_HANDLER.unsubscribe(); // once
1686 APP_HANDLER.with(AppWeakHandle::clone_boxed(&handle), is_preview, || {
1687 (handler.lock())(value.take().unwrap(), std::mem::take(&mut tags))
1688 })
1689 }));
1690
1691 if is_preview {
1692 UPDATES.on_pre_update(update_once).perm();
1693 } else {
1694 UPDATES.on_update(update_once).perm();
1695 }
1696 true
1697 })
1698}
1699
1700/// Arguments for a var event handler.
1701#[non_exhaustive]
1702pub struct OnVarArgs<T: VarValue> {
1703 /// The new value.
1704 pub value: T,
1705 /// Custom tag objects that where set when the value was modified.
1706 pub tags: Vec<BoxAnyVarValue>,
1707}
1708impl<T: VarValue> OnVarArgs<T> {
1709 /// New from value and custom modify tags.
1710 pub fn new(value: T, tags: Vec<BoxAnyVarValue>) -> Self {
1711 Self { value, tags }
1712 }
1713
1714 /// Reference all custom tag values of type `T`.
1715 pub fn downcast_tags<Ta: VarValue>(&self) -> impl Iterator<Item = &Ta> + '_ {
1716 self.tags.iter().filter_map(|t| (*t).downcast_ref::<Ta>())
1717 }
1718}
1719impl<T: VarValue> Clone for OnVarArgs<T> {
1720 fn clone(&self) -> Self {
1721 Self {
1722 value: self.value.clone(),
1723 tags: self.tags.iter().map(|t| (*t).clone_boxed()).collect(),
1724 }
1725 }
1726}
1727
1728/// Extension methods to layout var values.
1729pub trait VarLayout<T: VarValue> {
1730 /// Compute the pixel value in the current [`LAYOUT`] context.
1731 ///
1732 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1733 fn layout(&self) -> T::Px
1734 where
1735 T: Layout2d;
1736
1737 /// Compute the pixel value in the current [`LAYOUT`] context with `default`.
1738 ///
1739 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1740 fn layout_dft(&self, default: T::Px) -> T::Px
1741 where
1742 T: Layout2d;
1743
1744 /// Compute the pixel value in the current [`LAYOUT`] context ***x*** axis.
1745 ///
1746 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1747 fn layout_x(&self) -> Px
1748 where
1749 T: Layout1d;
1750
1751 /// Compute the pixel value in the current [`LAYOUT`] context ***y*** axis.
1752 ///
1753 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1754 fn layout_y(&self) -> Px
1755 where
1756 T: Layout1d;
1757
1758 /// Compute the pixel value in the current [`LAYOUT`] context ***z*** axis.
1759 ///
1760 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1761 fn layout_z(&self) -> Px
1762 where
1763 T: Layout1d;
1764
1765 /// Compute the pixel value in the current [`LAYOUT`] context ***x*** axis with `default`.
1766 ///
1767 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1768 fn layout_dft_x(&self, default: Px) -> Px
1769 where
1770 T: Layout1d;
1771
1772 /// Compute the pixel value in the current [`LAYOUT`] context ***y*** axis with `default`.
1773 ///
1774 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1775 fn layout_dft_y(&self, default: Px) -> Px
1776 where
1777 T: Layout1d;
1778
1779 /// Compute the pixel value in the current [`LAYOUT`] context ***z*** axis with `default`.
1780 ///
1781 /// [`LAYOUT`]: zng_layout::context::LAYOUT
1782 fn layout_dft_z(&self, default: Px) -> Px
1783 where
1784 T: Layout1d;
1785}
1786impl<T: VarValue> VarLayout<T> for Var<T> {
1787 fn layout(&self) -> <T>::Px
1788 where
1789 T: Layout2d,
1790 {
1791 self.with(|s| s.layout())
1792 }
1793
1794 fn layout_dft(&self, default: <T>::Px) -> <T>::Px
1795 where
1796 T: Layout2d,
1797 {
1798 self.with(move |s| s.layout_dft(default))
1799 }
1800
1801 fn layout_x(&self) -> Px
1802 where
1803 T: Layout1d,
1804 {
1805 self.with(|s| s.layout_x())
1806 }
1807
1808 fn layout_y(&self) -> Px
1809 where
1810 T: Layout1d,
1811 {
1812 self.with(|s| s.layout_y())
1813 }
1814
1815 fn layout_z(&self) -> Px
1816 where
1817 T: Layout1d,
1818 {
1819 self.with(|s| s.layout_z())
1820 }
1821
1822 fn layout_dft_x(&self, default: Px) -> Px
1823 where
1824 T: Layout1d,
1825 {
1826 self.with(move |s| s.layout_dft_x(default))
1827 }
1828
1829 fn layout_dft_y(&self, default: Px) -> Px
1830 where
1831 T: Layout1d,
1832 {
1833 self.with(move |s| s.layout_dft_y(default))
1834 }
1835
1836 fn layout_dft_z(&self, default: Px) -> Px
1837 where
1838 T: Layout1d,
1839 {
1840 self.with(move |s| s.layout_dft_z(default))
1841 }
1842}
1843
1844/// Integrate [`UiTask`] with widget updates.
1845pub trait UiTaskWidget<R> {
1846 /// Create a UI bound future executor.
1847 ///
1848 /// The `task` is inert and must be polled using [`update`] to start, and it must be polled every
1849 /// [`UiNode::update`] after that, in widgets the `target` can be set so that the update requests are received.
1850 ///
1851 /// [`update`]: UiTask::update
1852 /// [`UiNode::update`]: crate::widget::node::UiNode::update
1853 /// [`UiNode::info`]: crate::widget::node::UiNode::info
1854 fn new<F>(target: Option<WidgetId>, task: impl IntoFuture<IntoFuture = F>) -> Self
1855 where
1856 F: Future<Output = R> + Send + 'static;
1857
1858 /// Like [`new`], from an already boxed and pinned future.
1859 ///
1860 /// [`new`]: UiTaskWidget::new
1861 fn new_boxed(target: Option<WidgetId>, task: Pin<Box<dyn Future<Output = R> + Send + 'static>>) -> Self;
1862}
1863impl<R> UiTaskWidget<R> for UiTask<R> {
1864 fn new<F>(target: Option<WidgetId>, task: impl IntoFuture<IntoFuture = F>) -> Self
1865 where
1866 F: Future<Output = R> + Send + 'static,
1867 {
1868 UiTask::new_raw(UPDATES.waker(target), task)
1869 }
1870
1871 fn new_boxed(target: Option<WidgetId>, task: Pin<Box<dyn Future<Output = R> + Send + 'static>>) -> Self {
1872 UiTask::new_raw_boxed(UPDATES.waker(target), task)
1873 }
1874}