2026-06-15 09:15:30 -05:00
|
|
|
//! The [`Animation`] trait and supporting types.
|
|
|
|
|
//!
|
|
|
|
|
//! An animation encapsulates a time-bounded visual effect: it advances via
|
|
|
|
|
//! [`update`](Animation::update), renders via [`draw`](Animation::draw), and
|
2026-06-15 11:44:18 -05:00
|
|
|
//! reports its layer, which [`InputMode`] is active while it runs
|
|
|
|
|
//! ([`input_mode_during`](Animation::input_mode_during)), and which mode to
|
|
|
|
|
//! enter when it finishes ([`input_mode_after`](Animation::input_mode_after)).
|
|
|
|
|
//! Most animations use the default `input_mode_during` ([`InputMode::Ignore`]),
|
|
|
|
|
//! but open animations may advertise an interactive mode so the overlay is
|
|
|
|
|
//! responsive before the animation completes.
|
2026-06-15 09:15:30 -05:00
|
|
|
|
|
|
|
|
use ratatui::buffer::Buffer;
|
|
|
|
|
use ratatui::layout::Rect;
|
|
|
|
|
use ratatui::widgets::Widget;
|
|
|
|
|
use crate::input::InputMode;
|
|
|
|
|
|
|
|
|
|
/// Which region of the terminal an animation occupies.
|
|
|
|
|
pub enum AnimationLayer {
|
|
|
|
|
/// Renders in the inner board area, replacing the board (e.g. the wipe transition).
|
|
|
|
|
Board,
|
|
|
|
|
/// Renders over the full terminal area on top of the board (e.g. scroll open/close).
|
|
|
|
|
Overlay,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A time-bounded visual effect managed by [`Ui`](crate::ui::Ui).
|
|
|
|
|
pub trait Animation {
|
|
|
|
|
/// Advance the animation by `dt` seconds. Returns `true` when the animation is done.
|
|
|
|
|
fn update(&mut self, dt: f32) -> bool;
|
|
|
|
|
/// Draw the current animation frame into `area` on `buf`.
|
|
|
|
|
fn draw(&self, area: Rect, buf: &mut Buffer);
|
|
|
|
|
/// Which region this animation draws to (board area vs. full overlay).
|
|
|
|
|
fn layer(&self) -> AnimationLayer;
|
2026-06-15 11:44:18 -05:00
|
|
|
/// Which [`InputMode`] is active while this animation is running.
|
|
|
|
|
/// Defaults to [`InputMode::Ignore`] (all input discarded).
|
|
|
|
|
fn input_mode_during(&self) -> InputMode { InputMode::Ignore }
|
2026-06-15 09:15:30 -05:00
|
|
|
/// Which [`InputMode`] to enter when the animation finishes.
|
|
|
|
|
fn input_mode_after(&self) -> InputMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Wraps a `&dyn Animation` as a ratatui [`Widget`] so it can be passed to
|
|
|
|
|
/// `frame.render_widget`. The animation's [`draw`](Animation::draw) is called
|
|
|
|
|
/// with the area provided by the layout.
|
|
|
|
|
pub struct AnimWidget<'a>(pub &'a dyn Animation);
|
|
|
|
|
|
|
|
|
|
impl Widget for AnimWidget<'_> {
|
|
|
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
|
|
|
self.0.draw(area, buf);
|
|
|
|
|
}
|
|
|
|
|
}
|