katabastird/src/timer.rs
2022-10-13 15:14:21 -07:00

165 lines
4.7 KiB
Rust

use egui::{Color32, Direction, FontId, Layout, RichText, Ui};
use egui_extras::{Size, StripBuilder};
use std::time::{Duration, Instant};
use eframe::App;
#[derive(Debug, Clone, Copy)]
pub enum CountDirection {
Up,
Down,
}
#[derive(Debug, Clone, Copy)]
pub struct Timer {
direction: CountDirection,
duration: Duration,
state: State,
}
#[derive(Debug, Clone, Copy)]
enum State {
Unstarted,
Paused(Duration), // time remaining
Running(RunningState), // time remaining
}
impl PartialEq for State {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Paused(_), Self::Paused(_)) => true,
(Self::Running(_), Self::Running(_)) => true,
(Self::Unstarted, Self::Unstarted) => true,
_ => false,
}
}
}
impl Eq for State {}
#[derive(Debug, Clone, Copy)]
struct RunningState {
started: Instant,
remaining: Duration,
}
impl Default for Timer {
fn default() -> Self {
let dur = Duration::from_secs(30);
Self {
direction: CountDirection::Down,
duration: dur,
//state: State::Running(dur),
state: State::Unstarted,
}
}
}
impl App for Timer {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
ctx.request_repaint_after(Duration::from_secs(1));
egui::CentralPanel::default().show(ctx, |ui| {
let size = ctx.used_size();
let vsize = if size[1].is_normal() {
size[1].abs()
} else {
200.0
};
match self.state {
State::Running(_) => self.running(ui, vsize),
State::Paused(_) => {}
State::Unstarted => {
self.unstarted(ui, vsize);
}
}
});
}
}
impl Timer {
fn unstarted(&mut self, ui: &mut Ui, size: f32) {
let start = RichText::new("START")
.font(FontId::monospace(size * 0.9))
.color(Color32::WHITE)
.background_color(Color32::LIGHT_GREEN);
StripBuilder::new(ui)
.size(Size::remainder())
.cell_layout(Layout::centered_and_justified(egui::Direction::TopDown))
.horizontal(|mut strip| {
strip.cell(|ui| {
if ui.button(start).clicked() {
let dur = self.duration;
self.state = State::Running(RunningState {
started: Instant::now(),
remaining: dur,
});
}
});
});
}
fn paused(&mut self, ui: &mut Ui, size: f32) {
todo!()
}
fn running(&mut self, ui: &mut Ui, size: f32) {
let tsize = size * 0.2;
let text = RichText::new("PAUSE")
.font(FontId::monospace(tsize))
.color(Color32::GOLD);
let elapsed;
let started;
if let State::Running(rs) = self.state {
elapsed = Instant::now() - rs.started;
started = rs.started;
} else {
unreachable!()
}
let remaining = self.duration.saturating_sub(elapsed);
// StripBuilder::vertical();
StripBuilder::new(ui)
.size(Size::remainder())
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
.horizontal(|mut strip| {
strip.cell(|ui| {
if ui.button(text).clicked() {
self.state = State::Paused(remaining);
}
});
});
if let State::Paused(_) = self.state {
return;
}
self.state = State::Running(RunningState { started, remaining });
let hours = remaining.as_secs() / 3600;
let minutes = (remaining.as_secs() / 60) % 60;
let seconds = remaining.as_secs() % 60;
let tsize = size * 0.7;
let hours = RichText::new(format!("{:02}", hours)).font(FontId::monospace(tsize));
let minutes = RichText::new(format!("{:02}", minutes)).font(FontId::monospace(tsize));
let seconds = RichText::new(format!("{:02}", seconds)).font(FontId::monospace(tsize));
StripBuilder::new(ui)
.sizes(Size::relative(0.33), 3)
.cell_layout(Layout::centered_and_justified(Direction::TopDown))
.horizontal(|mut strip| {
strip.cell(|ui| {
ui.label(hours);
});
strip.cell(|ui| {
ui.label(minutes);
});
strip.cell(|ui| {
ui.label(seconds);
});
});
}
}