zng/
var.rs

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

pub use zng_var::types::{
    AnyWhenVarBuilder, ArcCowVar, ArcWhenVar, ContextualizedVar, ReadOnlyVar, Response, VecChange, WeakArcVar, WeakContextualizedVar,
    WeakReadOnlyVar, WeakWhenVar,
};
pub use zng_var::{
    context_var, expr_var, getter_var, impl_from_and_into_var, merge_var, response_done_var, response_var, state_var, var, var_default,
    var_from, when_var, AnyVar, AnyVarValue, AnyWeakVar, ArcEq, ArcVar, BoxedAnyVar, BoxedAnyWeakVar, BoxedVar, BoxedWeakVar,
    ContextInitHandle, ContextVar, IntoValue, IntoVar, LocalVar, MergeVarBuilder, ObservableVec, ReadOnlyArcVar, ReadOnlyContextVar,
    ResponderVar, ResponseVar, TraceValueArgs, Var, VarCapability, VarHandle, VarHandles, VarHookArgs, VarModify, VarPtr, VarUpdateId,
    VarValue, WeakVar, VARS,
};

pub use zng_app::widget::{AnyVarSubscribe, OnVarArgs, VarLayout, VarSubscribe};

/// Var animation types and functions.
pub mod animation {
    pub use zng_var::animation::{
        Animation, AnimationController, AnimationHandle, ChaseAnimation, ForceAnimationController, ModifyInfo, Transition, TransitionKeyed,
        Transitionable, WeakAnimationHandle,
    };

    /// Common easing functions.
    pub mod easing {
        pub use zng_var::animation::easing::{
            back, bounce, circ, cubic, cubic_bezier, ease_in, ease_in_out, ease_out, ease_out_in, elastic, expo, linear, none, quad, quart,
            quint, reverse, reverse_out, sine, step_ceil, step_floor, Bezier, EasingFn, EasingStep, EasingTime,
        };
    }
}