Add dynamic font scaling, hotkeys for quitting.
Huge thanks to `@AlexChaplinBraz` in the egui discord for help with the fonts!
This commit is contained in:
parent
b6b3be19ec
commit
ad7b0c9d4d
2 changed files with 52 additions and 30 deletions
80
src/timer.rs
80
src/timer.rs
|
@ -7,7 +7,11 @@ use egui_extras::{Size, StripBuilder};
|
||||||
|
|
||||||
use crate::{cli::Cli, util::*};
|
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum CountDirection {
|
pub enum CountDirection {
|
||||||
|
@ -20,15 +24,16 @@ pub struct Timer {
|
||||||
direction: CountDirection,
|
direction: CountDirection,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
state: TimerState,
|
state: TimerState,
|
||||||
tstart: Instant,
|
tstart: Instant, // so we can blink
|
||||||
alarm: Option<String>,
|
alarm: Option<String>,
|
||||||
|
height: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum TimerState {
|
enum TimerState {
|
||||||
Unstarted,
|
Unstarted,
|
||||||
Paused(ChronoState), // time remaining
|
Paused(ChronoState),
|
||||||
Running(ChronoState), // time remaining
|
Running(ChronoState),
|
||||||
Finished,
|
Finished,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,15 +58,10 @@ struct ChronoState {
|
||||||
}
|
}
|
||||||
|
|
||||||
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(MAX_REPAINT);
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
let size = ctx.used_size();
|
let vsize = self.height.unwrap_or(500.0);
|
||||||
let vsize = if size.x.is_normal() {
|
|
||||||
size.x.abs()
|
|
||||||
} else {
|
|
||||||
400.0
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
TimerState::Unstarted => self.unstarted(ui, vsize),
|
TimerState::Unstarted => self.unstarted(ui, vsize),
|
||||||
|
@ -75,6 +75,10 @@ impl App for Timer {
|
||||||
|
|
||||||
TimerState::Finished => self.finished(ui, vsize),
|
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,
|
state: TimerState::Unstarted,
|
||||||
tstart: Instant::now(),
|
tstart: Instant::now(),
|
||||||
alarm: cli.alarm,
|
alarm: cli.alarm,
|
||||||
|
height: None,
|
||||||
};
|
};
|
||||||
if cli.running {
|
if cli.running {
|
||||||
let cs = ChronoState {
|
let cs = ChronoState {
|
||||||
|
@ -125,12 +130,14 @@ impl Timer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unstarted(&mut self, ui: &mut Ui, size: f32) {
|
fn unstarted(&mut self, ui: &mut Ui, size: f32) {
|
||||||
|
let tsize = size * 0.5;
|
||||||
let start = RichText::new("START")
|
let start = RichText::new("START")
|
||||||
.font(FontId::monospace(size * 0.9))
|
.font(FontId::monospace(tsize))
|
||||||
|
.size(tsize)
|
||||||
.color(Color32::WHITE)
|
.color(Color32::WHITE)
|
||||||
.background_color(Color32::LIGHT_GREEN);
|
.background_color(Color32::LIGHT_GREEN);
|
||||||
|
|
||||||
StripBuilder::new(ui)
|
let height = StripBuilder::new(ui)
|
||||||
.size(Size::remainder())
|
.size(Size::remainder())
|
||||||
.cell_layout(Layout::centered_and_justified(egui::Direction::TopDown))
|
.cell_layout(Layout::centered_and_justified(egui::Direction::TopDown))
|
||||||
.horizontal(|mut strip| {
|
.horizontal(|mut strip| {
|
||||||
|
@ -143,13 +150,17 @@ impl Timer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
})
|
||||||
|
.rect
|
||||||
|
.height();
|
||||||
|
self.height = Some(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn running(&mut self, ui: &mut Ui, size: f32) {
|
fn running(&mut self, ui: &mut Ui, size: f32) {
|
||||||
let tsize = size * 0.3;
|
let tsize = size * TEXT_FACTOR;
|
||||||
let text = RichText::new("PAUSE")
|
let text = RichText::new("PAUSE")
|
||||||
.font(FontId::monospace(tsize))
|
.font(FontId::monospace(tsize))
|
||||||
|
.size(tsize)
|
||||||
.color(Color32::GOLD);
|
.color(Color32::GOLD);
|
||||||
|
|
||||||
let elapsed;
|
let elapsed;
|
||||||
|
@ -164,7 +175,7 @@ impl Timer {
|
||||||
|
|
||||||
let remaining = remaining.saturating_sub(elapsed);
|
let remaining = remaining.saturating_sub(elapsed);
|
||||||
|
|
||||||
StripBuilder::new(ui)
|
let height = StripBuilder::new(ui)
|
||||||
.size(Size::relative(0.3333))
|
.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))
|
||||||
|
@ -183,10 +194,14 @@ impl Timer {
|
||||||
};
|
};
|
||||||
// now the numbers
|
// now the numbers
|
||||||
let color = Color32::DARK_GRAY;
|
let color = Color32::DARK_GRAY;
|
||||||
let tsize = size * 0.7;
|
let tsize = size * DIGIT_FACTOR;
|
||||||
|
|
||||||
display_digits(&mut strip, remaining, color, tsize);
|
display_digits(&mut strip, remaining, color, tsize);
|
||||||
});
|
})
|
||||||
|
.rect
|
||||||
|
.height();
|
||||||
|
|
||||||
|
self.height = Some(height);
|
||||||
|
|
||||||
if remaining.is_zero() {
|
if remaining.is_zero() {
|
||||||
if let Some(alarm_file) = &self.alarm {
|
if let Some(alarm_file) = &self.alarm {
|
||||||
|
@ -215,7 +230,7 @@ impl Timer {
|
||||||
fn paused(&mut self, ui: &mut Ui, vsize: f32) {
|
fn paused(&mut self, ui: &mut Ui, vsize: f32) {
|
||||||
let elapsed;
|
let elapsed;
|
||||||
let mut is_running = false;
|
let mut is_running = false;
|
||||||
let tsize = vsize * 0.3;
|
let tsize = vsize * TEXT_FACTOR;
|
||||||
if let TimerState::Paused(cs) = self.state {
|
if let TimerState::Paused(cs) = self.state {
|
||||||
elapsed = cs.remaining;
|
elapsed = cs.remaining;
|
||||||
} else {
|
} else {
|
||||||
|
@ -223,7 +238,7 @@ impl Timer {
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaining = elapsed;
|
let remaining = elapsed;
|
||||||
StripBuilder::new(ui)
|
let height = StripBuilder::new(ui)
|
||||||
.size(Size::relative(0.33333))
|
.size(Size::relative(0.33333))
|
||||||
.size(Size::remainder())
|
.size(Size::remainder())
|
||||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||||
|
@ -236,7 +251,8 @@ impl Timer {
|
||||||
pstrip.cell(|ui| {
|
pstrip.cell(|ui| {
|
||||||
let resume = RichText::new("RESUME")
|
let resume = RichText::new("RESUME")
|
||||||
.color(Color32::GREEN)
|
.color(Color32::GREEN)
|
||||||
.font(FontId::monospace(tsize));
|
.font(FontId::monospace(tsize))
|
||||||
|
.size(tsize);
|
||||||
if ui.button(resume).clicked() {
|
if ui.button(resume).clicked() {
|
||||||
is_running = true;
|
is_running = true;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +260,8 @@ impl Timer {
|
||||||
pstrip.cell(|ui| {
|
pstrip.cell(|ui| {
|
||||||
let reset = RichText::new("RESET")
|
let reset = RichText::new("RESET")
|
||||||
.color(Color32::RED)
|
.color(Color32::RED)
|
||||||
.font(FontId::monospace(tsize));
|
.font(FontId::monospace(tsize))
|
||||||
|
.size(tsize);
|
||||||
if ui.button(reset).clicked() {
|
if ui.button(reset).clicked() {
|
||||||
self.state = TimerState::Unstarted;
|
self.state = TimerState::Unstarted;
|
||||||
}
|
}
|
||||||
|
@ -264,8 +281,11 @@ impl Timer {
|
||||||
CountDirection::Down => remaining,
|
CountDirection::Down => remaining,
|
||||||
CountDirection::Up => self.duration - 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 {
|
if is_running {
|
||||||
let cs = ChronoState {
|
let cs = ChronoState {
|
||||||
|
@ -292,9 +312,11 @@ impl Timer {
|
||||||
.cell_layout(Layout::centered_and_justified(Direction::TopDown))
|
.cell_layout(Layout::centered_and_justified(Direction::TopDown))
|
||||||
.horizontal(|mut pstrip| {
|
.horizontal(|mut pstrip| {
|
||||||
pstrip.cell(|ui| {
|
pstrip.cell(|ui| {
|
||||||
let reset = RichText::new("RESET")
|
let tsize = vsize * 0.3;
|
||||||
.color(Color32::GOLD)
|
let reset = RichText::new("RESTART")
|
||||||
.font(FontId::monospace(vsize * 0.3));
|
.color(Color32::DARK_GREEN)
|
||||||
|
.font(FontId::monospace(tsize))
|
||||||
|
.size(tsize);
|
||||||
if ui.button(reset).clicked() {
|
if ui.button(reset).clicked() {
|
||||||
self.state = TimerState::Unstarted;
|
self.state = TimerState::Unstarted;
|
||||||
}
|
}
|
||||||
|
@ -309,7 +331,7 @@ impl Timer {
|
||||||
Color32::DARK_GRAY
|
Color32::DARK_GRAY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
display_digits(&mut strip, remaining, color, vsize * 0.7);
|
display_digits(&mut strip, remaining, color, vsize * DIGIT_FACTOR);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
||||||
use egui::{Color32, Direction, FontId, Layout, RichText};
|
use egui::{Color32, Direction, FontId, Layout, RichText};
|
||||||
use egui_extras::{Size, Strip};
|
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))
|
RichText::new(format!("{:02}", digits))
|
||||||
.font(FontId::monospace(size))
|
.font(FontId::monospace(size))
|
||||||
.color(color)
|
.color(color)
|
||||||
|
|
Loading…
Reference in a new issue