use super::Widget;
use crate::{ColorPair, Result, Window};
pub struct Spinner {
frames: Vec<&'static str>,
current: usize,
x: u16,
y: u16,
colors: Option<ColorPair>,
label: Option<String>,
}
impl Spinner {
pub fn new() -> Self {
Self {
frames: vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
current: 0,
x: 0,
y: 0,
colors: None,
label: None,
}
}
pub fn with_frames(frames: &[&'static str]) -> Self {
Self {
frames: frames.to_vec(),
current: 0,
x: 0,
y: 0,
colors: None,
label: None,
}
}
pub fn at(mut self, x: u16, y: u16) -> Self {
self.x = x;
self.y = y;
self
}
pub fn with_color(mut self, colors: ColorPair) -> Self {
self.colors = Some(colors);
self
}
pub fn with_label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn advance(&mut self) {
self.current = (self.current + 1) % self.frames.len();
}
pub fn current_frame(&self) -> &str {
self.frames[self.current]
}
pub fn frame_count(&self) -> usize {
self.frames.len()
}
pub fn reset(&mut self) {
self.current = 0;
}
}
impl Widget for Spinner {
fn draw(&self, window: &mut dyn Window) -> Result<()> {
let frame = self.current_frame();
if let Some(ref label) = self.label {
let full_text = format!("{} {}", frame, label);
match self.colors {
Some(colors) => window.write_str_colored(self.y, self.x, &full_text, colors),
None => window.write_str(self.y, self.x, &full_text),
}
} else {
match self.colors {
Some(colors) => window.write_str_colored(self.y, self.x, frame, colors),
None => window.write_str(self.y, self.x, frame),
}
}
}
fn get_size(&self) -> (u16, u16) {
let frame_width = self.current_frame().chars().count() as u16;
let total_width = if let Some(ref label) = self.label {
frame_width + 1 + label.chars().count() as u16
} else {
frame_width
};
(total_width, 1)
}
fn get_position(&self) -> (u16, u16) {
(self.x, self.y)
}
}
impl Default for Spinner {
fn default() -> Self {
Self::new()
}
}