tuigui 0.23.0

An easy-to-use, highly extensible, and speedy TUI library.
Documentation
use crate::preludes::widget_creation::*;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum AnimationContainerSequence<A: crate::Animation> {
    Single(A),
    Many(Vec<A>),
}

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// Play widget animations
pub struct AnimationContainer<W: Widget, A: crate::Animation> {
    pub widget: W,
    pub sequence: AnimationContainerSequence<A>,
    index: usize,
    prev_transform: Option<Transform>,
    new_start_transform: Option<Transform>,
    is_playing: bool,
    paused_time: Option<std::time::Instant>,
    paused_duration: std::time::Duration,
    is_done: bool,
    widget_data: WidgetData,
}

impl<W: Widget, A: crate::Animation> AnimationContainer<W, A> {
    /// Create new animation container
    pub fn new(sequence: AnimationContainerSequence<A>, autoplay: bool, widget: W) -> Self {
        Self {
            widget,
            sequence,
            index: 0,
            prev_transform: None,
            new_start_transform: None,
            is_playing: autoplay,
            paused_time: None,
            paused_duration: std::time::Duration::ZERO,
            is_done: false,
            widget_data: WidgetData::new(),
        }
    }

    /// Play/resume animation(s)
    pub fn play(&mut self) {
        if self.is_playing == false {
            self.is_playing = true;

            if let Some(paused_time) = self.paused_time {
                let duration = std::time::Instant::now() - paused_time;

                self.paused_duration += duration;
            }

            else {
                self.soft_reset();
            }
        }
    }

    /// Pause animation(s)
    pub fn pause(&mut self) {
        if self.is_playing {
            self.is_playing = false;
            self.paused_time = Some(std::time::Instant::now());
        }
    }

    /// Returns 'true' if the animations are playing (not paused)
    pub fn is_playing(&self) -> bool {
        return self.is_playing;
    }

    /// Returns 'true' if all the animations have finished
    pub fn has_finished(&self) -> bool {
        return self.is_done;
    }

    /// Reset the animations
    pub fn reset(&mut self, autoplay: bool) {
        self.index = 0;
        self.is_done = false;
        self.is_playing = autoplay;
        self.soft_reset();
    }

    fn soft_reset(&mut self) {
        self.paused_time = None;
        self.paused_duration = std::time::Duration::ZERO;
        self.widget.widget_data().animation_data.reset();
    }
}

impl<W: Widget, A: crate::Animation> Widget for AnimationContainer<W, A> {
    fn draw(&mut self, canvas: &mut Canvas, state_frame: Option<&EventStateFrame>) {
        let is_playing = self.is_playing();
        let is_done = self.has_finished();

        let child_data = self.widget.widget_data();

        // The transform to use if the animation is unable to animate.
        // (Either paused or done.)
        let static_rest = self.prev_transform.unwrap_or(canvas.original_transform());

        if is_playing && is_done == false {
            let offset: f64 = -self.paused_duration.as_secs_f64();

            let (animation, is_single) = match self.sequence {
                AnimationContainerSequence::Single(ref mut single) => (Some(single), true),
                AnimationContainerSequence::Many(ref mut many) => (many.get_mut(self.index), false),
            };

            if let Some(animation) = animation {
                canvas.animate_with_offset(
                    animation,
                    &child_data.animation_data,
                    self.new_start_transform,
                    offset
                );

                self.prev_transform = Some(canvas.transform);

                if animation.is_done(
                    child_data.animation_data.duration()
                        .as_secs_f64() + offset,
                ) {
                    if is_single {
                        self.is_done = true;
                    } else {
                        self.index += 1;
                        self.new_start_transform = Some(canvas.transform);
                        self.soft_reset();
                    }
                }
            }

            else {
                self.is_done = true;
                canvas.transform = static_rest;
            }
        }

        else {
            canvas.transform = static_rest;
        }

        self.widget.draw(canvas, state_frame);
    }

    fn widget_info(&self) -> WidgetInfo {
        return self.widget.widget_info();
    }

    fn widget_data(&mut self) -> &mut WidgetData {
        return &mut self.widget_data;
    }
}