use crate::utils::PrettyDuration;
use clock_core::stopwatch::{Stopwatch, StopwatchData};
use cursive::{
event::{Callback, Event, EventResult, Key, MouseEvent},
view::View,
Cursive, Printer, Vec2, With,
};
use std::rc::Rc;
#[derive(Default)]
pub struct StopwatchView {
stopwatch: Stopwatch,
on_stop: Option<Rc<dyn Fn(&mut Cursive, StopwatchData)>>,
show_laps: usize,
show_laps_offset: usize,
}
impl StopwatchView {
pub fn new() -> Self {
Self::default()
}
pub fn with_laps(mut self, n: usize) -> Self {
self.show_laps = n;
self
}
pub fn set_on_stop<F, R>(&mut self, cb: F)
where
F: 'static + Fn(&mut Cursive, StopwatchData) -> R,
{
self.on_stop = Some(Rc::new(move |s, t| {
cb(s, t);
}));
}
pub fn on_stop<F, R>(self, cb: F) -> Self
where
F: 'static + Fn(&mut Cursive, StopwatchData) -> R,
{
self.with(|s| s.set_on_stop(cb))
}
fn stop(&mut self) -> EventResult {
let data = self.stopwatch.stop();
if self.on_stop.is_some() {
let cb = self.on_stop.clone().unwrap();
EventResult::Consumed(Some(Callback::from_fn_once(move |s| cb(s, data))))
} else {
EventResult::Consumed(None)
}
}
fn increment_show_lap_offset(&mut self) {
if self.stopwatch.data.laps.len() > self.show_laps + self.show_laps_offset {
self.show_laps_offset += 1;
}
}
fn decrement_show_lap_offset(&mut self) {
if self.show_laps_offset > 0 {
self.show_laps_offset -= 1;
}
}
}
impl View for StopwatchView {
fn draw(&self, printer: &Printer) {
printer.print((4, 0), &self.stopwatch.read().pretty());
let len = self.stopwatch.data.laps.len() - self.show_laps_offset;
let mut i = 0;
while i < std::cmp::min(len, self.show_laps) {
i += 1;
printer.print(
(0, i),
&[
format!("Lap {:02}: ", len - i + 1),
self.stopwatch.data.laps[len - i].pretty(),
]
.concat(),
);
}
if len != i {
printer.print((0, self.show_laps), ": ");
}
}
fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
Vec2::new(20, self.show_laps + 1) }
fn on_event(&mut self, event: Event) -> EventResult {
match event {
Event::Char(' ') => {
self.stopwatch.pause_or_resume();
}
Event::Key(Key::Enter) => {
self.show_laps_offset = 0; return self.stop();
}
Event::Char('l') => {
self.stopwatch.lap();
self.show_laps_offset = 0;
}
Event::Key(Key::Up) => {
self.decrement_show_lap_offset();
}
Event::Key(Key::Down) => {
self.increment_show_lap_offset();
}
Event::Mouse { event, .. } => {
match event {
MouseEvent::WheelUp => {
self.decrement_show_lap_offset();
}
MouseEvent::WheelDown => {
self.increment_show_lap_offset();
}
_ => return EventResult::Ignored,
}
return EventResult::Consumed(None);
}
_ => return EventResult::Ignored,
}
EventResult::Consumed(None)
}
}