zng/
var.rs

1//! Variables API.
2//!
3//! The [`Var<T>`] struct represents an observable value. The [`IntoVar<T>`] trait is the primary property input
4//! kind and the reason properties inputs are so versatile. Variables can be a simple value, a shared reference to a value or
5//! a contextual value, some variables are also derived from others and update when the source variable update.
6//!
7//! Properties and widgets can subscribe to a variable to update when the variable value changes, this features enables most
8//! of the dynamic UI behavior, from binding one widget to another to animation.
9//!
10//! # Value
11//!
12//! The simplest variable kind is [`const_var`], it represents an unchanging value that is shared by cloning. All values of types
13//! that implement [`VarValue`] automatically convert `IntoVar<T>` to const var, For this reason you don't usually need
14//! to write `const_var(_)` when setting properties.
15//!
16//! ```
17//! use zng::prelude::*;
18//!
19//! fn foo(size: impl IntoVar<layout::Size>) {
20//!     let size = size.into_var();
21//!     assert!(size.capabilities().is_const());
22//!     assert!(size.capabilities().is_always_read_only());
23//! }
24//!
25//! foo(layout::Size::new(10, 10));
26//! foo((10, 10));
27//! foo(10);
28//! ```
29//!
30//! The example above declares a const `Var<Size>` 3 times with equal value. The `(10, 10)` and `10` values are type conversions
31//! implemented by the `Size` type. Type conversions are very easy to implement with the help of the [`impl_from_and_into_var!`] macro,
32//! most of the types used by properties implement conversions that enable a form of shorthand syntax.
33//!
34//! # Share & Modify
35//!
36//! The [`var`] variable represents a shared value that can be modified.
37//!
38//! The example below declares a button that grows taller every click. The variable is shared between the height property
39//! and the click handler. On click the height is increased, this schedules an update that applies the new value and notifies
40//! all subscribers.
41//!
42//! ```
43//! use zng::prelude::*;
44//! # fn example() {
45//!
46//! let height = var(2.em());
47//! # let _ =
48//! Button! {
49//!     child = Text!("Taller!");
50//!     on_click = hn!(height, |_| {
51//!         // clone `height` reference for the handler.
52//!         height.set(height.get() + 10); // request an update to a new value.
53//!     });
54//!     layout::align = layout::Align::CENTER;
55//!     layout::height; // set the height (shorthand, variable is same name as property)
56//! }
57//! # ; }
58//! ```
59//!
60//! Note that variable updates don't happen immediately, in the handler above the variable is still the previous value after the [`set`](Var::set) call,
61//! this is done so that all widgets in a single update react to the same value. The variable values is updated at the end of the current update.
62//!
63//! ```
64//! use zng::prelude::*;
65//! # fn example() {
66//!
67//! let number = var(0u8);
68//! # let _ =
69//! Button! {
70//!     child = Text!("Test");
71//!     on_click = async_hn!(number, |_| {
72//!         assert_eq!(number.get(), 0);
73//!         number.set(1);
74//!         assert_eq!(number.get(), 0);
75//!
76//!         task::yield_now().await;
77//!         assert_eq!(number.get(), 1);
78//!     });
79//! }
80//! # ; }
81//! ```
82//!
83//! The example above demonstrates the delayed update of a variable.
84//!
85//! If multiple widgets set the same variable on the same update only
86//! the last value set will be used, widgets update in parallel by default so it is difficult to predict who is the last. The [`modify`](Var::modify)
87//! method can be used register a closure that can modify the value, this closure will observe the partially updated value that may already be
88//! modified by other widgets.
89//!
90//! The example below demonstrates how the `modify` closure observes a value that was just set in the same update cycle.
91//!
92//! ```
93//! use zng::prelude::*;
94//! # fn example() {
95//!
96//! let foo = var(0u8);
97//! # let _ =
98//! Wgt! {
99//!     widget::on_init = async_hn!(foo, |_| {
100//!         foo.set(1);
101//!         assert_eq!(0, foo.get());
102//!         foo.modify(|m| {
103//!             assert_eq!(1, **m);
104//!             **m = 2;
105//!         });
106//!         assert_eq!(0, foo.get());
107//!
108//!         foo.wait_update().await;
109//!         assert_eq!(2, foo.get());
110//!
111//!         println!("test ok");
112//!     });
113//! }
114//! # ; }
115//! ```
116//!
117//! # Mapping
118//!
119//! Variables can be mapped to other value types, when the source variable updates the mapping closure re-evaluates and the mapped variable
120//! updates, all in the same update cycle, that is both variable will be flagged new at the same time. Mapping can also be bidirectional.
121//!
122//! The example below demonstrates a button that updates an integer variable that is mapped to a text.
123//!
124//! ```
125//! use zng::prelude::*;
126//! # fn example() {
127//!
128//! let count = var(0u32);
129//! # let _ =
130//! Button! {
131//!     child = Text!(count.map(|i| match i {
132//!         0 => Txt::from("Click Me!"),
133//!         1 => Txt::from("Clicked 1 time!"),
134//!         n => formatx!("Clicked {n} times!"),
135//!     }));
136//!     on_click = hn!(|_| {
137//!         count.set(count.get() + 1);
138//!     });
139//! }
140//! # ; }
141//! ```
142//!
143//! # Binding
144//!
145//! Two existing variables can be bound, such that one variable update sets the other. The example below rewrites the mapping
146//! demo to use a [`bind_map`](Var::bind_map) instead.
147//!
148//! ```
149//! use zng::prelude::*;
150//! # fn example() {
151//!
152//! let count = var(0u32);
153//! let label = var(Txt::from("Click Me!"));
154//! count
155//!     .bind_map(&label, |i| match i {
156//!         1 => Txt::from("Clicked 1 time!"),
157//!         n => formatx!("Clicked {n} times!"),
158//!     })
159//!     .perm();
160//! # let _ =
161//! Button! {
162//!     child = Text!(label);
163//!     on_click = hn!(|_| {
164//!         count.set(count.get() + 1);
165//!     });
166//! }
167//! # ; }
168//! ```
169//!
170//! Note that unlike a map the initial value of the output variable is not updated, only subsequent ones. You can use
171//! [`set_from`](Var::set_from) to update the initial value too.
172//!
173//! # Animating
174//!
175//! Animation is implemented using variables, at the lowest level [`VARS.animate`](VARS::animate) is used to register a closure to be
176//! called every frame, the closure can set any number of variables, at a higher level the [`Var::ease`] and [`Var::chase`] methods
177//! can be used to animate the value of a variable.
178//!
179//! The example below uses [`Var::easing`] to animate the window background:
180//! ```
181//! use zng::prelude::*;
182//! # fn example() {
183//!
184//! let color = var(colors::AZURE.darken(30.pct()));
185//! # let _ =
186//! Window! {
187//!     widget::background_color = color.easing(500.ms(), easing::linear);
188//!     child = Button! {
189//!         layout::align = layout::Align::TOP;
190//!         on_click = hn!(|_| {
191//!             let mut c = color::Hsla::from(color.get());
192//!             c.hue += 60.0;
193//!             color.set(c);
194//!         });
195//!         child = Text!("Change background color");
196//!     };
197//! }
198//! # ; }
199//! ```
200//!
201//! Variables can only be operated by a single animation, when a newer animation or modify affects a variable older animations can no longer
202//! affect it, see [`VARS.animate`](VARS::animate) for more details.
203//!
204//! # Response
205//!
206//! The [`ResponseVar<T>`] is a specialized variable that represents the result of an async task. You can use `.await` directly
207//! in any async handler, but a response var lets you plug a query directly into a property. You can use [`task::respond`] to convert
208//! any future into a response var, and you can use [`wait_rsp`] to convert a response var to a future.
209//!
210//! ```no_run
211//! use zng::prelude::*;
212//! # fn example() {
213//!
214//! let rsp = task::respond(async {
215//!     let url = "https://raw.githubusercontent.com/git/git-scm.com/main/MIT-LICENSE.txt";
216//!     match task::http::get_txt(url).await {
217//!         Ok(t) => t,
218//!         Err(e) => formatx!("{e}"),
219//!     }
220//! });
221//! # let _ =
222//! SelectableText!(rsp.map(|r| {
223//!     use zng::var::Response::*;
224//!     match r {
225//!         Waiting => Txt::from("loading.."),
226//!         Done(t) => t.clone(),
227//!     }
228//! }))
229//! # ; }
230//! ```
231//!
232//! The example above creates a response var from a download future and maps the response to a widget.
233//!
234//! A response var is paired with a [`ResponderVar<T>`], you can create a *response channel* using the [`response_var`] function.
235//!
236//! [`task::respond`]: crate::task::respond
237//! [`wait_rsp`]: ResponseVar::wait_rsp
238//!
239//! # Merge
240//!
241//! The [`merge_var!`] and [`expr_var!`] macros can be used to declare a variable that merges multiple other variable values.
242//!
243//! The example below demonstrates the two macros.
244//!
245//! ```
246//! use zng::prelude::*;
247//! # fn example() {
248//!
249//! let a = var(10u32);
250//! let b = var(1u32);
251//!
252//! // let merge = expr_var!({
253//! //     let a = *#{a};
254//! //     let b = *#{b.clone()};
255//! //     formatx!("{a} + {b} = {}", a + b)
256//! // });
257//! let merge = merge_var!(a, b.clone(), |&a, &b| { formatx!("{a} + {b} = {}", a + b) });
258//! # let _ =
259//! Button! {
260//!     child = Text!(merge);
261//!     on_click = hn!(|_| b.set(b.get() + 1));
262//! }
263//! # ; }
264//! ```
265//!
266//! # Contextual
267//!
268//! The [`ContextVar<T>`] type represents a variable that has context depend value, meaning they can produce a different value depending
269//! on where they are used. Context vars are declared using the [`context_var!`] macro.
270//!
271//! The example below declares a context var and a property that sets it. The context var is then used in two texts with
272//! two different contexts, the first text will show "Text!", the second will show "Stack!".
273//!
274//! ```
275//! # fn main() { }
276//! use zng::prelude::*;
277//!
278//! context_var! {
279//!     static FOO_VAR: Txt = "";
280//! }
281//!
282//! #[zng::widget::property(CONTEXT, default(FOO_VAR))]
283//! pub fn foo(child: impl IntoUiNode, foo: impl IntoVar<Txt>) -> UiNode {
284//!     zng::widget::node::with_context_var(child, FOO_VAR, foo)
285//! }
286//!
287//! fn demo() -> UiNode {
288//!     Stack! {
289//!         direction = StackDirection::top_to_bottom();
290//!         spacing = 5;
291//!         foo = "Stack!";
292//!         children = ui_vec![
293//!             Text! {
294//!                 txt = FOO_VAR;
295//!                 foo = "Text!";
296//!             },
297//!             Text!(FOO_VAR),
298//!         ];
299//!     }
300//! }
301//! ```
302//!
303//! Context variables have all the same capabilities of other variables if the example if `foo` is set to a [`var`]
304//! the context var will be editable, and if `FOO_VAR` is mapped the mapping variable is also contextual.
305//!
306//! # Full API
307//!
308//! See [`zng_var`] for the full var API.
309
310pub use zng_var::{
311    AnyVar, AnyVarValue, AnyWhenVarBuilder, ArcEq, BoxAnyVarValue, ContextInitHandle, ContextVar, IntoValue, IntoVar, MergeVarBuilder,
312    ObservableVec, ResponderVar, Response, ResponseVar, VARS, Var, VarCapability, VarEq, VarHandle, VarHandles, VarHookArgs,
313    VarInstanceTag, VarModify, VarUpdateId, VarValue, VecChange, WeakAnyVar, WeakVar, any_var_derived, const_var, context_var,
314    contextual_var, expr_var, flat_expr_var, impl_from_and_into_var, merge_var, response_done_var, response_var, var, var_default,
315    var_from, var_getter, var_state, when_var,
316};
317
318pub use zng_app::widget::{AnyVarSubscribe, OnVarArgs, VarLayout, VarSubscribe};
319
320/// Var animation types and functions.
321pub mod animation {
322    pub use zng_var::animation::{
323        Animation, AnimationController, AnimationHandle, ChaseAnimation, ForceAnimationController, ModifyInfo, Transition, TransitionKeyed,
324        Transitionable, WeakAnimationHandle,
325    };
326
327    /// Common easing functions.
328    pub mod easing {
329        pub use zng_var::animation::easing::{
330            Bezier, EasingFn, EasingStep, EasingTime, back, bounce, circ, cubic, cubic_bezier, ease_in, ease_in_out, ease_out, ease_out_in,
331            elastic, expo, linear, none, quad, quart, quint, reverse, reverse_out, sine, step_ceil, step_floor,
332        };
333    }
334}