Skip to main content

guise/anim/
animated.rs

1//! `Animated` — the element that plays a clip.
2//!
3//! Two shapes, one wrapper. Give it a [`Motion`] or a [`Sequence`] and it
4//! plays once when the element mounts, no state anywhere: gpui's animation
5//! element supplies the clock and the clip supplies the values, so a
6//! staggered list of fifty rows is fifty stateless builders. Give it an
7//! [`Animator`] instead and it renders that animator's playhead, asking the
8//! window for the next frame while it is still moving.
9//!
10//! The values land on a wrapper `div` around your child. Offsets are relative
11//! insets, so an animating element never pushes its neighbours around.
12
13use gpui::prelude::*;
14use gpui::{div, AnyElement, App, ElementId, Entity, IntoElement, Window};
15
16use super::{Animator, Clip, Motion, Motioned, Sequence};
17use crate::devtools::{Probed, ProbedAny};
18use crate::transition::TransitionKind;
19
20/// A child with a clip playing on it.
21#[derive(IntoElement)]
22pub struct Animated {
23  id: ElementId,
24  clip: Clip,
25  animator: Option<Entity<Animator>>,
26  child: Option<AnyElement>,
27}
28
29impl Animated {
30  pub fn new(id: impl Into<ElementId>) -> Self {
31    Animated {
32      id: id.into(),
33      clip: Clip::default(),
34      animator: None,
35      child: None,
36    }
37  }
38
39  /// Play this motion once when the element mounts.
40  pub fn motion(mut self, motion: Motion) -> Self {
41    self.clip = Clip::Motion(motion);
42    self
43  }
44
45  /// Play this sequence once when the element mounts.
46  pub fn sequence(mut self, sequence: Sequence) -> Self {
47    self.clip = Clip::Sequence(sequence);
48    self
49  }
50
51  pub fn clip(mut self, clip: impl Into<Clip>) -> Self {
52    self.clip = clip.into();
53    self
54  }
55
56  /// One of the stock entrances, at the default 200ms.
57  pub fn enter(self, kind: TransitionKind) -> Self {
58    self.motion(Motion::enter(kind))
59  }
60
61  /// Render an [`Animator`]'s playhead instead of a one-shot clip. The
62  /// animator wins: whatever motion was set is ignored.
63  pub fn animator(mut self, animator: &Entity<Animator>) -> Self {
64    self.animator = Some(animator.clone());
65    self
66  }
67
68  pub fn child(mut self, child: impl IntoElement) -> Self {
69    self.child = Some(child.into_any_element());
70    self
71  }
72}
73
74impl RenderOnce for Animated {
75  fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
76    let child = self.child.unwrap_or_else(|| div().into_any_element());
77
78    if let Some(animator) = self.animator {
79      let frame = animator.read(cx).frame(window);
80      let progress = frame.progress;
81      return frame
82        .apply(div())
83        .child(child)
84        .probe("Animated")
85        .attr_with("progress", || format!("{progress:.2}"))
86        .into_any_element();
87    }
88
89    div()
90      .child(child)
91      .animate(self.id, self.clip)
92      .probe_any("Animated")
93      .into_any_element()
94  }
95}