clock_cli/tui/
stopwatch.rs1use crate::utils::PrettyDuration;
19use clock_core::stopwatch::{Stopwatch, StopwatchData};
21use cursive::{
22 event::{Callback, Event, EventResult, Key, MouseEvent},
23 view::View,
24 Cursive, Printer, Vec2, With,
25};
26use std::rc::Rc;
27
28#[derive(Default)]
29pub struct StopwatchView {
30 stopwatch: Stopwatch,
31 on_stop: Option<Rc<dyn Fn(&mut Cursive, StopwatchData)>>,
32 show_laps: usize,
33 show_laps_offset: usize,
34}
35
36impl StopwatchView {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn with_laps(mut self, n: usize) -> Self {
42 self.show_laps = n;
43 self
44 }
45
46 pub fn set_on_stop<F, R>(&mut self, cb: F)
47 where
48 F: 'static + Fn(&mut Cursive, StopwatchData) -> R,
49 {
50 self.on_stop = Some(Rc::new(move |s, t| {
51 cb(s, t);
52 }));
53 }
54
55 pub fn on_stop<F, R>(self, cb: F) -> Self
56 where
57 F: 'static + Fn(&mut Cursive, StopwatchData) -> R,
58 {
59 self.with(|s| s.set_on_stop(cb))
60 }
61
62 fn stop(&mut self) -> EventResult {
63 let data = self.stopwatch.stop();
64 if self.on_stop.is_some() {
65 let cb = self.on_stop.clone().unwrap();
66 EventResult::Consumed(Some(Callback::from_fn_once(move |s| cb(s, data))))
67 } else {
68 EventResult::Consumed(None)
69 }
70 }
71
72 fn increment_show_lap_offset(&mut self) {
73 if self.stopwatch.data.laps.len() > self.show_laps + self.show_laps_offset {
74 self.show_laps_offset += 1;
75 }
76 }
77
78 fn decrement_show_lap_offset(&mut self) {
79 if self.show_laps_offset > 0 {
80 self.show_laps_offset -= 1;
81 }
82 }
83}
84impl View for StopwatchView {
85 fn draw(&self, printer: &Printer) {
86 printer.print((4, 0), &self.stopwatch.read().pretty());
87
88 let len = self.stopwatch.data.laps.len() - self.show_laps_offset;
89 let mut i = 0;
90 while i < std::cmp::min(len, self.show_laps) {
91 i += 1;
92
93 printer.print(
94 (0, i),
95 &[
96 format!("Lap {:02}: ", len - i + 1),
97 self.stopwatch.data.laps[len - i].pretty(),
98 ]
99 .concat(),
100 );
101 }
102 if len != i {
103 printer.print((0, self.show_laps), ": ");
104 }
105 }
106
107 fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
108 Vec2::new(20, self.show_laps + 1) }
111
112 fn on_event(&mut self, event: Event) -> EventResult {
113 match event {
114 Event::Char(' ') => {
116 self.stopwatch.pause_or_resume();
117 }
118 Event::Key(Key::Enter) => {
119 self.show_laps_offset = 0; return self.stop();
121 }
122 Event::Char('l') => {
123 self.stopwatch.lap();
124 self.show_laps_offset = 0;
125 }
126 Event::Key(Key::Up) => {
127 self.decrement_show_lap_offset();
128 }
129 Event::Key(Key::Down) => {
130 self.increment_show_lap_offset();
131 }
132 Event::Mouse { event, .. } => {
133 match event {
134 MouseEvent::WheelUp => {
135 self.decrement_show_lap_offset();
136 }
137 MouseEvent::WheelDown => {
138 self.increment_show_lap_offset();
139 }
140 _ => return EventResult::Ignored,
141 }
142 return EventResult::Consumed(None);
143 }
144 _ => return EventResult::Ignored,
145 }
146 EventResult::Consumed(None)
147 }
148}