use ratatui_core::layout::Rect;
use ratatui_core::style::Style;
use crate::geometry::Size;
use crate::surface::Surface;
use crate::view::{RenderCtx, View};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum SpinnerStyle {
#[default]
Braille,
Line,
Dots,
}
impl SpinnerStyle {
pub fn frames(self) -> &'static [&'static str] {
match self {
SpinnerStyle::Braille => &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
SpinnerStyle::Line => &["|", "/", "-", "\\"],
SpinnerStyle::Dots => &["⠂", "⠒", "⠐", "⠰", "⠠", "⠤", "⠄", "⠆"],
}
}
}
pub struct Spinner {
style: SpinnerStyle,
frame: u64,
color: Option<ratatui_core::style::Color>,
}
impl Spinner {
pub fn new(frame: u64) -> Self {
Self {
style: SpinnerStyle::default(),
frame,
color: None,
}
}
pub fn style(mut self, style: SpinnerStyle) -> Self {
self.style = style;
self
}
pub fn color(mut self, color: ratatui_core::style::Color) -> Self {
self.color = Some(color);
self
}
pub fn glyph(&self) -> &'static str {
let frames = self.style.frames();
frames[(self.frame as usize) % frames.len()]
}
}
impl View for Spinner {
fn measure(&self, _available: Size) -> Size {
Size::new(1, 1)
}
fn render(&self, area: Rect, surface: &mut Surface, ctx: &RenderCtx) {
if area.width == 0 || area.height == 0 {
return;
}
let color = self.color.unwrap_or(ctx.theme.accent);
surface.set_string(area.x, area.y, self.glyph(), Style::default().fg(color));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Surface;
use crate::test_support::{buffer, rainbow_theme};
use crate::view::{RenderCtx, View};
#[test]
fn spinner_cycles_frames() {
let frames = SpinnerStyle::Braille.frames();
assert_eq!(Spinner::new(0).glyph(), frames[0]);
assert_eq!(Spinner::new(1).glyph(), frames[1]);
assert_eq!(Spinner::new(frames.len() as u64).glyph(), frames[0]);
}
#[test]
fn spinner_default_color_is_theme_accent() {
let t = rainbow_theme();
let ctx = RenderCtx::new(&t);
let mut buf = buffer(3, 1);
let area = buf.area;
let mut surface = Surface::new(&mut buf, area);
Spinner::new(0).render(area, &mut surface, &ctx);
assert_eq!(buf[(0, 0)].fg, t.accent);
}
}