diff --git a/Predator.ttf b/resources/Predator.ttf similarity index 100% rename from Predator.ttf rename to resources/Predator.ttf diff --git a/airhorn_alarm.mp3 b/resources/airhorn_alarm.mp3 similarity index 100% rename from airhorn_alarm.mp3 rename to resources/airhorn_alarm.mp3 diff --git a/src/lib.rs b/src/lib.rs index e655a0e..e9990fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,13 @@ -pub const AIRHORN: &[u8] = include_bytes!("../airhorn_alarm.mp3"); -pub const PREDATOR_FONT: &[u8] = include_bytes!("../Predator.ttf"); +use std::time::Duration; + +pub const AIRHORN: &[u8] = include_bytes!("../resources/airhorn_alarm.mp3"); +pub const PREDATOR_FONT: &[u8] = include_bytes!("../resources/Predator.ttf"); + +pub(crate) const MIN_REPAINT: Duration = Duration::from_millis(100); +pub(crate) const MAX_REPAINT: Duration = Duration::from_millis(250); + +pub(crate) const DIGIT_FACTOR: f32 = 0.4; +pub(crate) const TEXT_FACTOR: f32 = 0.2; pub mod cli; pub mod timer; diff --git a/src/timer/eframe_app.rs b/src/timer/eframe_app.rs new file mode 100644 index 0000000..fc21789 --- /dev/null +++ b/src/timer/eframe_app.rs @@ -0,0 +1,28 @@ +use std::time::Instant; + +use super::{state::*, Timer}; +use crate::{MAX_REPAINT, MIN_REPAINT}; + +impl eframe::App for Timer { + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + ctx.request_repaint_after(MAX_REPAINT); + let height = ctx.input().screen_rect().height(); + egui::CentralPanel::default().show(ctx, |ui| { + match self.state { + TimerState::Unstarted => self.unstarted(ui, height), + TimerState::Running(cs) => { + let dur = Instant::now() - cs.updated; + let dur = MIN_REPAINT.saturating_sub(dur); + ctx.request_repaint_after(dur); + self.running(ui, height, cs); + } + TimerState::Paused(cs) => self.paused(ui, height, cs), + TimerState::Finished => self.finished(ui, height), + } + // check for quit key + if ui.input().key_pressed(egui::Key::Q) || ui.input().key_pressed(egui::Key::Escape) { + frame.close(); + } + }); + } +} diff --git a/src/timer.rs b/src/timer/mod.rs similarity index 82% rename from src/timer.rs rename to src/timer/mod.rs index e6e0817..edab29c 100644 --- a/src/timer.rs +++ b/src/timer/mod.rs @@ -1,17 +1,14 @@ use std::time::{Duration, Instant}; use clap::Parser; -use eframe::{App, CreationContext}; use egui::{Color32, Direction, FontId, Layout, RichText, Ui}; use egui_extras::{Size, StripBuilder}; -use crate::{cli::Cli, util::*, AIRHORN, PREDATOR_FONT}; +use crate::{cli::Cli, util::*, AIRHORN, DIGIT_FACTOR, PREDATOR_FONT, TEXT_FACTOR}; -const MIN_REPAINT: Duration = Duration::from_millis(100); -const MAX_REPAINT: Duration = Duration::from_millis(250); - -const DIGIT_FACTOR: f32 = 0.4; -const TEXT_FACTOR: f32 = 0.2; +mod state; +use state::{ChronoState, TimerState}; +mod eframe_app; #[derive(Debug, Clone, Copy)] pub enum CountDirection { @@ -28,60 +25,8 @@ pub struct Timer { alarm: Option>, } -#[derive(Debug, Clone, Copy)] -enum TimerState { - Unstarted, - Paused(ChronoState), - Running(ChronoState), - Finished, -} - -impl PartialEq for TimerState { - fn eq(&self, other: &Self) -> bool { - matches!( - (self, other), - (Self::Paused(_), Self::Paused(_)) - | (Self::Running(_), Self::Running(_)) - | (Self::Unstarted, Self::Unstarted) - | (Self::Finished, Self::Finished) - ) - } -} - -impl Eq for TimerState {} - -#[derive(Debug, Clone, Copy)] -struct ChronoState { - updated: Instant, - remaining: Duration, -} - -impl App for Timer { - fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { - ctx.request_repaint_after(MAX_REPAINT); - let height = ctx.input().screen_rect().height(); - egui::CentralPanel::default().show(ctx, |ui| { - match self.state { - TimerState::Unstarted => self.unstarted(ui, height), - TimerState::Running(cs) => { - let dur = Instant::now() - cs.updated; - let dur = MIN_REPAINT.saturating_sub(dur); - ctx.request_repaint_after(dur); - self.running(ui, height, cs); - } - TimerState::Paused(cs) => self.paused(ui, height, cs), - TimerState::Finished => self.finished(ui, height), - } - // check for quit key - if ui.input().key_pressed(egui::Key::Q) || ui.input().key_pressed(egui::Key::Escape) { - frame.close(); - } - }); - } -} - impl Timer { - pub fn new(ctx: &CreationContext) -> Self { + pub fn new(ctx: &eframe::CreationContext) -> Self { let cli = Cli::parse(); let predator = cli.predator; let seconds = cli.hours.unwrap_or(0) * 3600 diff --git a/src/timer/state.rs b/src/timer/state.rs new file mode 100644 index 0000000..e08bf5b --- /dev/null +++ b/src/timer/state.rs @@ -0,0 +1,29 @@ +use std::time::{Duration, Instant}; + +#[derive(Debug, Clone, Copy)] +pub(crate) enum TimerState { + Unstarted, + Paused(ChronoState), + Running(ChronoState), + Finished, +} + +impl PartialEq for TimerState { + fn eq(&self, other: &Self) -> bool { + matches!( + (self, other), + (Self::Paused(_), Self::Paused(_)) + | (Self::Running(_), Self::Running(_)) + | (Self::Unstarted, Self::Unstarted) + | (Self::Finished, Self::Finished) + ) + } +} + +impl Eq for TimerState {} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct ChronoState { + pub updated: Instant, + pub remaining: Duration, +}