animated_label.rs

  1use gpui::{Animation, AnimationExt, FontWeight, pulsating_between};
  2use std::time::Duration;
  3use ui::prelude::*;
  4
  5#[derive(IntoElement)]
  6pub struct AnimatedLabel {
  7    base: Label,
  8    text: SharedString,
  9}
 10
 11impl AnimatedLabel {
 12    pub fn new(text: impl Into<SharedString>) -> Self {
 13        let text = text.into();
 14        AnimatedLabel {
 15            base: Label::new(text.clone()),
 16            text,
 17        }
 18    }
 19}
 20
 21impl LabelCommon for AnimatedLabel {
 22    fn size(mut self, size: LabelSize) -> Self {
 23        self.base = self.base.size(size);
 24        self
 25    }
 26
 27    fn weight(mut self, weight: FontWeight) -> Self {
 28        self.base = self.base.weight(weight);
 29        self
 30    }
 31
 32    fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
 33        self.base = self.base.line_height_style(line_height_style);
 34        self
 35    }
 36
 37    fn color(mut self, color: Color) -> Self {
 38        self.base = self.base.color(color);
 39        self
 40    }
 41
 42    fn strikethrough(mut self) -> Self {
 43        self.base = self.base.strikethrough();
 44        self
 45    }
 46
 47    fn italic(mut self) -> Self {
 48        self.base = self.base.italic();
 49        self
 50    }
 51
 52    fn alpha(mut self, alpha: f32) -> Self {
 53        self.base = self.base.alpha(alpha);
 54        self
 55    }
 56
 57    fn underline(mut self) -> Self {
 58        self.base = self.base.underline();
 59        self
 60    }
 61
 62    fn truncate(mut self) -> Self {
 63        self.base = self.base.truncate();
 64        self
 65    }
 66
 67    fn single_line(mut self) -> Self {
 68        self.base = self.base.single_line();
 69        self
 70    }
 71
 72    fn buffer_font(mut self, cx: &App) -> Self {
 73        self.base = self.base.buffer_font(cx);
 74        self
 75    }
 76}
 77
 78impl RenderOnce for AnimatedLabel {
 79    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
 80        let text = self.text.clone();
 81
 82        self.base
 83            .color(Color::Muted)
 84            .with_animations(
 85                "animated-label",
 86                vec![
 87                    Animation::new(Duration::from_secs(1)),
 88                    Animation::new(Duration::from_secs(1)).repeat(),
 89                ],
 90                move |mut label, animation_ix, delta| {
 91                    match animation_ix {
 92                        0 => {
 93                            let chars_to_show = (delta * text.len() as f32).ceil() as usize;
 94                            let text = SharedString::from(text[0..chars_to_show].to_string());
 95                            label.set_text(text);
 96                        }
 97                        1 => match delta {
 98                            d if d < 0.25 => label.set_text(text.clone()),
 99                            d if d < 0.5 => label.set_text(format!("{}.", text)),
100                            d if d < 0.75 => label.set_text(format!("{}..", text)),
101                            _ => label.set_text(format!("{}...", text)),
102                        },
103                        _ => {}
104                    }
105                    label
106                },
107            )
108            .with_animation(
109                "pulsating-label",
110                Animation::new(Duration::from_secs(2))
111                    .repeat()
112                    .with_easing(pulsating_between(0.6, 1.)),
113                |label, delta| label.map_element(|label| label.alpha(delta)),
114            )
115    }
116}