zng_var/var.rs
1use core::fmt;
2use std::{any::TypeId, marker::PhantomData, ops, sync::Arc, time::Duration};
3
4use crate::{
5 AnyVar, AnyVarHookArgs, BoxAnyVarValue, VarHandle, VarHandles, VarImpl, VarIsReadOnlyError, VarModify, VarValue, WeakAnyVar,
6 animation::{
7 Animation, AnimationHandle, ChaseAnimation, Transition, TransitionKeyed, Transitionable,
8 easing::{EasingStep, EasingTime},
9 },
10 contextual_var,
11};
12
13use zng_clone_move::clmv;
14use zng_txt::{ToTxt, Txt};
15use zng_unit::{Factor, FactorUnits as _};
16
17/// Variable of type `T`.
18pub struct Var<T: VarValue> {
19 pub(crate) any: AnyVar,
20 _t: PhantomData<fn() -> T>,
21}
22impl<T: VarValue> Clone for Var<T> {
23 fn clone(&self) -> Self {
24 Self {
25 any: self.any.clone(),
26 _t: PhantomData,
27 }
28 }
29}
30impl<T: VarValue> From<Var<T>> for AnyVar {
31 fn from(var: Var<T>) -> Self {
32 var.any
33 }
34}
35impl<T: VarValue> TryFrom<AnyVar> for Var<T> {
36 type Error = AnyVar;
37
38 fn try_from(var: AnyVar) -> Result<Self, Self::Error> {
39 var.downcast()
40 }
41}
42impl<T: VarValue> ops::Deref for Var<T> {
43 type Target = AnyVar;
44
45 fn deref(&self) -> &Self::Target {
46 self.as_any()
47 }
48}
49impl<T: VarValue> Var<T> {
50 pub(crate) fn new_any(any: AnyVar) -> Self {
51 Var { any, _t: PhantomData }
52 }
53}
54impl<T: VarValue> fmt::Debug for Var<T> {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 f.debug_tuple("Var").field(&self.any.0).finish()
57 }
58}
59
60/// Value.
61impl<T: VarValue> Var<T> {
62 /// Visit a reference to the current value.
63 pub fn with<O>(&self, visitor: impl FnOnce(&T) -> O) -> O {
64 let mut once = Some(visitor);
65 let mut output = None;
66 self.0.with(&mut |v| {
67 output = Some(once.take().unwrap()(v.downcast_ref().unwrap()));
68 });
69 output.unwrap()
70 }
71
72 /// Get a clone of the current value.
73 pub fn get(&self) -> T {
74 self.with(|v| v.clone())
75 }
76
77 /// Get a clone of the current value into `value`.
78 ///
79 /// This uses [`Clone::clone_from`] to reuse the `value` memory if supported.
80 pub fn get_into(&self, value: &mut T) {
81 self.with(|v| value.clone_from(v));
82 }
83
84 /// Visit a reference to the current value if it [`is_new`].
85 ///
86 /// [`is_new`]: AnyVar::is_new
87 pub fn with_new<O>(&self, visitor: impl FnOnce(&T) -> O) -> Option<O> {
88 if self.is_new() { Some(self.with(visitor)) } else { None }
89 }
90
91 /// Gets a clone of the current value if it [`is_new`].
92 ///
93 /// [`is_new`]: AnyVar::is_new
94 pub fn get_new(&self) -> Option<T> {
95 if self.is_new() { Some(self.get()) } else { None }
96 }
97
98 /// Gets a clone of the current value into `value` if it [`is_new`].
99 ///
100 /// This uses [`Clone::clone_from`] to reuse the `value` memory if supported.
101 ///
102 /// [`is_new`]: AnyVar::is_new
103 pub fn get_new_into(&self, value: &mut T) -> bool {
104 self.with_new(|v| value.clone_from(v)).is_some()
105 }
106
107 /// Schedule `new_value` to be assigned next update.
108 pub fn try_set(&self, new_value: impl Into<T>) -> Result<(), VarIsReadOnlyError> {
109 self.any.try_set(BoxAnyVarValue::new(new_value.into()))
110 }
111
112 /// Schedule `new_value` to be assigned next update.
113 ///
114 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
115 /// Use [`try_set`] to get an error for read-only vars.
116 ///
117 /// [`try_set`]: Self::try_set
118 pub fn set(&self, new_value: impl Into<T>) {
119 trace_debug_error!(self.try_set(new_value))
120 }
121
122 /// Schedule `modify` to be called on the value for the next update.
123 ///
124 /// If the [`VarModify`] value is deref mut the variable will notify an update.
125 pub fn try_modify(&self, modify: impl FnOnce(&mut VarModify<T>) + Send + 'static) -> Result<(), VarIsReadOnlyError> {
126 self.any.try_modify(move |value| {
127 modify(&mut value.downcast::<T>().unwrap());
128 })
129 }
130
131 /// Schedule `modify` to be called on the value for the next update.
132 ///
133 /// If the [`VarModify`] value is deref mut the variable will notify an update.
134 ///
135 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
136 /// Use [`try_modify`] to get an error for read-only vars.
137 ///
138 /// [`try_modify`]: Self::try_modify
139 pub fn modify(&self, modify: impl FnOnce(&mut VarModify<T>) + Send + 'static) {
140 trace_debug_error!(self.try_modify(modify))
141 }
142
143 /// Schedule a new `value` for the variable, it will be set in the end of the current app update to the updated
144 /// value of `other`, so if the other var has already scheduled an update, the updated value will be used.
145 ///
146 /// This can be used just before creating a binding to start with synchronized values.
147 pub fn try_set_from(&self, other: &Var<T>) -> Result<(), VarIsReadOnlyError> {
148 self.any.try_set_from(other)
149 }
150
151 /// Schedule a new `value` for the variable, it will be set in the end of the current app update to the updated
152 /// value of `other`, so if the other var has already scheduled an update, the updated value will be used.
153 ///
154 /// This can be used just before creating a binding to start with synchronized values.
155 ///
156 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
157 /// Use [`try_set_from`] to get an error for read-only vars.
158 ///
159 /// [`try_set_from`]: Self::try_set_from
160 pub fn set_from(&self, other: &Var<T>) {
161 trace_debug_error!(self.try_set_from(other))
162 }
163
164 /// Like [`try_set_from`], but uses `map` to produce the new value from the updated value of `other`.
165 ///
166 /// [`try_set_from`]: Self::try_set_from
167 pub fn try_set_from_map<O: VarValue>(
168 &self,
169 other: &Var<O>,
170 map: impl FnOnce(&O) -> T + Send + 'static,
171 ) -> Result<(), VarIsReadOnlyError> {
172 self.any
173 .try_set_from_map(other, move |v| BoxAnyVarValue::new(map(v.downcast_ref::<O>().unwrap())))
174 }
175
176 /// Like [`set_from`], but uses `map` to produce the new value from the updated value of `other`.
177 ///
178 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
179 /// Use [`try_set_from_map`] to get an error for read-only vars.
180 ///
181 /// [`try_set_from_map`]: Self::try_set_from_map
182 /// [`set_from`]: Self::set_from
183 pub fn set_from_map<O: VarValue>(&self, other: &Var<O>, map: impl FnOnce(&O) -> T + Send + 'static) {
184 trace_debug_error!(self.try_set_from_map(other, map))
185 }
186
187 /// Setups a callback for just after the variable value update is applied, the closure runs in the root app context, just like
188 /// the `modify` closure. The closure must return `true` to be retained and `false` to be dropped.
189 ///
190 /// If you modify another variable in the closure modification applies in the same update, variable mapping and
191 /// binding is implemented using hooks.
192 ///
193 /// The variable store a weak reference to the callback if it has the `MODIFY` or `CAPS_CHANGE` capabilities, otherwise
194 /// the callback is discarded and [`VarHandle::dummy`] returned.
195 pub fn hook(&self, mut on_update: impl FnMut(&VarHookArgs<T>) -> bool + Send + 'static) -> VarHandle {
196 self.any
197 .hook(move |args: &AnyVarHookArgs| -> bool { on_update(&args.downcast().unwrap()) })
198 }
199
200 ///Awaits for a value that passes the `predicate`, including the current value.
201 #[allow(clippy::manual_async_fn)] // false positive, async fn futures are not Send + Sync
202 pub fn wait_match(&self, predicate: impl Fn(&T) -> bool + Send + Sync) -> impl Future<Output = ()> + Send + Sync {
203 self.any.wait_match(move |v| predicate(v.downcast_ref::<T>().unwrap()))
204 }
205
206 /// Awaits for an update them [`get`] the value.
207 ///
208 /// [`get`]: Self::get
209 #[allow(clippy::manual_async_fn)] // false positive, async fn futures are not Send + Sync
210 pub fn wait_next(&self) -> impl Future<Output = T> + Send + Sync {
211 async {
212 self.wait_update().await;
213 self.get()
214 }
215 }
216
217 /// Debug helper for tracing the lifetime of a value in this variable.
218 ///
219 /// The `enter_value` closure is called every time the variable updates, it can return
220 /// an implementation agnostic *scope* or *span* `S` that is only dropped when the variable updates again.
221 ///
222 /// The `enter_value` is also called immediately when this method is called to start tracking the first value.
223 ///
224 /// Returns a [`VarHandle`] that can be used to stop tracing.
225 ///
226 /// If this variable can never update the span is immediately dropped and a dummy handle is returned.
227 pub fn trace_value<S: Send + 'static>(&self, mut enter_value: impl FnMut(&VarHookArgs<T>) -> S + Send + 'static) -> VarHandle {
228 self.any.trace_value(move |args| enter_value(&args.downcast::<T>().unwrap()))
229 }
230}
231/// Value mapping.
232impl<T: VarValue> Var<T> {
233 /// Create a read-only mapping variable.
234 ///
235 /// The `map` closure must produce a mapped value from this variable's value.
236 ///
237 /// # Examples
238 ///
239 /// Basic usage:
240 ///
241 /// ```
242 /// # use zng_var::*;
243 /// # use zng_txt::*;
244 /// let n_var = var(0u32);
245 /// let n_10_var = n_var.map(|n| *n * 10);
246 /// let txt_var = n_10_var.map(|n| if *n < 100 { formatx!("{n}!") } else { formatx!("Done!") });
247 /// ```
248 ///
249 /// In the example above the `txt_var` will update every time the `n_var` updates.
250 ///
251 /// # Capabilities
252 ///
253 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static.
254 ///
255 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable and
256 /// is called again for every update of this variable. The mapping variable is another shared reference and it holds
257 /// a strong reference to this variable.
258 ///
259 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
260 /// mapping variable is also contextual and will init for every context it is used in.
261 ///
262 /// The mapping variable is read-only, see [`map_bidi`] for read-write mapping.
263 ///
264 /// If the `map` closure produce an equal value the mapping variable will not update, see also [`filter_map`]
265 /// to skip updating for some input values.
266 ///
267 /// [`map_bidi`]: Self::map_bidi
268 /// [`filter_map`]: Self::filter_map
269 pub fn map<O: VarValue>(&self, mut map: impl FnMut(&T) -> O + Send + 'static) -> Var<O> {
270 self.any.map(move |v| map(v.downcast_ref::<T>().unwrap()))
271 }
272
273 /// Create a [`map`] that converts from `T` to `O` using [`Into<O>`].
274 ///
275 /// [`map`]: Var::map
276 pub fn map_into<O>(&self) -> Var<O>
277 where
278 O: VarValue,
279 T: Into<O>,
280 {
281 self.map(|v| v.clone().into())
282 }
283
284 /// Create a [`map`] that converts from `T` to [`Txt`] using [`ToTxt`].
285 ///
286 /// [`map`]: Var::map
287 /// [`Txt`]: Txt
288 /// [`ToTxt`]: ToTxt
289 pub fn map_to_txt(&self) -> Var<Txt>
290 where
291 T: ToTxt,
292 {
293 self.map(ToTxt::to_txt)
294 }
295
296 /// Create a [`map`] that references and clones `O` from `T` using `std::ops::Deref<Target = O>`.
297 ///
298 /// The mapping variable is read-only, see [`map_deref_mut`] for mutable referencing.
299 ///
300 /// [`map`]: Self::map
301 /// [`map_deref_mut`]: Self::map_deref_mut
302 pub fn map_deref<O>(&self) -> Var<O>
303 where
304 O: VarValue,
305 T: ops::Deref<Target = O>,
306 {
307 self.map(|v| ops::Deref::deref(v).clone())
308 }
309
310 /// Create a mapping variable that can skip updates.
311 ///
312 /// The `map` closure is called for every update this variable and if it returns a new value the mapping variable updates.
313 ///
314 /// If the `map` closure does not produce a value on init the `fallback_init` closure is called.
315 ///
316 /// # Examples
317 ///
318 /// Basic usage:
319 ///
320 /// ```
321 /// # use zng_var::*;
322 /// # use zng_txt::*;
323 /// let n_var = var(100u32);
324 /// let txt_var = n_var.filter_map(|n| if *n < 100 { Some(formatx!("{n}!")) } else { None }, || "starting...".into());
325 /// ```
326 ///
327 /// In the example above the `txt_var` will update every time the `n_var` updates with value `n < 100`. Because
328 /// the `n_var` initial value does not match the filter the fallback value `"starting..."` is used.
329 ///
330 /// # Capabilities
331 ///
332 /// If this variable is static the closures are called immediately and dropped, the mapping variable is also static.
333 ///
334 /// If this variable is a shared reference the closures are called immediately to init the mapping variable and
335 /// are called again for every update of this variable. The mapping variable is another shared reference and it holds
336 /// a strong reference to this variable.
337 ///
338 /// If this variable is contextual the initial closures call is deferred until first usage of the mapping variable. The
339 /// mapping variable is also contextual and will init for every context it is used in.
340 ///
341 /// The mapping variable is read-only, see [`filter_map_bidi`] for read-write mapping.
342 ///
343 /// [`filter_map_bidi`]: Self::filter_map_bidi
344 pub fn filter_map<O: VarValue>(
345 &self,
346 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
347 fallback_init: impl Fn() -> O + Send + 'static,
348 ) -> Var<O> {
349 self.any.filter_map(move |v| map(v.downcast_ref::<T>().unwrap()), fallback_init)
350 }
351
352 /// Create a [`filter_map`] that tries to convert from `T` to `O` using [`TryInto<O>`].
353 ///
354 /// [`filter_map`]: Var::filter_map
355 pub fn filter_try_into<O, I>(&self, fallback_init: I) -> Var<O>
356 where
357 O: VarValue,
358 T: TryInto<O>,
359 I: Fn() -> O + Send + Sync + 'static,
360 {
361 self.filter_map(|v| v.clone().try_into().ok(), fallback_init)
362 }
363
364 /// Create a [`filter_map`] that tries to convert from `T` to `O` using [`FromStr`].
365 ///
366 /// [`filter_map`]: Var::filter_map
367 /// [`FromStr`]: std::str::FromStr
368 pub fn filter_parse<O, I>(&self, fallback_init: I) -> Var<O>
369 where
370 O: VarValue + std::str::FromStr,
371 T: AsRef<str>,
372 I: Fn() -> O + Send + Sync + 'static,
373 {
374 self.filter_map(|v| v.as_ref().parse().ok(), fallback_init)
375 }
376
377 /// Create a bidirectional mapping variable.
378 ///
379 /// # Examples
380 ///
381 /// Basic usage:
382 ///
383 /// ```
384 /// # use zng_var::*;
385 /// # use zng_txt::*;
386 /// let n_var = var(0u32);
387 /// let n_100_var = n_var.map_bidi(|n| n * 100, |n_100| n_100 / 100);
388 /// ```
389 ///
390 /// In the example above the `n_100_var` will update every time the `n_var` updates and the `n_var` will
391 /// update every time the `n_100_var` updates.
392 ///
393 /// # Capabilities
394 ///
395 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static,
396 /// the `map_back` closure is ignored.
397 ///
398 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable.
399 /// The mapping variable is another shared reference and it holds a strong reference to this variable.
400 /// The `map` closure is called again for every update of this variable that is not caused by the mapping variable.
401 /// The `map_back` closure is called for every update of the mapping variable that was not caused by this variable.
402 ///
403 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
404 /// mapping variable is also contextual and will init for every context it is used in.
405 pub fn map_bidi<O: VarValue>(
406 &self,
407 mut map: impl FnMut(&T) -> O + Send + 'static,
408 mut map_back: impl FnMut(&O) -> T + Send + 'static,
409 ) -> Var<O> {
410 let mapping = self.map_bidi_any(
411 move |input| BoxAnyVarValue::new(map(input.downcast_ref::<T>().unwrap())),
412 move |output| BoxAnyVarValue::new(map_back(output.downcast_ref::<O>().unwrap())),
413 TypeId::of::<O>(),
414 );
415 Var::new_any(mapping)
416 }
417
418 /// Create a bidirectional mapping variable that modifies back instead of mapping back.
419 ///
420 /// # Examples
421 ///
422 /// Basic usage:
423 ///
424 /// ```
425 /// # use zng_var::*;
426 /// # use zng_txt::*;
427 /// let list_var = var(vec!['a', 'b', 'c']);
428 /// let first_var = list_var.map_bidi_modify(
429 /// // map:
430 /// |l| l.first().copied().unwrap_or('_'),
431 /// // modify_back:
432 /// |c, l| if l.is_empty() { l.push(*c) } else { l[0] = *c },
433 /// );
434 /// ```
435 ///
436 /// In the example above the `first_var` represents the first item on the vector in `list_var`. Note that the `map` closure
437 /// works the same as in [`map_bidi`], but the `modify_back` closure modifies the list. This is not a mapping that can be declared
438 /// with [`map_bidi`] as the mapping variable does not have the full list to map back.
439 ///
440 /// # Capabilities
441 ///
442 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static,
443 /// the `modify_back` closure is ignored.
444 ///
445 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable.
446 /// The mapping variable is another shared reference and it holds a strong reference to this variable.
447 /// The `map` closure is called again for every update of this variable that is not caused by the mapping variable.
448 /// The `modify_back` closure is called for every update of the mapping variable that was not caused by this variable.
449 ///
450 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
451 /// mapping variable is also contextual and will init for every context it is used in.
452 ///
453 /// Like other mappings and bindings cyclic updates are avoided automatically, if the `modify_back` closure touches/updates the value
454 /// a var instance tag is inserted after the closure returns, you do not need to mark it manually.
455 ///
456 /// [`map_bidi`]: Self::map_bidi
457 pub fn map_bidi_modify<O: VarValue>(
458 &self,
459 mut map: impl FnMut(&T) -> O + Send + 'static,
460 mut modify_back: impl FnMut(&O, &mut VarModify<T>) + Send + 'static,
461 ) -> Var<O> {
462 let mapping = self.map_bidi_modify_any(
463 move |input| BoxAnyVarValue::new(map(input.downcast_ref::<T>().unwrap())),
464 move |v, m| modify_back(v.downcast_ref::<O>().unwrap(), &mut m.downcast::<T>().unwrap()),
465 TypeId::of::<O>(),
466 );
467 Var::new_any(mapping)
468 }
469
470 /// Create a [`map_bidi`] that converts between `T` and `O` using [`Into`].
471 ///
472 /// [`map_bidi`]: Var::map_bidi
473 pub fn map_into_bidi<O>(&self) -> Var<O>
474 where
475 O: VarValue + Into<T>,
476 T: Into<O>,
477 {
478 self.map_bidi(|t| t.clone().into(), |o| o.clone().into())
479 }
480
481 /// Create a [`map_bidi_modify`] that references and clones `O` from `T` using `std::ops::Deref<Target = O>` and
482 /// modifies back using `std::ops::DerefMut<Target = O>`.
483 ///
484 /// [`map_bidi_modify`]: Self::map_bidi_modify
485 pub fn map_deref_mut<O>(&self) -> Var<O>
486 where
487 O: VarValue,
488 T: ops::Deref<Target = O>,
489 T: ops::DerefMut<Target = O>,
490 {
491 self.map_bidi_modify(
492 |input| T::deref(input).clone(),
493 |output, modify| *T::deref_mut(modify) = output.clone(),
494 )
495 }
496
497 /// Create a bidirectional mapping variable that can skip updates.
498 ///
499 /// If the `map` closure does not produce a value on init the `fallback_init` closure is called.
500 ///
501 /// # Examples
502 ///
503 /// Basic usage:
504 ///
505 /// ```
506 /// # use zng_var::*;
507 /// # use zng_txt::*;
508 /// let n_var = var(0u32);
509 /// let n_100_var = n_var.filter_map_bidi(
510 /// |n| Some(n * 100),
511 /// |n_100| {
512 /// let r = n_100 / 100;
513 /// if r < 100 { Some(r) } else { None }
514 /// },
515 /// || 0,
516 /// );
517 /// ```
518 ///
519 /// In the example above the `n_100_var` will update every time the `n_var` updates with any value and the `n_var` will
520 /// update every time the `n_100_var` updates with a value that `(n_100 / 100) < 100`.
521 ///
522 /// # Capabilities
523 ///
524 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static,
525 /// the `map_back` closure is ignored.
526 ///
527 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable.
528 /// The mapping variable is another shared reference and it holds a strong reference to this variable.
529 /// The `map` closure is called again for every update of this variable that is not caused by the mapping variable.
530 /// The `map_back` closure is called for every update of the mapping variable that was not caused by this variable.
531 ///
532 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
533 /// mapping variable is also contextual and will init for every context it is used in.
534 pub fn filter_map_bidi<O: VarValue>(
535 &self,
536 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
537 mut map_back: impl FnMut(&O) -> Option<T> + Send + 'static,
538 fallback_init: impl Fn() -> O + Send + 'static,
539 ) -> Var<O> {
540 let mapping = self.filter_map_bidi_any(
541 move |t| map(t.downcast_ref::<T>().unwrap()).map(BoxAnyVarValue::new),
542 move |o| map_back(o.downcast_ref::<O>().unwrap()).map(BoxAnyVarValue::new),
543 move || BoxAnyVarValue::new(fallback_init()),
544 TypeId::of::<O>(),
545 );
546 Var::new_any(mapping)
547 }
548
549 /// Create a [`filter_map_bidi`] that tries to convert between `T` to `O` using [`TryInto`].
550 ///
551 /// [`filter_map_bidi`]: Var::filter_map_bidi
552 pub fn filter_try_into_bidi<O, I>(&self, fallback_init: I) -> Var<O>
553 where
554 O: VarValue,
555 T: TryInto<O>,
556 O: TryInto<T>,
557 I: Fn() -> O + Send + Sync + 'static,
558 {
559 self.filter_map_bidi(|v| v.clone().try_into().ok(), |o| o.clone().try_into().ok(), fallback_init)
560 }
561
562 /// Create a flat mapping variable that *unwraps* an inner variable stored in the the value of this variable.
563 ///
564 /// # Capabilities
565 ///
566 /// If this variable is static the `map` closure is called immediately and dropped and the inner variable is returned.
567 ///
568 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable and
569 /// is called again for every update of this variable. The mapping variable is another shared reference and it holds
570 /// a strong reference to this variable and to the inner variable.
571 ///
572 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
573 /// mapping variable is also contextual and will init for every context it is used in.
574 ///
575 /// The mapping variable has the same capabilities of the inner variable, plus [`MODIFY_CHANGES`]. When the inner variable
576 /// is writeable the return variable is too.
577 ///
578 /// [`map`]: Var::map
579 /// [`MODIFY_CHANGES`]: crate::VarCapability::MODIFY_CHANGES
580 pub fn flat_map<O: VarValue>(&self, mut map: impl FnMut(&T) -> Var<O> + Send + 'static) -> Var<O> {
581 self.any.flat_map(move |v| map(v.downcast_ref::<T>().unwrap()))
582 }
583}
584impl<T: VarValue> Var<crate::VarEq<T>> {
585 /// Create a [`flat_map`] to the inner variable.
586 ///
587 /// [`flat_map`]: Self::flat_map
588 pub fn flatten(&self) -> Var<T> {
589 self.flat_map(|v| v.0.clone())
590 }
591}
592impl<T: VarValue> Var<Vec<T>> {
593 /// Create a flat mapping variable that maps each variable entry in `self` to a value entry in the output.
594 ///
595 /// This is similar to [`flat_map`], but operates over many inner variables in a `Vec` value. Note that the `map`
596 /// closure inputs are each item index and the item.
597 ///
598 /// # Capabilities
599 ///
600 /// If this variable is static the `map` closure is called immediately for each item and dropped. The selected inner variables
601 /// are merged into the mapping variable and will continue updating it.
602 ///
603 /// If this variable is a shared reference the `map` closure is called immediately for each item to init the result and will
604 /// be called again for each item for every update of this variable. The mapping variable is another shared reference and it holds
605 /// a strong reference to this variable and the inner variables.
606 ///
607 /// If this variable is contextual the initial `map` calls is deferred until first usage of the mapping variable. The
608 /// mapping variable is also contextual and will init for every context it is used in.
609 ///
610 /// The mapping variable is read-only.
611 ///
612 /// [`flat_map`]: Self::flat_map
613 pub fn flat_map_vec<O: VarValue>(&self, mut map: impl FnMut(usize, &T) -> Var<O> + Send + 'static) -> Var<Vec<O>> {
614 self.flat_map(move |vec| {
615 let item_vars: Vec<Var<O>> = vec.iter().enumerate().map(|(i, it)| map(i, it)).collect();
616 let out_value: Vec<O> = item_vars.iter().map(|v| v.get()).collect();
617 let out_var = crate::var(out_value);
618
619 for (i, item_var) in item_vars.iter().enumerate() {
620 item_var
621 .bind_modify(&out_var, move |item_value, out_value| {
622 if &out_value.value()[i] != item_value {
623 out_value.value_mut()[i] = item_value.clone();
624 }
625 })
626 .perm();
627 }
628 out_var.hold(item_vars).perm();
629
630 out_var.read_only()
631 })
632 }
633}
634/// Binding
635impl<T: VarValue> Var<T> {
636 /// Bind `other` to receive the new values from this variable.
637 ///
638 /// # Examples
639 ///
640 /// Basic usage:
641 ///
642 /// ```
643 /// # use zng_var::*;
644 /// #
645 /// let a = var(10);
646 /// let b = var(0);
647 ///
648 /// a.bind(&b).perm();
649 /// ```
650 ///
651 /// In the example above the variable `b` will be set every time the variable `a` updates. Note that the current
652 /// value is not propagated, only updates. You can use [`set_bind`] to assign the current value and bind.
653 ///
654 /// # Capabilities
655 ///
656 /// If this variable is const or the other variable is always read-only does nothing and returns a dummy handle.
657 ///
658 /// If any variable is contextual the binding is set on the current context inner variable.
659 ///
660 /// Neither variable holds the other, only a weak reference is used, if either variable or the handle is dropped the binding
661 /// is dropped.
662 ///
663 /// [`set_bind`]: Self::set_bind
664 pub fn bind(&self, other: &Var<T>) -> VarHandle {
665 self.any.bind(other)
666 }
667
668 /// Like [`bind`] but also sets `other` to the current value.
669 ///
670 /// Basic usage:
671 ///
672 /// ```
673 /// # fn demo() {
674 /// # use zng_var::*;
675 /// #
676 /// let a = var(10);
677 /// let b = var(0);
678 ///
679 /// a.set_bind(&b).perm();
680 /// # }
681 /// ```
682 ///
683 /// In the example above the variable `b` will be set to the current value of `a` and every time the variable `a` updates.
684 ///
685 /// # Capabilities
686 ///
687 /// If this variable is const or the other variable is always read-only does nothing and returns a dummy handle.
688 ///
689 /// If any variable is contextual the binding is set on the current context inner variable.
690 ///
691 /// Neither variable holds the other, only a weak reference is used, if either variable or the handle is dropped the binding
692 /// is dropped.
693 ///
694 /// [`bind`]: Self::bind
695 pub fn set_bind(&self, other: &Var<T>) -> VarHandle {
696 self.any.set_bind(other)
697 }
698
699 /// Bind `other` to receive the new values mapped from this variable.
700 ///
701 /// This has the same capabilities as [`bind`], but the `map` closure is called to produce the new value for `other`.
702 ///
703 /// # Examples
704 ///
705 /// Basic usage:
706 ///
707 /// ```
708 /// # use zng_var::*;
709 /// # use zng_txt::*;
710 /// let a = var(10);
711 /// let b = var(Txt::from(""));
712 ///
713 /// a.bind_map(&b, |&a| formatx!("{:?}", a * 2)).perm();
714 /// ```
715 ///
716 /// In the example above every time the variable `a` updates the variable `b` will be set to the text representation of the value times two.
717 ///
718 /// [`bind`]: Self::bind
719 pub fn bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> O + Send + 'static) -> VarHandle {
720 self.any.bind_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
721 }
722
723 /// Like [`bind_map`] but also sets `other` to the current value.
724 ///
725 /// This has the same capabilities as [`set_bind`], but the `map` closure is called to produce the new value for `other`.
726 ///
727 /// [`bind_map`]: Self::bind_map
728 /// [`set_bind`]: Self::set_bind
729 pub fn set_bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> O + Send + 'static) -> VarHandle {
730 self.any.set_bind_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
731 }
732
733 /// Bind `other` to be modified when this variable updates.
734 ///
735 /// This has the same capabilities as [`bind`], but the `modify` closure is called to modify `other` using a reference to the new value.
736 ///
737 /// # Examples
738 ///
739 /// Basic usage:
740 ///
741 /// ```
742 /// # use zng_var::*;
743 /// #
744 /// let a = var(10);
745 /// let b = var(vec![1, 2, 3]);
746 /// a.bind_modify(&b, |&a, b| {
747 /// if b.is_empty() {
748 /// b.push(a);
749 /// } else {
750 /// b[0] = a;
751 /// }
752 /// })
753 /// .perm();
754 /// ```
755 ///
756 /// In the example above the variable `b` first element is set to the updated value of `a`.
757 ///
758 /// [`bind`]: Self::bind
759 pub fn bind_modify<O: VarValue>(&self, other: &Var<O>, mut modify: impl FnMut(&T, &mut VarModify<O>) + Send + 'static) -> VarHandle {
760 self.any.bind_modify(other, move |v, m| modify(v.downcast_ref::<T>().unwrap(), m))
761 }
762
763 /// Bind `other` to receive the new values from this variable and this variable to receive new values from `other`.
764 ///
765 /// # Capabilities
766 ///
767 /// This has the same capabilities as [`bind`], it is equivalent of setting two bindings.
768 ///
769 /// The bindings are protected against cyclic updates, like all other mappings and bindings.
770 ///
771 /// [`bind`]: Self::bind
772 pub fn bind_bidi(&self, other: &Var<T>) -> VarHandles {
773 self.any.bind_bidi(other)
774 }
775
776 /// Bind `other` to receive the new mapped values from this variable and this variable to receive new mapped values from `other`.
777 ///
778 /// This has the same capabilities as [`bind_bidi`], but the `map` closure is called to produce the new value for `other`
779 /// and `map_back` is called to produce the new value for this variable.
780 ///
781 /// [`bind_bidi`]: Self::bind_bidi
782 pub fn bind_map_bidi<O: VarValue>(
783 &self,
784 other: &Var<O>,
785 mut map: impl FnMut(&T) -> O + Send + 'static,
786 mut map_back: impl FnMut(&O) -> T + Send + 'static,
787 ) -> VarHandles {
788 self.any.bind_map_bidi_any(
789 other,
790 move |v| BoxAnyVarValue::new(map(v.downcast_ref::<T>().unwrap())),
791 move |v| BoxAnyVarValue::new(map_back(v.downcast_ref::<O>().unwrap())),
792 )
793 }
794
795 /// Bind `other` to be modified when this variable updates and this variable to be modified when `other` updates.
796 ///
797 /// This has the same capabilities as [`bind_bidi`], but the `modify` closure is called to modify `other`
798 /// and `modify_back` is called to modify this variable.
799 ///
800 /// [`bind_bidi`]: Self::bind_bidi
801 pub fn bind_modify_bidi<O: VarValue>(
802 &self,
803 other: &Var<O>,
804 mut modify: impl FnMut(&T, &mut VarModify<O>) + Send + 'static,
805 mut modify_back: impl FnMut(&O, &mut VarModify<T>) + Send + 'static,
806 ) -> VarHandles {
807 self.any.bind_modify_bidi(
808 other,
809 move |v, m| modify(v.downcast_ref::<T>().unwrap(), m),
810 move |v, m| modify_back(v, &mut m.downcast::<T>().unwrap()),
811 )
812 }
813
814 /// Bind `other` to receive the new values filtered mapped from this variable.
815 ///
816 /// This has the same capabilities as [`bind_map`], except that `other` will only receive a new value if `map` returns a value.
817 ///
818 /// [`bind_map`]: Self::bind_map
819 pub fn bind_filter_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> Option<O> + Send + 'static) -> VarHandle {
820 self.any.bind_filter_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
821 }
822
823 /// Bind `other` to receive the new filtered mapped values from this variable and this variable to receive
824 /// new filtered mapped values from `other`.
825 pub fn bind_filter_map_bidi<O: VarValue>(
826 &self,
827 other: &Var<O>,
828 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
829 mut map_back: impl FnMut(&O) -> Option<T> + Send + 'static,
830 ) -> VarHandles {
831 self.any.bind_filter_map_bidi_any(
832 other,
833 move |v| map(v.downcast_ref::<T>().unwrap()).map(BoxAnyVarValue::new),
834 move |v| map_back(v.downcast_ref::<O>().unwrap()).map(BoxAnyVarValue::new),
835 )
836 }
837}
838/// Animation
839impl<T: VarValue> Var<T> {
840 /// Schedule a custom animation that targets this variable.
841 ///
842 /// The `animate` closure is called every frame, starting after next frame, the closure inputs are
843 /// the [`Animation`] args and *modify* access to the variable value, the args
844 /// can be used to calculate the new variable value and to control or stop the animation.
845 ///
846 /// # Examples
847 ///
848 /// Customs animation that displays the animation elapsed time:
849 ///
850 /// ```
851 /// # fn demo() {
852 /// # use zng_var::*;
853 /// # use zng_txt::*;
854 /// # use zng_unit::*;
855 /// let status = var(Txt::from("not animating"));
856 ///
857 /// status
858 /// .animate(|animation, value| {
859 /// let elapsed = animation.elapsed_dur();
860 /// if elapsed < 5.secs() {
861 /// value.set(formatx!("animating: elapsed {}ms", elapsed.as_millis()));
862 /// } else {
863 /// animation.stop();
864 /// value.set("not animating");
865 /// }
866 /// })
867 /// .perm();
868 /// # }
869 /// ```
870 ///
871 /// # Capabilities
872 ///
873 /// If the variable is always read-only no animation is created and a dummy handle returned.
874 ///
875 /// If this var is contextual the animation targets the current context var.
876 ///
877 /// The animation is stopped if this variable is dropped.
878 ///
879 /// [`Animation`]: Animation
880 pub fn animate(&self, mut animate: impl FnMut(&Animation, &mut VarModify<T>) + Send + 'static) -> AnimationHandle {
881 self.any.animate(move |a, v| animate(a, &mut v.downcast::<T>().unwrap()))
882 }
883
884 /// Schedule animations started by `animate`, the closure is called once at the start to begin, then again every time
885 /// the variable stops animating.
886 ///
887 /// This can be used to create a sequence of animations or to repeat an animation.
888 ///
889 /// # Examples
890 ///
891 /// Running multiple animations in sequence:
892 ///
893 /// ```
894 /// # fn demo() {
895 /// # use zng_var::{*, animation::*};
896 /// # use zng_txt::*;
897 /// # use zng_unit::*;
898 /// let status = var(Txt::from("not animating"));
899 ///
900 /// let mut stage = 0;
901 /// status
902 /// .sequence(move |status| {
903 /// stage += 1;
904 /// if stage < 5 {
905 /// status.animate(move |animation, value| {
906 /// let elapsed = animation.elapsed_stop(5.secs());
907 /// value.set(formatx!("animation {stage}: {}", elapsed.pct()));
908 /// })
909 /// } else {
910 /// status.set("not animating");
911 /// AnimationHandle::dummy()
912 /// }
913 /// })
914 /// .perm();
915 /// # }
916 /// ```
917 ///
918 /// # Capabilities
919 ///
920 /// The sequence stops when `animate` returns a dummy handle, or the variable is modified outside of `animate`,
921 /// or animations are disabled, or the returned handle is dropped.
922 pub fn sequence(&self, mut animate: impl FnMut(Var<T>) -> AnimationHandle + Send + 'static) -> VarHandle {
923 self.any.sequence(move |v| animate(Var::new_any(v)))
924 }
925
926 /// Schedule an easing transition from the `start_value` to `end_value`.
927 ///
928 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
929 ///
930 /// # Examples
931 ///
932 /// Basic usage:
933 ///
934 /// ```
935 /// # fn demo() {
936 /// # use zng_var::{*, animation::easing};
937 /// # use zng_unit::*;
938 /// let progress = var(0.pct());
939 ///
940 /// progress.set_ease(0.pct(), 100.pct(), 5.secs(), easing::linear).perm();
941 /// # }
942 /// ```
943 ///
944 /// Variable is reset to 0% at the start and them transition to 100% in 5 seconds with linear progression.
945 ///
946 /// # Capabilities
947 ///
948 /// See [`animate`] for details about animation capabilities.
949 ///
950 /// [`animate`]: Self::animate
951 pub fn set_ease(
952 &self,
953 start_value: impl Into<T>,
954 end_value: impl Into<T>,
955 duration: Duration,
956 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
957 ) -> AnimationHandle
958 where
959 T: Transitionable,
960 {
961 self.set_ease_with(start_value, end_value, duration, easing, Transition::sample)
962 }
963
964 /// Oscillate between `start_value` to `end_value` with an easing transition.
965 ///
966 /// The `duration` defines the easing duration between the two values. The animation will continue running
967 /// until the handle or the variable is dropped.
968 ///
969 /// Note that you can use [`sequence`] to create more complex looping animations.
970 ///
971 /// [`sequence`]: Var::sequence
972 pub fn set_ease_oci(
973 &self,
974 start_value: impl Into<T>,
975 end_value: impl Into<T>,
976 duration: Duration,
977 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
978 ) -> AnimationHandle
979 where
980 T: Transitionable,
981 {
982 self.set_ease_oci_with(start_value, end_value, duration, easing, Transition::sample)
983 }
984
985 /// Schedule an easing transition from the `start_value` to `end_value` using a custom value sampler.
986 ///
987 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
988 ///
989 /// See [`animate`] for details about animation capabilities.
990 ///
991 /// [`animate`]: Self::animate
992 pub fn set_ease_with(
993 &self,
994 start_value: impl Into<T>,
995 end_value: impl Into<T>,
996 duration: Duration,
997 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
998 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
999 ) -> AnimationHandle
1000 where
1001 T: Transitionable,
1002 {
1003 self.ease_impl(start_value.into(), end_value.into(), duration, easing, 999.fct(), sampler)
1004 }
1005
1006 /// Oscillate between `start_value` to `end_value` with an easing transition using a custom value sampler.
1007 ///
1008 /// The `duration` defines the easing duration between the two values.
1009 ///
1010 /// Note that you can use [`sequence`] to create more complex looping animations.
1011 ///
1012 /// [`sequence`]: Self::sequence
1013 pub fn set_ease_oci_with(
1014 &self,
1015 start_value: impl Into<T>,
1016 end_value: impl Into<T>,
1017 duration: Duration,
1018 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1019 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1020 ) -> AnimationHandle
1021 where
1022 T: Transitionable,
1023 {
1024 self.ease_oci_impl(start_value.into(), end_value.into(), duration, easing, 999.fct(), sampler)
1025 }
1026
1027 /// Schedule an easing transition from the current value to `new_value`.
1028 ///
1029 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
1030 ///
1031 /// See [`animate`] for details about animation capabilities.
1032 ///
1033 /// [`animate`]: Var::animate
1034 pub fn ease(
1035 &self,
1036 new_value: impl Into<T>,
1037 duration: Duration,
1038 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1039 ) -> AnimationHandle
1040 where
1041 T: Transitionable,
1042 {
1043 self.ease_with(new_value, duration, easing, Transition::sample)
1044 }
1045
1046 /// Oscillate between the current value and `new_value` with an easing transition.
1047 ///
1048 /// The `duration` defines the easing duration between the two values.
1049 ///
1050 /// Note that you can use [`sequence`] to create more complex looping animations.
1051 ///
1052 /// [`sequence`]: Var::sequence
1053 pub fn ease_oci(
1054 &self,
1055 new_value: impl Into<T>,
1056 duration: Duration,
1057 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1058 ) -> AnimationHandle
1059 where
1060 T: Transitionable,
1061 {
1062 self.ease_oci_with(new_value, duration, easing, Transition::sample)
1063 }
1064
1065 /// Schedule an easing transition from the current value to `new_value` using a custom value sampler.
1066 ///
1067 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
1068 ///
1069 /// See [`animate`] for details about animation capabilities.
1070 ///
1071 /// [`animate`]: Var::animate
1072 pub fn ease_with(
1073 &self,
1074 new_value: impl Into<T>,
1075 duration: Duration,
1076 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1077 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1078 ) -> AnimationHandle
1079 where
1080 T: Transitionable,
1081 {
1082 self.ease_impl(self.get(), new_value.into(), duration, easing, 0.fct(), sampler)
1083 }
1084
1085 /// Oscillate between the current value and `new_value` with an easing transition and a custom value sampler.
1086 ///
1087 /// The `duration` defines the easing duration between the two values.
1088 ///
1089 /// Note that you can use [`sequence`] to create more complex looping animations.
1090 ///
1091 /// [`sequence`]: Self::sequence
1092 pub fn ease_oci_with(
1093 &self,
1094 new_value: impl Into<T>,
1095 duration: Duration,
1096 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1097 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1098 ) -> AnimationHandle
1099 where
1100 T: Transitionable,
1101 {
1102 self.ease_oci_impl(self.get(), new_value.into(), duration, easing, 0.fct(), sampler)
1103 }
1104
1105 /// Schedule a keyframed transition animation for the variable, starting from the first key.
1106 ///
1107 /// The variable will be set to the first keyframe, then animated across all other keys.
1108 ///
1109 /// See [`animate`] for details about animations.
1110 ///
1111 /// [`animate`]: Self::animate
1112 pub fn set_ease_keyed(
1113 &self,
1114 keys: Vec<(Factor, T)>,
1115 duration: Duration,
1116 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1117 ) -> AnimationHandle
1118 where
1119 T: Transitionable,
1120 {
1121 self.set_ease_keyed_with(keys, duration, easing, TransitionKeyed::sample)
1122 }
1123
1124 /// Schedule a keyframed transition animation for the variable, starting from the first key, using a custom value sampler.
1125 ///
1126 /// The variable will be set to the first keyframe, then animated across all other keys.
1127 ///
1128 /// See [`animate`] for details about animations.
1129 ///
1130 /// [`animate`]: Self::animate
1131 pub fn set_ease_keyed_with(
1132 &self,
1133 keys: Vec<(Factor, T)>,
1134 duration: Duration,
1135 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1136 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1137 ) -> AnimationHandle
1138 where
1139 T: Transitionable,
1140 {
1141 if let Some(transition) = TransitionKeyed::new(keys) {
1142 self.ease_keyed_impl(transition, duration, easing, 999.fct(), sampler)
1143 } else {
1144 AnimationHandle::dummy()
1145 }
1146 }
1147
1148 /// Schedule a keyframed transition animation for the variable, starting from the current value.
1149 ///
1150 /// The variable will be set to the first keyframe, then animated across all other keys.
1151 ///
1152 /// See [`animate`] for details about animations.
1153 ///
1154 /// [`animate`]: Self::animate
1155 pub fn ease_keyed(
1156 &self,
1157 keys: Vec<(Factor, T)>,
1158 duration: Duration,
1159 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1160 ) -> AnimationHandle
1161 where
1162 T: Transitionable,
1163 {
1164 self.ease_keyed_with(keys, duration, easing, TransitionKeyed::sample)
1165 }
1166
1167 /// Schedule a keyframed transition animation for the variable, starting from the current value, using a custom value sampler.
1168 ///
1169 /// The variable will be set to the first keyframe, then animated across all other keys.
1170 ///
1171 /// See [`animate`] for details about animations.
1172 ///
1173 /// [`animate`]: Self::animate
1174 pub fn ease_keyed_with(
1175 &self,
1176 mut keys: Vec<(Factor, T)>,
1177 duration: Duration,
1178 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1179 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1180 ) -> AnimationHandle
1181 where
1182 T: Transitionable,
1183 {
1184 keys.insert(0, (0.fct(), self.get()));
1185
1186 let transition = TransitionKeyed::new(keys).unwrap();
1187 self.ease_keyed_impl(transition, duration, easing, 0.fct(), sampler)
1188 }
1189
1190 /// Set the variable to `new_value` after a `delay`.
1191 ///
1192 /// The variable [`is_animating`] until the delay elapses and the value is set.
1193 ///
1194 /// See [`animate`] for details about animations.
1195 ///
1196 /// [`is_animating`]: AnyVar::is_animating
1197 /// [`animate`]: Self::animate
1198 pub fn step(&self, new_value: impl Into<T>, delay: Duration) -> AnimationHandle {
1199 self.step_impl(new_value.into(), delay)
1200 }
1201
1202 /// Oscillate between the current value and `new_value`, every time the `delay` elapses the variable is set to the next value.
1203 pub fn step_oci(&self, new_value: impl Into<T>, delay: Duration) -> AnimationHandle {
1204 self.step_oci_impl([self.get(), new_value.into()], delay, false)
1205 }
1206
1207 /// Oscillate between `from` and `to`, the variable is set to `from` to start and every time the `delay` elapses
1208 /// the variable is set to the next value.
1209 pub fn set_step_oci(&self, from: impl Into<T>, to: impl Into<T>, delay: Duration) -> AnimationHandle {
1210 self.step_oci_impl([from.into(), to.into()], delay, true)
1211 }
1212
1213 /// Set the variable to a sequence of values as a time `duration` elapses.
1214 ///
1215 /// An animation curve is used to find the first factor in `steps` above or at the curve line at the current time,
1216 /// the variable is set to this step value, continuing animating across the next steps until the last or the animation end.
1217 /// The variable [`is_animating`] from the start, even if no step applies and stays *animating* until the last *step* applies
1218 /// or the duration is reached.
1219 ///
1220 /// # Examples
1221 ///
1222 /// Creates a variable that outputs text every 5% of a 5 seconds animation, advanced linearly.
1223 ///
1224 /// ```
1225 /// # use zng_var::{*, animation::easing};
1226 /// # use zng_txt::*;
1227 /// # use zng_unit::*;
1228 /// # fn demo(text_var: Var<Txt>) {
1229 /// let steps = (0..=100).step_by(5).map(|i| (i.pct().fct(), formatx!("{i}%"))).collect();
1230 /// # let _ =
1231 /// text_var.steps(steps, 5.secs(), easing::linear)
1232 /// # ;}
1233 /// ```
1234 ///
1235 /// The variable is set to `"0%"`, after 5% of the `duration` elapses it is set to `"5%"` and so on
1236 /// until the value is set to `"100%` at the end of the animation.
1237 ///
1238 /// Returns an [`AnimationHandle`]. See [`Var::animate`] for details about animations.
1239 ///
1240 /// [`is_animating`]: AnyVar::is_animating
1241 /// [`AnimationHandle`]: crate::animation::AnimationHandle
1242 pub fn steps(
1243 &self,
1244 steps: Vec<(Factor, T)>,
1245 duration: Duration,
1246 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1247 ) -> AnimationHandle {
1248 let mut prev_step = 999.fct();
1249 self.animate(move |a, vm| {
1250 let step = easing(a.elapsed_stop(duration));
1251 if step != prev_step {
1252 prev_step = step;
1253 if let Some(val) = steps.iter().find(|(f, _)| *f >= step).map(|(_, step)| step.clone()) {
1254 vm.set(val);
1255 }
1256 }
1257 })
1258 }
1259
1260 /// Starts an easing animation that *chases* a target value that can be changed using the [`ChaseAnimation<T>`] handle.
1261 pub fn chase(
1262 &self,
1263 first_target: impl Into<T>,
1264 duration: Duration,
1265 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1266 ) -> ChaseAnimation<T>
1267 where
1268 T: Transitionable,
1269 {
1270 self.chase_impl(first_target.into(), duration, easing)
1271 }
1272 fn chase_impl(
1273 &self,
1274 first_target: T,
1275 duration: Duration,
1276 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1277 ) -> ChaseAnimation<T>
1278 where
1279 T: Transitionable,
1280 {
1281 ChaseAnimation {
1282 handle: self.ease(first_target.clone(), duration, easing),
1283 target: first_target,
1284 var: self.current_context(),
1285 }
1286 }
1287
1288 /// Start a [`chase`] animation without a first target.
1289 ///
1290 /// Use [`ChaseAnimation<T>::set`] to set the first chase target.
1291 ///
1292 /// [`chase`]: Self::chase
1293 pub fn chase_begin(&self) -> ChaseAnimation<T>
1294 where
1295 T: Transitionable,
1296 {
1297 ChaseAnimation {
1298 handle: AnimationHandle::dummy(),
1299 target: self.get(),
1300 var: self.current_context(),
1301 }
1302 }
1303
1304 /// Create a vars that [`ease`] to each new value of `self`.
1305 ///
1306 /// Note that the mapping var can be [contextualized], see [`map`] for more details.
1307 ///
1308 /// If `self` can change the output variable will keep it alive.
1309 ///
1310 /// [contextualized]: crate::contextual_var
1311 /// [`ease`]: Var::ease
1312 /// [`map`]: Var::map
1313 pub fn easing(&self, duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + Sync + 'static) -> Var<T>
1314 where
1315 T: Transitionable,
1316 {
1317 self.easing_with(duration, easing, Transition::sample)
1318 }
1319
1320 /// Create a vars that [`ease_with`] to each new value of `self`.
1321 ///
1322 /// Note that the mapping var can be contextualized, see [`map`] for more details.
1323 /// If `self` is shared the output variable will hold a strong reference to it.
1324 ///
1325 /// [`ease_with`]: Var::ease_with
1326 /// [`map`]: Var::map
1327 pub fn easing_with(
1328 &self,
1329 duration: Duration,
1330 easing: impl Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
1331 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + Sync + 'static,
1332 ) -> Var<T>
1333 where
1334 T: Transitionable,
1335 {
1336 let caps = self.capabilities();
1337 if caps.is_const() {
1338 return self.clone();
1339 }
1340
1341 let fns = Arc::new((easing, sampler));
1342
1343 if caps.is_contextual() {
1344 let me = self.clone();
1345 return contextual_var(move || me.clone().easing_with_tail(duration, fns.clone()));
1346 }
1347
1348 self.easing_with_tail(duration, fns)
1349 }
1350 // to avoid infinite closure type (contextual case)
1351 fn easing_with_tail(
1352 &self,
1353 duration: Duration,
1354 fns: Arc<(
1355 impl Fn(EasingTime) -> Factor + Send + Sync + 'static,
1356 impl Fn(&Transition<T>, Factor) -> T + Send + Sync + 'static,
1357 )>,
1358 ) -> Var<T>
1359 where
1360 T: Transitionable,
1361 {
1362 let me = self.current_context();
1363
1364 let output = crate::var(me.get());
1365
1366 let weak_output = output.downgrade();
1367 let mut _ease_handle = AnimationHandle::dummy();
1368 me.hook(move |args| {
1369 if let Some(output) = weak_output.upgrade() {
1370 _ease_handle = output.ease_with(
1371 args.value().clone(),
1372 duration,
1373 clmv!(fns, |t| fns.0(t)),
1374 clmv!(fns, |t, s| fns.1(t, s)),
1375 );
1376 true
1377 } else {
1378 false
1379 }
1380 })
1381 .perm();
1382 output.hold(me).perm();
1383
1384 output.read_only()
1385 }
1386
1387 fn ease_impl(
1388 &self,
1389 start_value: T,
1390 end_value: T,
1391 duration: Duration,
1392 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1393 init_step: Factor, // set to 0 skips first frame, set to 999 includes first frame.
1394 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1395 ) -> AnimationHandle
1396 where
1397 T: Transitionable,
1398 {
1399 let transition = Transition::new(start_value, end_value);
1400 let mut prev_step = init_step;
1401 self.animate(move |a, vm| {
1402 let step = easing(a.elapsed_stop(duration));
1403
1404 if prev_step != step {
1405 vm.set(sampler(&transition, step));
1406 prev_step = step;
1407 }
1408 })
1409 }
1410
1411 fn ease_oci_impl(
1412 &self,
1413 start_value: T,
1414 end_value: T,
1415 duration: Duration,
1416 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1417 init_step: EasingStep, // set to 0 skips first frame, set to 999 includes first frame.
1418 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1419 ) -> AnimationHandle
1420 where
1421 T: Transitionable,
1422 {
1423 let transition = Transition::new(start_value, end_value);
1424 let mut prev_step = init_step;
1425 self.animate(move |a, vm| {
1426 let t = a.elapsed(duration);
1427 let mut step = easing(t);
1428 if a.count() % 2 != 0 {
1429 step = step.flip()
1430 }
1431 if t.is_end() {
1432 a.restart();
1433 }
1434
1435 if prev_step != step {
1436 vm.set(sampler(&transition, step));
1437 prev_step = step;
1438 }
1439 })
1440 }
1441
1442 fn ease_keyed_impl(
1443 &self,
1444 transition: TransitionKeyed<T>,
1445 duration: Duration,
1446 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1447 init_step: EasingStep,
1448 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1449 ) -> AnimationHandle
1450 where
1451 T: Transitionable,
1452 {
1453 let mut prev_step = init_step;
1454 self.animate(move |a, value| {
1455 let step = easing(a.elapsed_stop(duration));
1456
1457 if prev_step != step {
1458 value.set(sampler(&transition, step));
1459 prev_step = step;
1460 }
1461 })
1462 }
1463
1464 fn step_impl(&self, new_value: T, delay: Duration) -> AnimationHandle {
1465 let mut new_value = Some(new_value);
1466 self.animate(move |a, vm| {
1467 if !a.animations_enabled() || a.elapsed_dur() >= delay {
1468 a.stop();
1469 if let Some(nv) = new_value.take() {
1470 vm.set(nv);
1471 }
1472 } else {
1473 a.sleep(delay);
1474 }
1475 })
1476 }
1477
1478 fn step_oci_impl(&self, values: [T; 2], delay: Duration, mut set: bool) -> AnimationHandle {
1479 let mut first = false;
1480 self.animate(move |a, vm| {
1481 if !a.animations_enabled() || std::mem::take(&mut set) {
1482 vm.set(values[0].clone());
1483 } else if a.elapsed_dur() >= delay {
1484 if first {
1485 vm.set(values[0].clone());
1486 } else {
1487 vm.set(values[1].clone());
1488 }
1489 first = !first;
1490 }
1491 a.sleep(delay);
1492 })
1493 }
1494}
1495/// Transition animations
1496impl<T: VarValue + Transitionable> Var<T> {}
1497/// Value type.
1498impl<T: VarValue> Var<T> {
1499 /// Reference the variable without the strong value type.
1500 pub fn as_any(&self) -> &AnyVar {
1501 &self.any
1502 }
1503}
1504/// Variable type.
1505impl<T: VarValue> Var<T> {
1506 /// Create a weak reference to this variable.
1507 pub fn downgrade(&self) -> WeakVar<T> {
1508 WeakVar {
1509 any: self.any.downgrade(),
1510 _t: PhantomData,
1511 }
1512 }
1513
1514 /// Gets a clone of the var that is always read-only.
1515 ///
1516 /// The returned variable can still update if `self` is modified, but it does not have the `MODIFY` capability.
1517 pub fn read_only(&self) -> Var<T> {
1518 Var::new_any(self.any.read_only())
1519 }
1520
1521 /// Create a var that redirects to this variable until the first value update, then it disconnects as a separate variable.
1522 ///
1523 /// The return variable is *clone-on-write* and has the `MODIFY` capability independent of the source capabilities, when
1524 /// a modify request is made the source value is cloned and offered for modification, if modified the source variable is dropped,
1525 /// if the modify closure does not update the source variable is retained.
1526 pub fn cow(&self) -> Var<T> {
1527 Var::new_any(self.any.cow())
1528 }
1529
1530 /// Gets the underlying var in the current calling context.
1531 ///
1532 /// If this variable is [`CONTEXT`] returns a clone of the inner variable,
1533 /// otherwise returns a clone of this variable.
1534 ///
1535 /// [`CONTEXT`]: crate::VarCapability::CONTEXT
1536 pub fn current_context(&self) -> Var<T> {
1537 Var::new_any(self.any.current_context())
1538 }
1539
1540 /// Gets if this variable is the same as `other`.
1541 ///
1542 /// If this variable is [`SHARE`] compares the *pointer*. If this variable is local this is always `false`.
1543 ///
1544 /// [`SHARE`]: crate::VarCapability::SHARE
1545 pub fn var_eq(&self, other: &Self) -> bool {
1546 self.any.var_eq(&other.any)
1547 }
1548}
1549
1550/// Weak reference to a [`Var<T>`].
1551pub struct WeakVar<T: VarValue> {
1552 any: WeakAnyVar,
1553 _t: PhantomData<T>,
1554}
1555impl<T: VarValue> fmt::Debug for WeakVar<T> {
1556 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1557 f.debug_tuple("WeakVar").field(&self.any.0).finish()
1558 }
1559}
1560impl<T: VarValue> Clone for WeakVar<T> {
1561 fn clone(&self) -> Self {
1562 Self {
1563 any: self.any.clone(),
1564 _t: PhantomData,
1565 }
1566 }
1567}
1568impl<T: VarValue> From<WeakVar<T>> for WeakAnyVar {
1569 fn from(var: WeakVar<T>) -> Self {
1570 var.any
1571 }
1572}
1573impl<T: VarValue> ops::Deref for WeakVar<T> {
1574 type Target = WeakAnyVar;
1575
1576 fn deref(&self) -> &Self::Target {
1577 self.as_any()
1578 }
1579}
1580impl<T: VarValue> WeakVar<T> {
1581 /// Reference the weak variable without the strong value type.
1582 pub fn as_any(&self) -> &WeakAnyVar {
1583 &self.any
1584 }
1585
1586 /// Attempt to create a strong reference to the variable.
1587 pub fn upgrade(&self) -> Option<Var<T>> {
1588 self.any.upgrade().map(Var::new_any)
1589 }
1590}
1591
1592/// New read/write shared reference variable from any type that can convert into it.
1593pub fn var_from<T: VarValue>(initial_value: impl Into<T>) -> Var<T> {
1594 crate::var(initial_value.into())
1595}
1596
1597/// New read/write shared reference variable with default initial value.
1598pub fn var_default<T: VarValue + Default>() -> Var<T> {
1599 crate::var(T::default())
1600}
1601
1602/// New immutable variable that stores the `value` directly.
1603///
1604/// Cloning this variable clones the value.
1605pub fn const_var<T: VarValue>(value: T) -> Var<T> {
1606 Var::new_any(any_const_var(BoxAnyVarValue::new(value)))
1607}
1608
1609/// Type erased [`const_var`].
1610pub fn any_const_var(value: BoxAnyVarValue) -> AnyVar {
1611 AnyVar(crate::DynAnyVar::Const(crate::var_impl::const_var::ConstVar::new(value)))
1612}
1613
1614/// Weak variable that never upgrades.
1615pub fn weak_var<T: VarValue>() -> WeakVar<T> {
1616 WeakVar {
1617 any: weak_var_any(),
1618 _t: PhantomData,
1619 }
1620}
1621
1622/// Weak variable that never upgrades.
1623pub fn weak_var_any() -> WeakAnyVar {
1624 WeakAnyVar(crate::DynWeakAnyVar::Const(crate::var_impl::const_var::WeakConstVar))
1625}
1626
1627/// Arguments for [`Var::hook`].
1628pub struct VarHookArgs<'a, T: VarValue> {
1629 pub(super) any: &'a AnyVarHookArgs<'a>,
1630 pub(super) _t: PhantomData<&'a T>,
1631}
1632impl<'a, T: VarValue> VarHookArgs<'a, T> {
1633 /// Reference the updated value.
1634 pub fn value(&self) -> &'a T {
1635 self.any.value.downcast_ref::<T>().unwrap()
1636 }
1637}
1638impl<'a, T: VarValue> ops::Deref for VarHookArgs<'a, T> {
1639 type Target = AnyVarHookArgs<'a>;
1640
1641 fn deref(&self) -> &Self::Target {
1642 self.any
1643 }
1644}