works
This commit is contained in:
parent
857a064a61
commit
b49625a973
2 changed files with 117 additions and 52 deletions
|
@ -1,13 +1,15 @@
|
||||||
|
use egui::Vec2;
|
||||||
use katabastird::timer::Timer;
|
use katabastird::timer::Timer;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
renderer: eframe::Renderer::Wgpu,
|
renderer: eframe::Renderer::Wgpu,
|
||||||
|
initial_window_size: Some(Vec2::new(1400.0, 800.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"eframe template",
|
"katabastird",
|
||||||
options,
|
options,
|
||||||
Box::new(|_cc| Box::new(Timer::default())),
|
Box::new(|_cc| Box::new(Timer::default())),
|
||||||
);
|
);
|
||||||
|
|
165
src/timer.rs
165
src/timer.rs
|
@ -20,8 +20,8 @@ pub struct Timer {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum State {
|
enum State {
|
||||||
Unstarted,
|
Unstarted,
|
||||||
Paused(Duration), // time remaining
|
Paused(ChronoState), // time remaining
|
||||||
Running(RunningState), // time remaining
|
Running(ChronoState), // time remaining
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for State {
|
impl PartialEq for State {
|
||||||
|
@ -38,7 +38,7 @@ impl PartialEq for State {
|
||||||
impl Eq for State {}
|
impl Eq for State {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct RunningState {
|
struct ChronoState {
|
||||||
started: Instant,
|
started: Instant,
|
||||||
remaining: Duration,
|
remaining: Duration,
|
||||||
}
|
}
|
||||||
|
@ -49,35 +49,51 @@ impl Default for Timer {
|
||||||
Self {
|
Self {
|
||||||
direction: CountDirection::Down,
|
direction: CountDirection::Down,
|
||||||
duration: dur,
|
duration: dur,
|
||||||
//state: State::Running(dur),
|
|
||||||
state: State::Unstarted,
|
state: State::Unstarted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App for Timer {
|
impl App for Timer {
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
ctx.request_repaint_after(Duration::from_secs(1));
|
ctx.request_repaint_after(Duration::from_secs(1));
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
let size = ctx.used_size();
|
let size = ctx.used_size();
|
||||||
let vsize = if size[1].is_normal() {
|
let vsize = if size[1].is_normal() {
|
||||||
size[1].abs()
|
size[1].abs()
|
||||||
} else {
|
} else {
|
||||||
200.0
|
600.0
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Running(_) => self.running(ui, vsize),
|
State::Unstarted => self.unstarted(ui, vsize),
|
||||||
State::Paused(_) => {}
|
_ => self.running(ui, vsize),
|
||||||
State::Unstarted => {
|
|
||||||
self.unstarted(ui, vsize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
|
pub fn new(duration: Duration, direction: CountDirection, paused: bool) -> Self {
|
||||||
|
if paused {
|
||||||
|
Timer {
|
||||||
|
duration,
|
||||||
|
direction,
|
||||||
|
state: State::Unstarted,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let cs = ChronoState {
|
||||||
|
remaining: duration,
|
||||||
|
started: Instant::now(),
|
||||||
|
};
|
||||||
|
Timer {
|
||||||
|
duration,
|
||||||
|
direction,
|
||||||
|
state: State::Running(cs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn unstarted(&mut self, ui: &mut Ui, size: f32) {
|
fn unstarted(&mut self, ui: &mut Ui, size: f32) {
|
||||||
let start = RichText::new("START")
|
let start = RichText::new("START")
|
||||||
.font(FontId::monospace(size * 0.9))
|
.font(FontId::monospace(size * 0.9))
|
||||||
|
@ -91,7 +107,7 @@ impl Timer {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
if ui.button(start).clicked() {
|
if ui.button(start).clicked() {
|
||||||
let dur = self.duration;
|
let dur = self.duration;
|
||||||
self.state = State::Running(RunningState {
|
self.state = State::Running(ChronoState {
|
||||||
started: Instant::now(),
|
started: Instant::now(),
|
||||||
remaining: dur,
|
remaining: dur,
|
||||||
});
|
});
|
||||||
|
@ -100,66 +116,113 @@ impl Timer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paused(&mut self, ui: &mut Ui, size: f32) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn running(&mut self, ui: &mut Ui, size: f32) {
|
fn running(&mut self, ui: &mut Ui, size: f32) {
|
||||||
let tsize = size * 0.2;
|
let tsize = size * 0.3;
|
||||||
let text = RichText::new("PAUSE")
|
let text = RichText::new("PAUSE")
|
||||||
.font(FontId::monospace(tsize))
|
.font(FontId::monospace(tsize))
|
||||||
.color(Color32::GOLD);
|
.color(Color32::GOLD);
|
||||||
|
|
||||||
let elapsed;
|
let elapsed;
|
||||||
let started;
|
let started;
|
||||||
|
let mut is_paused;
|
||||||
if let State::Running(rs) = self.state {
|
if let State::Running(rs) = self.state {
|
||||||
elapsed = Instant::now() - rs.started;
|
elapsed = Instant::now() - rs.started;
|
||||||
started = rs.started;
|
started = rs.started;
|
||||||
|
is_paused = false;
|
||||||
|
} else if let State::Paused(cs) = self.state {
|
||||||
|
elapsed = cs.remaining;
|
||||||
|
started = Instant::now() - (self.duration - elapsed);
|
||||||
|
is_paused = true;
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaining = self.duration.saturating_sub(elapsed);
|
let remaining = if is_paused {
|
||||||
|
elapsed
|
||||||
|
} else {
|
||||||
|
self.duration.saturating_sub(elapsed)
|
||||||
|
};
|
||||||
|
|
||||||
// StripBuilder::vertical();
|
|
||||||
StripBuilder::new(ui)
|
StripBuilder::new(ui)
|
||||||
|
.size(Size::relative(0.3333))
|
||||||
.size(Size::remainder())
|
.size(Size::remainder())
|
||||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||||
.horizontal(|mut strip| {
|
.vertical(|mut strip| {
|
||||||
strip.cell(|ui| {
|
if is_paused {
|
||||||
if ui.button(text).clicked() {
|
strip.strip(|pstrip| {
|
||||||
self.state = State::Paused(remaining);
|
pstrip
|
||||||
}
|
.sizes(Size::remainder(), 2)
|
||||||
|
.cell_layout(Layout::centered_and_justified(Direction::TopDown))
|
||||||
|
.horizontal(|mut pstrip| {
|
||||||
|
pstrip.cell(|ui| {
|
||||||
|
let resume = RichText::new("RESUME")
|
||||||
|
.color(Color32::GREEN)
|
||||||
|
.font(FontId::monospace(tsize));
|
||||||
|
if ui.button(resume).clicked() {
|
||||||
|
is_paused = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
pstrip.cell(|ui| {
|
||||||
|
let reset = RichText::new("RESET")
|
||||||
|
.color(Color32::RED)
|
||||||
|
.font(FontId::monospace(tsize));
|
||||||
|
if ui.button(reset).clicked() {
|
||||||
|
self.state = State::Unstarted;
|
||||||
|
is_paused = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// first the pause
|
||||||
|
strip.cell(|ui| {
|
||||||
|
if ui.button(text).clicked() {
|
||||||
|
is_paused = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let remaining = match self.direction {
|
||||||
|
CountDirection::Down => remaining,
|
||||||
|
_ => self.duration - remaining,
|
||||||
|
};
|
||||||
|
|
||||||
|
// now the numbers
|
||||||
|
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));
|
||||||
|
strip.strip(|strip| {
|
||||||
|
strip
|
||||||
|
.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);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if let State::Paused(_) = self.state {
|
let cs = ChronoState { remaining, started };
|
||||||
return;
|
if is_paused {
|
||||||
|
if self.state == State::Unstarted {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.state = State::Paused(cs);
|
||||||
|
} else {
|
||||||
|
self.state = State::Running(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue