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