diff --git a/src/components/utilities.rs b/src/components/utilities.rs index 58685411..c448e83b 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -1175,72 +1175,6 @@ impl Component for StatusBar { } } -#[derive(Debug)] -pub struct Progress { - description: String, - total_work: usize, - finished: usize, - id: ComponentId, -} - -impl Progress { - pub fn new(s: String, total_work: usize) -> Self { - Progress { - description: s, - total_work, - finished: 0, - id: ComponentId::new_v4(), - } - } - - pub fn add_work(&mut self, n: usize) { - if self.finished >= self.total_work { - return; - } - self.finished += n; - } - - pub fn percentage(&self) -> usize { - if self.total_work > 0 { - 100 * self.finished / self.total_work - } else { - 0 - } - } - - pub fn description(&self) -> &str { - &self.description - } -} - -impl fmt::Display for Progress { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // TODO display info - write!(f, "progress bar") - } -} - -impl Component for Progress { - fn draw(&mut self, _grid: &mut CellBuffer, _area: Area, _context: &mut Context) { - unimplemented!() - } - fn process_event(&mut self, _event: &mut UIEvent, _context: &mut Context) -> bool { - false - } - fn set_dirty(&mut self, _value: bool) {} - - fn is_dirty(&self) -> bool { - false - } - - fn id(&self) -> ComponentId { - self.id - } - fn set_id(&mut self, id: ComponentId) { - self.id = id; - } -} - #[derive(Debug)] pub struct Tabbed { pinned: usize, diff --git a/src/components/utilities/widgets.rs b/src/components/utilities/widgets.rs index 9c158c7b..44e4c2cd 100644 --- a/src/components/utilities/widgets.rs +++ b/src/components/utilities/widgets.rs @@ -989,3 +989,102 @@ impl ScrollBar { } } } + +#[derive(Debug)] +pub struct ProgressSpinner { + timer: crate::timer::PosixTimer, + stage: usize, + kind: usize, + dirty: bool, + id: ComponentId, +} + +impl ProgressSpinner { + const KINDS: &'static [&'static [&'static str]] = &[ + &["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"], + &["⣀", "⣄", "⣤", "⣦", "⣶", "⣷", "⣿"], + &["⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"], + &["○", "◔", "◐", "◕", "⬤"], + &["□", "◱", "◧", "▣", "■"], + &["□", "◱", "▨", "▩", "■"], + &["□", "◱", "▥", "▦", "■"], + &["░", "▒", "▓", "█"], + &["░", "█"], + &["⬜", "⬛"], + &["▱", "▰"], + &["▭", "◼"], + &["▯", "▮"], + &["◯", "⬤"], + &["⚪", "⚫"], + ]; + + pub fn new(kind: usize) -> Self { + let timer = crate::timer::PosixTimer::new_with_signal( + std::time::Duration::from_millis(50), + std::time::Duration::from_millis(500), + nix::sys::signal::Signal::SIGALRM, + ) + .unwrap(); + ProgressSpinner { + timer, + stage: 0, + kind: kind % Self::KINDS.len(), + dirty: true, + id: ComponentId::new_v4(), + } + } +} + +impl fmt::Display for ProgressSpinner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "progress bar") + } +} + +impl Component for ProgressSpinner { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + if self.dirty { + let theme_attr = crate::conf::value(context, "theme_default"); + clear_area(grid, area, theme_attr); + let stage = self.stage; + self.stage = (self.stage + 1).wrapping_rem(Self::KINDS[self.kind].len()); + write_string_to_grid( + Self::KINDS[self.kind][stage], + grid, + theme_attr.fg, + theme_attr.bg, + theme_attr.attrs, + area, + None, + ); + context.dirty_areas.push_back(area); + self.dirty = false; + } + } + + fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool { + match event { + UIEvent::Timer(id) if *id == self.timer.si_value => { + self.dirty = true; + true + } + _ => false, + } + } + + fn set_dirty(&mut self, new_val: bool) { + self.dirty = new_val; + } + + fn is_dirty(&self) -> bool { + self.dirty + } + + fn id(&self) -> ComponentId { + self.id + } + + fn set_id(&mut self, id: ComponentId) { + self.id = id; + } +}