diff --git a/src/timer.rs b/src/timer.rs index 882c0bb..520a743 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -7,7 +7,11 @@ use egui_extras::{Size, StripBuilder}; use crate::{cli::Cli, util::*}; -const MIN_REPAINT: Duration = Duration::from_millis(100); +const MIN_REPAINT: Duration = Duration::from_millis(183); // one frame before 200ms +const MAX_REPAINT: Duration = Duration::from_millis(500); + +const DIGIT_FACTOR: f32 = 0.4; +const TEXT_FACTOR: f32 = 0.2; #[derive(Debug, Clone, Copy)] pub enum CountDirection { @@ -20,15 +24,16 @@ pub struct Timer { direction: CountDirection, duration: Duration, state: TimerState, - tstart: Instant, + tstart: Instant, // so we can blink alarm: Option, + height: Option, } #[derive(Debug, Clone, Copy)] enum TimerState { Unstarted, - Paused(ChronoState), // time remaining - Running(ChronoState), // time remaining + Paused(ChronoState), + Running(ChronoState), Finished, } @@ -53,15 +58,10 @@ struct ChronoState { } impl App for Timer { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - ctx.request_repaint_after(Duration::from_secs(1)); + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + ctx.request_repaint_after(MAX_REPAINT); egui::CentralPanel::default().show(ctx, |ui| { - let size = ctx.used_size(); - let vsize = if size.x.is_normal() { - size.x.abs() - } else { - 400.0 - }; + let vsize = self.height.unwrap_or(500.0); match self.state { TimerState::Unstarted => self.unstarted(ui, vsize), @@ -75,6 +75,10 @@ impl App for Timer { TimerState::Finished => self.finished(ui, vsize), } + // check for quit key + if ui.input().key_pressed(egui::Key::Q) || ui.input().key_pressed(egui::Key::Escape) { + frame.close(); + } }); } } @@ -112,6 +116,7 @@ impl Timer { state: TimerState::Unstarted, tstart: Instant::now(), alarm: cli.alarm, + height: None, }; if cli.running { let cs = ChronoState { @@ -125,12 +130,14 @@ impl Timer { } fn unstarted(&mut self, ui: &mut Ui, size: f32) { + let tsize = size * 0.5; let start = RichText::new("START") - .font(FontId::monospace(size * 0.9)) + .font(FontId::monospace(tsize)) + .size(tsize) .color(Color32::WHITE) .background_color(Color32::LIGHT_GREEN); - StripBuilder::new(ui) + let height = StripBuilder::new(ui) .size(Size::remainder()) .cell_layout(Layout::centered_and_justified(egui::Direction::TopDown)) .horizontal(|mut strip| { @@ -143,13 +150,17 @@ impl Timer { }); } }); - }); + }) + .rect + .height(); + self.height = Some(height); } fn running(&mut self, ui: &mut Ui, size: f32) { - let tsize = size * 0.3; + let tsize = size * TEXT_FACTOR; let text = RichText::new("PAUSE") .font(FontId::monospace(tsize)) + .size(tsize) .color(Color32::GOLD); let elapsed; @@ -164,7 +175,7 @@ impl Timer { let remaining = remaining.saturating_sub(elapsed); - StripBuilder::new(ui) + let height = StripBuilder::new(ui) .size(Size::relative(0.3333)) .size(Size::remainder()) .cell_layout(Layout::centered_and_justified(Direction::LeftToRight)) @@ -183,10 +194,14 @@ impl Timer { }; // now the numbers let color = Color32::DARK_GRAY; - let tsize = size * 0.7; + let tsize = size * DIGIT_FACTOR; display_digits(&mut strip, remaining, color, tsize); - }); + }) + .rect + .height(); + + self.height = Some(height); if remaining.is_zero() { if let Some(alarm_file) = &self.alarm { @@ -215,7 +230,7 @@ impl Timer { fn paused(&mut self, ui: &mut Ui, vsize: f32) { let elapsed; let mut is_running = false; - let tsize = vsize * 0.3; + let tsize = vsize * TEXT_FACTOR; if let TimerState::Paused(cs) = self.state { elapsed = cs.remaining; } else { @@ -223,7 +238,7 @@ impl Timer { } let remaining = elapsed; - StripBuilder::new(ui) + let height = StripBuilder::new(ui) .size(Size::relative(0.33333)) .size(Size::remainder()) .cell_layout(Layout::centered_and_justified(Direction::LeftToRight)) @@ -236,7 +251,8 @@ impl Timer { pstrip.cell(|ui| { let resume = RichText::new("RESUME") .color(Color32::GREEN) - .font(FontId::monospace(tsize)); + .font(FontId::monospace(tsize)) + .size(tsize); if ui.button(resume).clicked() { is_running = true; } @@ -244,7 +260,8 @@ impl Timer { pstrip.cell(|ui| { let reset = RichText::new("RESET") .color(Color32::RED) - .font(FontId::monospace(tsize)); + .font(FontId::monospace(tsize)) + .size(tsize); if ui.button(reset).clicked() { self.state = TimerState::Unstarted; } @@ -264,8 +281,11 @@ impl Timer { CountDirection::Down => remaining, CountDirection::Up => self.duration - remaining, }; - display_digits(&mut strip, remaining, color, vsize * 0.7); - }); + display_digits(&mut strip, remaining, color, vsize * DIGIT_FACTOR); + }) + .rect + .height(); + self.height = Some(height); if is_running { let cs = ChronoState { @@ -292,9 +312,11 @@ impl Timer { .cell_layout(Layout::centered_and_justified(Direction::TopDown)) .horizontal(|mut pstrip| { pstrip.cell(|ui| { - let reset = RichText::new("RESET") - .color(Color32::GOLD) - .font(FontId::monospace(vsize * 0.3)); + let tsize = vsize * 0.3; + let reset = RichText::new("RESTART") + .color(Color32::DARK_GREEN) + .font(FontId::monospace(tsize)) + .size(tsize); if ui.button(reset).clicked() { self.state = TimerState::Unstarted; } @@ -309,7 +331,7 @@ impl Timer { Color32::DARK_GRAY } }; - display_digits(&mut strip, remaining, color, vsize * 0.7); + display_digits(&mut strip, remaining, color, vsize * DIGIT_FACTOR); }); } } diff --git a/src/util.rs b/src/util.rs index e5d0e22..9fdc330 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,7 +3,7 @@ use std::time::Duration; use egui::{Color32, Direction, FontId, Layout, RichText}; use egui_extras::{Size, Strip}; -pub fn format_digits(digits: u64, size: f32, color: Color32) -> RichText { +fn format_digits(digits: u64, size: f32, color: Color32) -> RichText { RichText::new(format!("{:02}", digits)) .font(FontId::monospace(size)) .color(color)