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 mut item_vars: Vec<(Var<O>, VarHandle)> = vec.iter().enumerate().map(|(i, it)| (map(i, it), VarHandle::dummy())).collect();
616 let out_value: Vec<O> = item_vars.iter().map(|v| v.0.get()).collect();
617 let out_var = crate::var(out_value);
618
619 for (i, (item_var, handle)) in item_vars.iter_mut().enumerate() {
620 *handle = item_var.bind_modify(&out_var, move |item_value, out_value| {
621 if &out_value.value()[i] != item_value {
622 out_value.value_mut()[i] = item_value.clone();
623 }
624 });
625 }
626 out_var.hold(item_vars).perm();
627
628 out_var.read_only()
629 })
630 }
631}
632/// Binding
633impl<T: VarValue> Var<T> {
634 /// Bind `other` to receive the new values from this variable.
635 ///
636 /// # Examples
637 ///
638 /// Basic usage:
639 ///
640 /// ```
641 /// # use zng_var::*;
642 /// #
643 /// let a = var(10);
644 /// let b = var(0);
645 ///
646 /// a.bind(&b).perm();
647 /// ```
648 ///
649 /// In the example above the variable `b` will be set every time the variable `a` updates. Note that the current
650 /// value is not propagated, only updates. You can use [`set_bind`] to assign the current value and bind.
651 ///
652 /// # Capabilities
653 ///
654 /// If this variable is const or the other variable is always read-only does nothing and returns a dummy handle.
655 ///
656 /// If any variable is contextual the binding is set on the current context inner variable.
657 ///
658 /// Neither variable holds the other, only a weak reference is used, if either variable or the handle is dropped the binding
659 /// is dropped.
660 ///
661 /// [`set_bind`]: Self::set_bind
662 pub fn bind(&self, other: &Var<T>) -> VarHandle {
663 self.any.bind(other)
664 }
665
666 /// Like [`bind`] but also sets `other` to the current value.
667 ///
668 /// Basic usage:
669 ///
670 /// ```
671 /// # fn demo() {
672 /// # use zng_var::*;
673 /// #
674 /// let a = var(10);
675 /// let b = var(0);
676 ///
677 /// a.set_bind(&b).perm();
678 /// # }
679 /// ```
680 ///
681 /// In the example above the variable `b` will be set to the current value of `a` and every time the variable `a` updates.
682 ///
683 /// # Capabilities
684 ///
685 /// If this variable is const or the other variable is always read-only does nothing and returns a dummy handle.
686 ///
687 /// If any variable is contextual the binding is set on the current context inner variable.
688 ///
689 /// Neither variable holds the other, only a weak reference is used, if either variable or the handle is dropped the binding
690 /// is dropped.
691 ///
692 /// [`bind`]: Self::bind
693 pub fn set_bind(&self, other: &Var<T>) -> VarHandle {
694 self.any.set_bind(other)
695 }
696
697 /// Bind `other` to receive the new values mapped from this variable.
698 ///
699 /// This has the same capabilities as [`bind`], but the `map` closure is called to produce the new value for `other`.
700 ///
701 /// # Examples
702 ///
703 /// Basic usage:
704 ///
705 /// ```
706 /// # use zng_var::*;
707 /// # use zng_txt::*;
708 /// let a = var(10);
709 /// let b = var(Txt::from(""));
710 ///
711 /// a.bind_map(&b, |&a| formatx!("{:?}", a * 2)).perm();
712 /// ```
713 ///
714 /// 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.
715 ///
716 /// [`bind`]: Self::bind
717 pub fn bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> O + Send + 'static) -> VarHandle {
718 self.any.bind_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
719 }
720
721 /// Like [`bind_map`] but also sets `other` to the current value.
722 ///
723 /// This has the same capabilities as [`set_bind`], but the `map` closure is called to produce the new value for `other`.
724 ///
725 /// [`bind_map`]: Self::bind_map
726 /// [`set_bind`]: Self::set_bind
727 pub fn set_bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> O + Send + 'static) -> VarHandle {
728 self.any.set_bind_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
729 }
730
731 /// Bind `other` to be modified when this variable updates.
732 ///
733 /// This has the same capabilities as [`bind`], but the `modify` closure is called to modify `other` using a reference to the new value.
734 ///
735 /// # Examples
736 ///
737 /// Basic usage:
738 ///
739 /// ```
740 /// # use zng_var::*;
741 /// #
742 /// let a = var(10);
743 /// let b = var(vec![1, 2, 3]);
744 /// a.bind_modify(&b, |&a, b| {
745 /// if b.is_empty() {
746 /// b.push(a);
747 /// } else {
748 /// b[0] = a;
749 /// }
750 /// })
751 /// .perm();
752 /// ```
753 ///
754 /// In the example above the variable `b` first element is set to the updated value of `a`.
755 ///
756 /// [`bind`]: Self::bind
757 pub fn bind_modify<O: VarValue>(&self, other: &Var<O>, mut modify: impl FnMut(&T, &mut VarModify<O>) + Send + 'static) -> VarHandle {
758 self.any.bind_modify(other, move |v, m| modify(v.downcast_ref::<T>().unwrap(), m))
759 }
760
761 /// Bind `other` to receive the new values from this variable and this variable to receive new values from `other`.
762 ///
763 /// # Capabilities
764 ///
765 /// This has the same capabilities as [`bind`], it is equivalent of setting two bindings.
766 ///
767 /// The bindings are protected against cyclic updates, like all other mappings and bindings.
768 ///
769 /// [`bind`]: Self::bind
770 pub fn bind_bidi(&self, other: &Var<T>) -> VarHandles {
771 self.any.bind_bidi(other)
772 }
773
774 /// Bind `other` to receive the new mapped values from this variable and this variable to receive new mapped values from `other`.
775 ///
776 /// This has the same capabilities as [`bind_bidi`], but the `map` closure is called to produce the new value for `other`
777 /// and `map_back` is called to produce the new value for this variable.
778 ///
779 /// [`bind_bidi`]: Self::bind_bidi
780 pub fn bind_map_bidi<O: VarValue>(
781 &self,
782 other: &Var<O>,
783 mut map: impl FnMut(&T) -> O + Send + 'static,
784 mut map_back: impl FnMut(&O) -> T + Send + 'static,
785 ) -> VarHandles {
786 self.any.bind_map_bidi_any(
787 other,
788 move |v| BoxAnyVarValue::new(map(v.downcast_ref::<T>().unwrap())),
789 move |v| BoxAnyVarValue::new(map_back(v.downcast_ref::<O>().unwrap())),
790 )
791 }
792
793 /// Bind `other` to be modified when this variable updates and this variable to be modified when `other` updates.
794 ///
795 /// This has the same capabilities as [`bind_bidi`], but the `modify` closure is called to modify `other`
796 /// and `modify_back` is called to modify this variable.
797 ///
798 /// [`bind_bidi`]: Self::bind_bidi
799 pub fn bind_modify_bidi<O: VarValue>(
800 &self,
801 other: &Var<O>,
802 mut modify: impl FnMut(&T, &mut VarModify<O>) + Send + 'static,
803 mut modify_back: impl FnMut(&O, &mut VarModify<T>) + Send + 'static,
804 ) -> VarHandles {
805 self.any.bind_modify_bidi(
806 other,
807 move |v, m| modify(v.downcast_ref::<T>().unwrap(), m),
808 move |v, m| modify_back(v, &mut m.downcast::<T>().unwrap()),
809 )
810 }
811
812 /// Bind `other` to receive the new values filtered mapped from this variable.
813 ///
814 /// This has the same capabilities as [`bind_map`], except that `other` will only receive a new value if `map` returns a value.
815 ///
816 /// [`bind_map`]: Self::bind_map
817 pub fn bind_filter_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> Option<O> + Send + 'static) -> VarHandle {
818 self.any.bind_filter_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
819 }
820
821 /// Bind `other` to receive the new filtered mapped values from this variable and this variable to receive
822 /// new filtered mapped values from `other`.
823 pub fn bind_filter_map_bidi<O: VarValue>(
824 &self,
825 other: &Var<O>,
826 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
827 mut map_back: impl FnMut(&O) -> Option<T> + Send + 'static,
828 ) -> VarHandles {
829 self.any.bind_filter_map_bidi_any(
830 other,
831 move |v| map(v.downcast_ref::<T>().unwrap()).map(BoxAnyVarValue::new),
832 move |v| map_back(v.downcast_ref::<O>().unwrap()).map(BoxAnyVarValue::new),
833 )
834 }
835}
836/// Animation
837impl<T: VarValue> Var<T> {
838 /// Schedule a custom animation that targets this variable.
839 ///
840 /// The `animate` closure is called every frame, starting after next frame, the closure inputs are
841 /// the [`Animation`] args and *modify* access to the variable value, the args
842 /// can be used to calculate the new variable value and to control or stop the animation.
843 ///
844 /// # Examples
845 ///
846 /// Customs animation that displays the animation elapsed time:
847 ///
848 /// ```
849 /// # fn demo() {
850 /// # use zng_var::*;
851 /// # use zng_txt::*;
852 /// # use zng_unit::*;
853 /// let status = var(Txt::from("not animating"));
854 ///
855 /// status
856 /// .animate(|animation, value| {
857 /// let elapsed = animation.elapsed_dur();
858 /// if elapsed < 5.secs() {
859 /// value.set(formatx!("animating: elapsed {}ms", elapsed.as_millis()));
860 /// } else {
861 /// animation.stop();
862 /// value.set("not animating");
863 /// }
864 /// })
865 /// .perm();
866 /// # }
867 /// ```
868 ///
869 /// # Capabilities
870 ///
871 /// If the variable is always read-only no animation is created and a dummy handle returned.
872 ///
873 /// If this var is contextual the animation targets the current context var.
874 ///
875 /// The animation is stopped if this variable is dropped.
876 ///
877 /// [`Animation`]: Animation
878 pub fn animate(&self, mut animate: impl FnMut(&Animation, &mut VarModify<T>) + Send + 'static) -> AnimationHandle {
879 self.any.animate(move |a, v| animate(a, &mut v.downcast::<T>().unwrap()))
880 }
881
882 /// Schedule animations started by `animate`, the closure is called once at the start to begin, then again every time
883 /// the variable stops animating.
884 ///
885 /// This can be used to create a sequence of animations or to repeat an animation.
886 ///
887 /// # Examples
888 ///
889 /// Running multiple animations in sequence:
890 ///
891 /// ```
892 /// # fn demo() {
893 /// # use zng_var::{*, animation::*};
894 /// # use zng_txt::*;
895 /// # use zng_unit::*;
896 /// let status = var(Txt::from("not animating"));
897 ///
898 /// let mut stage = 0;
899 /// status
900 /// .sequence(move |status| {
901 /// stage += 1;
902 /// if stage < 5 {
903 /// status.animate(move |animation, value| {
904 /// let elapsed = animation.elapsed_stop(5.secs());
905 /// value.set(formatx!("animation {stage}: {}", elapsed.pct()));
906 /// })
907 /// } else {
908 /// status.set("not animating");
909 /// AnimationHandle::dummy()
910 /// }
911 /// })
912 /// .perm();
913 /// # }
914 /// ```
915 ///
916 /// # Capabilities
917 ///
918 /// The sequence stops when `animate` returns a dummy handle, or the variable is modified outside of `animate`,
919 /// or animations are disabled, or the returned handle is dropped.
920 pub fn sequence(&self, mut animate: impl FnMut(Var<T>) -> AnimationHandle + Send + 'static) -> VarHandle {
921 self.any.sequence(move |v| animate(Var::new_any(v)))
922 }
923
924 /// Schedule an easing transition from the `start_value` to `end_value`.
925 ///
926 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
927 ///
928 /// # Examples
929 ///
930 /// Basic usage:
931 ///
932 /// ```
933 /// # fn demo() {
934 /// # use zng_var::{*, animation::easing};
935 /// # use zng_unit::*;
936 /// let progress = var(0.pct());
937 ///
938 /// progress.set_ease(0.pct(), 100.pct(), 5.secs(), easing::linear).perm();
939 /// # }
940 /// ```
941 ///
942 /// Variable is reset to 0% at the start and them transition to 100% in 5 seconds with linear progression.
943 ///
944 /// # Capabilities
945 ///
946 /// See [`animate`] for details about animation capabilities.
947 ///
948 /// [`animate`]: Self::animate
949 pub fn set_ease(
950 &self,
951 start_value: impl Into<T>,
952 end_value: impl Into<T>,
953 duration: Duration,
954 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
955 ) -> AnimationHandle
956 where
957 T: Transitionable,
958 {
959 self.set_ease_with(start_value, end_value, duration, easing, Transition::sample)
960 }
961
962 /// Oscillate between `start_value` to `end_value` with an easing transition.
963 ///
964 /// The `duration` defines the easing duration between the two values. The animation will continue running
965 /// until the handle or the variable is dropped.
966 ///
967 /// Note that you can use [`sequence`] to create more complex looping animations.
968 ///
969 /// [`sequence`]: Var::sequence
970 pub fn set_ease_oci(
971 &self,
972 start_value: impl Into<T>,
973 end_value: impl Into<T>,
974 duration: Duration,
975 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
976 ) -> AnimationHandle
977 where
978 T: Transitionable,
979 {
980 self.set_ease_oci_with(start_value, end_value, duration, easing, Transition::sample)
981 }
982
983 /// Schedule an easing transition from the `start_value` to `end_value` using a custom value sampler.
984 ///
985 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
986 ///
987 /// See [`animate`] for details about animation capabilities.
988 ///
989 /// [`animate`]: Self::animate
990 pub fn set_ease_with(
991 &self,
992 start_value: impl Into<T>,
993 end_value: impl Into<T>,
994 duration: Duration,
995 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
996 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
997 ) -> AnimationHandle
998 where
999 T: Transitionable,
1000 {
1001 self.ease_impl(start_value.into(), end_value.into(), duration, easing, 999.fct(), sampler)
1002 }
1003
1004 /// Oscillate between `start_value` to `end_value` with an easing transition using a custom value sampler.
1005 ///
1006 /// The `duration` defines the easing duration between the two values.
1007 ///
1008 /// Note that you can use [`sequence`] to create more complex looping animations.
1009 ///
1010 /// [`sequence`]: Self::sequence
1011 pub fn set_ease_oci_with(
1012 &self,
1013 start_value: impl Into<T>,
1014 end_value: impl Into<T>,
1015 duration: Duration,
1016 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1017 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1018 ) -> AnimationHandle
1019 where
1020 T: Transitionable,
1021 {
1022 self.ease_oci_impl(start_value.into(), end_value.into(), duration, easing, 999.fct(), sampler)
1023 }
1024
1025 /// Schedule an easing transition from the current value to `new_value`.
1026 ///
1027 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
1028 ///
1029 /// See [`animate`] for details about animation capabilities.
1030 ///
1031 /// [`animate`]: Var::animate
1032 pub fn ease(
1033 &self,
1034 new_value: impl Into<T>,
1035 duration: Duration,
1036 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1037 ) -> AnimationHandle
1038 where
1039 T: Transitionable,
1040 {
1041 self.ease_with(new_value, duration, easing, Transition::sample)
1042 }
1043
1044 /// Oscillate between the current value and `new_value` with an easing transition.
1045 ///
1046 /// The `duration` defines the easing duration between the two values.
1047 ///
1048 /// Note that you can use [`sequence`] to create more complex looping animations.
1049 ///
1050 /// [`sequence`]: Var::sequence
1051 pub fn ease_oci(
1052 &self,
1053 new_value: impl Into<T>,
1054 duration: Duration,
1055 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1056 ) -> AnimationHandle
1057 where
1058 T: Transitionable,
1059 {
1060 self.ease_oci_with(new_value, duration, easing, Transition::sample)
1061 }
1062
1063 /// Schedule an easing transition from the current value to `new_value` using a custom value sampler.
1064 ///
1065 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
1066 ///
1067 /// See [`animate`] for details about animation capabilities.
1068 ///
1069 /// [`animate`]: Var::animate
1070 pub fn ease_with(
1071 &self,
1072 new_value: impl Into<T>,
1073 duration: Duration,
1074 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1075 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1076 ) -> AnimationHandle
1077 where
1078 T: Transitionable,
1079 {
1080 self.ease_impl(self.get(), new_value.into(), duration, easing, 0.fct(), sampler)
1081 }
1082
1083 /// Oscillate between the current value and `new_value` with an easing transition and a custom value sampler.
1084 ///
1085 /// The `duration` defines the easing duration between the two values.
1086 ///
1087 /// Note that you can use [`sequence`] to create more complex looping animations.
1088 ///
1089 /// [`sequence`]: Self::sequence
1090 pub fn ease_oci_with(
1091 &self,
1092 new_value: impl Into<T>,
1093 duration: Duration,
1094 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1095 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1096 ) -> AnimationHandle
1097 where
1098 T: Transitionable,
1099 {
1100 self.ease_oci_impl(self.get(), new_value.into(), duration, easing, 0.fct(), sampler)
1101 }
1102
1103 /// Schedule a keyframed transition animation for the variable, starting from the first key.
1104 ///
1105 /// The variable will be set to the first keyframe, then animated across all other keys.
1106 ///
1107 /// See [`animate`] for details about animations.
1108 ///
1109 /// [`animate`]: Self::animate
1110 pub fn set_ease_keyed(
1111 &self,
1112 keys: Vec<(Factor, T)>,
1113 duration: Duration,
1114 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1115 ) -> AnimationHandle
1116 where
1117 T: Transitionable,
1118 {
1119 self.set_ease_keyed_with(keys, duration, easing, TransitionKeyed::sample)
1120 }
1121
1122 /// Schedule a keyframed transition animation for the variable, starting from the first key, using a custom value sampler.
1123 ///
1124 /// The variable will be set to the first keyframe, then animated across all other keys.
1125 ///
1126 /// See [`animate`] for details about animations.
1127 ///
1128 /// [`animate`]: Self::animate
1129 pub fn set_ease_keyed_with(
1130 &self,
1131 keys: Vec<(Factor, T)>,
1132 duration: Duration,
1133 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1134 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1135 ) -> AnimationHandle
1136 where
1137 T: Transitionable,
1138 {
1139 if let Some(transition) = TransitionKeyed::new(keys) {
1140 self.ease_keyed_impl(transition, duration, easing, 999.fct(), sampler)
1141 } else {
1142 AnimationHandle::dummy()
1143 }
1144 }
1145
1146 /// Schedule a keyframed transition animation for the variable, starting from the current value.
1147 ///
1148 /// The variable will be set to the first keyframe, then animated across all other keys.
1149 ///
1150 /// See [`animate`] for details about animations.
1151 ///
1152 /// [`animate`]: Self::animate
1153 pub fn ease_keyed(
1154 &self,
1155 keys: Vec<(Factor, T)>,
1156 duration: Duration,
1157 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1158 ) -> AnimationHandle
1159 where
1160 T: Transitionable,
1161 {
1162 self.ease_keyed_with(keys, duration, easing, TransitionKeyed::sample)
1163 }
1164
1165 /// Schedule a keyframed transition animation for the variable, starting from the current value, using a custom value sampler.
1166 ///
1167 /// The variable will be set to the first keyframe, then animated across all other keys.
1168 ///
1169 /// See [`animate`] for details about animations.
1170 ///
1171 /// [`animate`]: Self::animate
1172 pub fn ease_keyed_with(
1173 &self,
1174 mut keys: Vec<(Factor, T)>,
1175 duration: Duration,
1176 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1177 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1178 ) -> AnimationHandle
1179 where
1180 T: Transitionable,
1181 {
1182 keys.insert(0, (0.fct(), self.get()));
1183
1184 let transition = TransitionKeyed::new(keys).unwrap();
1185 self.ease_keyed_impl(transition, duration, easing, 0.fct(), sampler)
1186 }
1187
1188 /// Set the variable to `new_value` after a `delay`.
1189 ///
1190 /// The variable [`is_animating`] until the delay elapses and the value is set.
1191 ///
1192 /// See [`animate`] for details about animations.
1193 ///
1194 /// [`is_animating`]: AnyVar::is_animating
1195 /// [`animate`]: Self::animate
1196 pub fn step(&self, new_value: impl Into<T>, delay: Duration) -> AnimationHandle {
1197 self.step_impl(new_value.into(), delay)
1198 }
1199
1200 /// Oscillate between the current value and `new_value`, every time the `delay` elapses the variable is set to the next value.
1201 pub fn step_oci(&self, new_value: impl Into<T>, delay: Duration) -> AnimationHandle {
1202 self.step_oci_impl([self.get(), new_value.into()], delay, false)
1203 }
1204
1205 /// Oscillate between `from` and `to`, the variable is set to `from` to start and every time the `delay` elapses
1206 /// the variable is set to the next value.
1207 pub fn set_step_oci(&self, from: impl Into<T>, to: impl Into<T>, delay: Duration) -> AnimationHandle {
1208 self.step_oci_impl([from.into(), to.into()], delay, true)
1209 }
1210
1211 /// Set the variable to a sequence of values as a time `duration` elapses.
1212 ///
1213 /// An animation curve is used to find the first factor in `steps` above or at the curve line at the current time,
1214 /// the variable is set to this step value, continuing animating across the next steps until the last or the animation end.
1215 /// The variable [`is_animating`] from the start, even if no step applies and stays *animating* until the last *step* applies
1216 /// or the duration is reached.
1217 ///
1218 /// # Examples
1219 ///
1220 /// Creates a variable that outputs text every 5% of a 5 seconds animation, advanced linearly.
1221 ///
1222 /// ```
1223 /// # use zng_var::{*, animation::easing};
1224 /// # use zng_txt::*;
1225 /// # use zng_unit::*;
1226 /// # fn demo(text_var: Var<Txt>) {
1227 /// let steps = (0..=100).step_by(5).map(|i| (i.pct().fct(), formatx!("{i}%"))).collect();
1228 /// # let _ =
1229 /// text_var.steps(steps, 5.secs(), easing::linear)
1230 /// # ;}
1231 /// ```
1232 ///
1233 /// The variable is set to `"0%"`, after 5% of the `duration` elapses it is set to `"5%"` and so on
1234 /// until the value is set to `"100%` at the end of the animation.
1235 ///
1236 /// Returns an [`AnimationHandle`]. See [`Var::animate`] for details about animations.
1237 ///
1238 /// [`is_animating`]: AnyVar::is_animating
1239 /// [`AnimationHandle`]: crate::animation::AnimationHandle
1240 pub fn steps(
1241 &self,
1242 steps: Vec<(Factor, T)>,
1243 duration: Duration,
1244 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1245 ) -> AnimationHandle {
1246 let mut prev_step = 999.fct();
1247 self.animate(move |a, vm| {
1248 let step = easing(a.elapsed_stop(duration));
1249 if step != prev_step {
1250 prev_step = step;
1251 if let Some(val) = steps.iter().find(|(f, _)| *f >= step).map(|(_, step)| step.clone()) {
1252 vm.set(val);
1253 }
1254 }
1255 })
1256 }
1257
1258 /// Starts an easing animation that *chases* a target value that can be changed using the [`ChaseAnimation<T>`] handle.
1259 pub fn chase(
1260 &self,
1261 first_target: impl Into<T>,
1262 duration: Duration,
1263 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1264 ) -> ChaseAnimation<T>
1265 where
1266 T: Transitionable,
1267 {
1268 self.chase_impl(first_target.into(), duration, easing)
1269 }
1270 fn chase_impl(
1271 &self,
1272 first_target: T,
1273 duration: Duration,
1274 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1275 ) -> ChaseAnimation<T>
1276 where
1277 T: Transitionable,
1278 {
1279 ChaseAnimation {
1280 handle: self.ease(first_target.clone(), duration, easing),
1281 target: first_target,
1282 var: self.current_context(),
1283 }
1284 }
1285
1286 /// Start a [`chase`] animation without a first target.
1287 ///
1288 /// Use [`ChaseAnimation<T>::set`] to set the first chase target.
1289 ///
1290 /// [`chase`]: Self::chase
1291 pub fn chase_begin(&self) -> ChaseAnimation<T>
1292 where
1293 T: Transitionable,
1294 {
1295 ChaseAnimation {
1296 handle: AnimationHandle::dummy(),
1297 target: self.get(),
1298 var: self.current_context(),
1299 }
1300 }
1301
1302 /// Create a vars that [`ease`] to each new value of `self`.
1303 ///
1304 /// Note that the mapping var can be [contextualized], see [`map`] for more details.
1305 ///
1306 /// If `self` can change the output variable will keep it alive.
1307 ///
1308 /// [contextualized]: crate::contextual_var
1309 /// [`ease`]: Var::ease
1310 /// [`map`]: Var::map
1311 pub fn easing(&self, duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + Sync + 'static) -> Var<T>
1312 where
1313 T: Transitionable,
1314 {
1315 self.easing_with(duration, easing, Transition::sample)
1316 }
1317
1318 /// Create a vars that [`ease_with`] to each new value of `self`.
1319 ///
1320 /// Note that the mapping var can be contextualized, see [`map`] for more details.
1321 /// If `self` is shared the output variable will hold a strong reference to it.
1322 ///
1323 /// [`ease_with`]: Var::ease_with
1324 /// [`map`]: Var::map
1325 pub fn easing_with(
1326 &self,
1327 duration: Duration,
1328 easing: impl Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
1329 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + Sync + 'static,
1330 ) -> Var<T>
1331 where
1332 T: Transitionable,
1333 {
1334 let caps = self.capabilities();
1335 if caps.is_const() {
1336 return self.clone();
1337 }
1338
1339 let fns = Arc::new((easing, sampler));
1340
1341 if caps.is_contextual() {
1342 let me = self.clone();
1343 return contextual_var(move || me.clone().easing_with_tail(duration, fns.clone()));
1344 }
1345
1346 self.easing_with_tail(duration, fns)
1347 }
1348 // to avoid infinite closure type (contextual case)
1349 fn easing_with_tail(
1350 &self,
1351 duration: Duration,
1352 fns: Arc<(
1353 impl Fn(EasingTime) -> Factor + Send + Sync + 'static,
1354 impl Fn(&Transition<T>, Factor) -> T + Send + Sync + 'static,
1355 )>,
1356 ) -> Var<T>
1357 where
1358 T: Transitionable,
1359 {
1360 let me = self.current_context();
1361
1362 let output = crate::var(me.get());
1363
1364 let weak_output = output.downgrade();
1365 let mut _ease_handle = AnimationHandle::dummy();
1366 me.hook(move |args| {
1367 if let Some(output) = weak_output.upgrade() {
1368 _ease_handle = output.ease_with(
1369 args.value().clone(),
1370 duration,
1371 clmv!(fns, |t| fns.0(t)),
1372 clmv!(fns, |t, s| fns.1(t, s)),
1373 );
1374 true
1375 } else {
1376 false
1377 }
1378 })
1379 .perm();
1380 output.hold(me).perm();
1381
1382 output.read_only()
1383 }
1384
1385 fn ease_impl(
1386 &self,
1387 start_value: T,
1388 end_value: T,
1389 duration: Duration,
1390 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1391 init_step: Factor, // set to 0 skips first frame, set to 999 includes first frame.
1392 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1393 ) -> AnimationHandle
1394 where
1395 T: Transitionable,
1396 {
1397 let transition = Transition::new(start_value, end_value);
1398 let mut prev_step = init_step;
1399 self.animate(move |a, vm| {
1400 let step = easing(a.elapsed_stop(duration));
1401
1402 if prev_step != step {
1403 vm.set(sampler(&transition, step));
1404 prev_step = step;
1405 }
1406 })
1407 }
1408
1409 fn ease_oci_impl(
1410 &self,
1411 start_value: T,
1412 end_value: T,
1413 duration: Duration,
1414 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1415 init_step: EasingStep, // set to 0 skips first frame, set to 999 includes first frame.
1416 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1417 ) -> AnimationHandle
1418 where
1419 T: Transitionable,
1420 {
1421 let transition = Transition::new(start_value, end_value);
1422 let mut prev_step = init_step;
1423 self.animate(move |a, vm| {
1424 let t = a.elapsed(duration);
1425 let mut step = easing(t);
1426 if a.count() % 2 != 0 {
1427 step = step.flip()
1428 }
1429 if t.is_end() {
1430 a.restart();
1431 }
1432
1433 if prev_step != step {
1434 vm.set(sampler(&transition, step));
1435 prev_step = step;
1436 }
1437 })
1438 }
1439
1440 fn ease_keyed_impl(
1441 &self,
1442 transition: TransitionKeyed<T>,
1443 duration: Duration,
1444 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1445 init_step: EasingStep,
1446 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1447 ) -> AnimationHandle
1448 where
1449 T: Transitionable,
1450 {
1451 let mut prev_step = init_step;
1452 self.animate(move |a, value| {
1453 let step = easing(a.elapsed_stop(duration));
1454
1455 if prev_step != step {
1456 value.set(sampler(&transition, step));
1457 prev_step = step;
1458 }
1459 })
1460 }
1461
1462 fn step_impl(&self, new_value: T, delay: Duration) -> AnimationHandle {
1463 let mut new_value = Some(new_value);
1464 self.animate(move |a, vm| {
1465 if !a.animations_enabled() || a.elapsed_dur() >= delay {
1466 a.stop();
1467 if let Some(nv) = new_value.take() {
1468 vm.set(nv);
1469 }
1470 } else {
1471 a.sleep(delay, false);
1472 }
1473 })
1474 }
1475
1476 fn step_oci_impl(&self, values: [T; 2], delay: Duration, mut set: bool) -> AnimationHandle {
1477 let mut first = false;
1478 self.animate(move |a, vm| {
1479 if !a.animations_enabled() || std::mem::take(&mut set) {
1480 vm.set(values[0].clone());
1481 } else if a.elapsed_dur() >= delay {
1482 if first {
1483 vm.set(values[0].clone());
1484 } else {
1485 vm.set(values[1].clone());
1486 }
1487 first = !first;
1488 }
1489 a.sleep(delay, false);
1490 })
1491 }
1492}
1493/// Transition animations
1494impl<T: VarValue + Transitionable> Var<T> {}
1495/// Value type.
1496impl<T: VarValue> Var<T> {
1497 /// Reference the variable without the strong value type.
1498 pub fn as_any(&self) -> &AnyVar {
1499 &self.any
1500 }
1501}
1502/// Variable type.
1503impl<T: VarValue> Var<T> {
1504 /// Create a weak reference to this variable.
1505 pub fn downgrade(&self) -> WeakVar<T> {
1506 WeakVar {
1507 any: self.any.downgrade(),
1508 _t: PhantomData,
1509 }
1510 }
1511
1512 /// Gets a clone of the var that is always read-only.
1513 ///
1514 /// The returned variable can still update if `self` is modified, but it does not have the `MODIFY` capability.
1515 pub fn read_only(&self) -> Var<T> {
1516 Var::new_any(self.any.read_only())
1517 }
1518
1519 /// Create a var that redirects to this variable until the first value update, then it disconnects as a separate variable.
1520 ///
1521 /// The return variable is *clone-on-write* and has the `MODIFY` capability independent of the source capabilities, when
1522 /// a modify request is made the source value is cloned and offered for modification, if modified the source variable is dropped,
1523 /// if the modify closure does not update the source variable is retained.
1524 pub fn cow(&self) -> Var<T> {
1525 Var::new_any(self.any.cow())
1526 }
1527
1528 /// Gets the underlying var in the current calling context.
1529 ///
1530 /// If this variable is [`CONTEXT`] returns a clone of the inner variable,
1531 /// otherwise returns a clone of this variable.
1532 ///
1533 /// [`CONTEXT`]: crate::VarCapability::CONTEXT
1534 pub fn current_context(&self) -> Var<T> {
1535 Var::new_any(self.any.current_context())
1536 }
1537
1538 /// Gets if this variable is the same as `other`.
1539 ///
1540 /// If this variable is [`SHARE`] compares the *pointer*. If this variable is local this is always `false`.
1541 ///
1542 /// [`SHARE`]: crate::VarCapability::SHARE
1543 pub fn var_eq(&self, other: &Self) -> bool {
1544 self.any.var_eq(&other.any)
1545 }
1546}
1547
1548/// Weak reference to a [`Var<T>`].
1549pub struct WeakVar<T: VarValue> {
1550 any: WeakAnyVar,
1551 _t: PhantomData<T>,
1552}
1553impl<T: VarValue> fmt::Debug for WeakVar<T> {
1554 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1555 f.debug_tuple("WeakVar").field(&self.any.0).finish()
1556 }
1557}
1558impl<T: VarValue> Clone for WeakVar<T> {
1559 fn clone(&self) -> Self {
1560 Self {
1561 any: self.any.clone(),
1562 _t: PhantomData,
1563 }
1564 }
1565}
1566impl<T: VarValue> From<WeakVar<T>> for WeakAnyVar {
1567 fn from(var: WeakVar<T>) -> Self {
1568 var.any
1569 }
1570}
1571impl<T: VarValue> ops::Deref for WeakVar<T> {
1572 type Target = WeakAnyVar;
1573
1574 fn deref(&self) -> &Self::Target {
1575 self.as_any()
1576 }
1577}
1578impl<T: VarValue> WeakVar<T> {
1579 /// Reference the weak variable without the strong value type.
1580 pub fn as_any(&self) -> &WeakAnyVar {
1581 &self.any
1582 }
1583
1584 /// Attempt to create a strong reference to the variable.
1585 pub fn upgrade(&self) -> Option<Var<T>> {
1586 self.any.upgrade().map(Var::new_any)
1587 }
1588
1589 /// New weak var that does not upgrade.
1590 pub const fn new() -> Self {
1591 Self {
1592 any: WeakAnyVar::new(),
1593 _t: PhantomData,
1594 }
1595 }
1596}
1597impl<T: VarValue> Default for WeakVar<T> {
1598 fn default() -> Self {
1599 Self::new()
1600 }
1601}
1602
1603/// New read/write shared reference variable from any type that can convert into it.
1604pub fn var_from<T: VarValue>(initial_value: impl Into<T>) -> Var<T> {
1605 crate::var(initial_value.into())
1606}
1607
1608/// New read/write shared reference variable with default initial value.
1609pub fn var_default<T: VarValue + Default>() -> Var<T> {
1610 crate::var(T::default())
1611}
1612
1613/// New immutable variable that stores the `value` directly.
1614///
1615/// Cloning this variable clones the value.
1616pub fn const_var<T: VarValue>(value: T) -> Var<T> {
1617 Var::new_any(any_const_var(BoxAnyVarValue::new(value)))
1618}
1619
1620/// Type erased [`const_var`].
1621pub fn any_const_var(value: BoxAnyVarValue) -> AnyVar {
1622 AnyVar(crate::DynAnyVar::Const(crate::var_impl::const_var::ConstVar::new(value)))
1623}
1624
1625/// Weak variable that never upgrades.
1626pub fn weak_var<T: VarValue>() -> WeakVar<T> {
1627 WeakVar {
1628 any: weak_var_any(),
1629 _t: PhantomData,
1630 }
1631}
1632
1633/// Weak variable that never upgrades.
1634pub fn weak_var_any() -> WeakAnyVar {
1635 WeakAnyVar(crate::DynWeakAnyVar::Const(crate::var_impl::const_var::WeakConstVar))
1636}
1637
1638/// Arguments for [`Var::hook`].
1639pub struct VarHookArgs<'a, T: VarValue> {
1640 pub(super) any: &'a AnyVarHookArgs<'a>,
1641 pub(super) _t: PhantomData<&'a T>,
1642}
1643impl<'a, T: VarValue> VarHookArgs<'a, T> {
1644 /// Reference the updated value.
1645 pub fn value(&self) -> &'a T {
1646 self.any.value.downcast_ref::<T>().unwrap()
1647 }
1648}
1649impl<'a, T: VarValue> ops::Deref for VarHookArgs<'a, T> {
1650 type Target = AnyVarHookArgs<'a>;
1651
1652 fn deref(&self) -> &Self::Target {
1653 self.any
1654 }
1655}