use channels to send signals
This commit is contained in:
parent
4ccc2e4738
commit
58319dffff
3 changed files with 187 additions and 113 deletions
71
src/timer/gui.rs
Normal file
71
src/timer/gui.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use crate::util::display_digits;
|
||||
|
||||
use super::state::NextTimerState;
|
||||
|
||||
use std::{sync::mpsc::Sender, time::Duration};
|
||||
|
||||
use egui::{Color32, Direction, Layout, RichText, Ui};
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
|
||||
pub(crate) fn two_button(
|
||||
ui: &mut Ui,
|
||||
button1: RichText,
|
||||
button2: RichText,
|
||||
signal1: NextTimerState,
|
||||
signal2: NextTimerState,
|
||||
sender: Sender<NextTimerState>,
|
||||
remaining: Duration,
|
||||
color: Color32,
|
||||
size: f32,
|
||||
) {
|
||||
let sender2 = sender.clone();
|
||||
StripBuilder::new(ui)
|
||||
.size(Size::relative(0.33333))
|
||||
.size(Size::remainder())
|
||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||
.vertical(|mut strip| {
|
||||
strip.strip(|pstrip| {
|
||||
pstrip
|
||||
.sizes(Size::remainder(), 2)
|
||||
.cell_layout(Layout::centered_and_justified(Direction::TopDown))
|
||||
.horizontal(|mut pstrip| {
|
||||
pstrip.cell(|ui| {
|
||||
if ui.button(button1).clicked() {
|
||||
sender.send(signal1).unwrap();
|
||||
}
|
||||
});
|
||||
pstrip.cell(|ui| {
|
||||
if ui.button(button2).clicked() {
|
||||
sender2.send(signal2).unwrap();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
display_digits(&mut strip, remaining, color, size);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn one_button(
|
||||
ui: &mut Ui,
|
||||
button1: RichText,
|
||||
signal1: NextTimerState,
|
||||
sender: Sender<NextTimerState>,
|
||||
remaining: Duration,
|
||||
color: Color32,
|
||||
size: f32,
|
||||
) {
|
||||
StripBuilder::new(ui)
|
||||
.size(Size::relative(0.33333))
|
||||
.size(Size::remainder())
|
||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||
.vertical(|mut strip| {
|
||||
strip.cell(|ui| {
|
||||
if ui.button(button1).clicked() {
|
||||
sender.send(signal1).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
display_digits(&mut strip, remaining, color, size);
|
||||
});
|
||||
}
|
218
src/timer/mod.rs
218
src/timer/mod.rs
|
@ -1,14 +1,17 @@
|
|||
use std::sync::mpsc::channel;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use clap::Parser;
|
||||
use egui::{Color32, Direction, FontId, Layout, RichText, Ui};
|
||||
use egui::{Color32, FontId, Layout, RichText, Ui};
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
|
||||
use crate::{cli::Cli, util::*, AIRHORN, DIGIT_FACTOR, PREDATOR_FONT, TEXT_FACTOR};
|
||||
|
||||
mod state;
|
||||
use state::{ChronoState, TimerState};
|
||||
use state::{ChronoState, NextTimerState, TimerState};
|
||||
mod eframe_app;
|
||||
mod gui;
|
||||
use gui::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CountDirection {
|
||||
|
@ -111,34 +114,8 @@ impl Timer {
|
|||
.font(FontId::monospace(tsize))
|
||||
.color(Color32::GOLD);
|
||||
|
||||
let mut is_paused = false;
|
||||
let elapsed = Instant::now() - cs.updated;
|
||||
let remaining = cs.remaining.saturating_sub(elapsed);
|
||||
|
||||
StripBuilder::new(ui)
|
||||
.size(Size::relative(0.3333))
|
||||
.size(Size::remainder())
|
||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||
.vertical(|mut strip| {
|
||||
// first the pause
|
||||
strip.cell(|ui| {
|
||||
if ui.button(text).clicked() {
|
||||
is_paused = true;
|
||||
}
|
||||
});
|
||||
|
||||
// if we're counting up, do the right thing
|
||||
let remaining = match self.direction {
|
||||
CountDirection::Down => remaining,
|
||||
CountDirection::Up => self.duration - remaining,
|
||||
};
|
||||
// now the numbers
|
||||
let color = Color32::DARK_GRAY;
|
||||
let tsize = size * DIGIT_FACTOR;
|
||||
|
||||
display_digits(&mut strip, remaining, color, tsize);
|
||||
});
|
||||
|
||||
if remaining.is_zero() {
|
||||
if let Some(alarm_file) = &self.alarm {
|
||||
let alarm_file = alarm_file.to_owned();
|
||||
|
@ -148,15 +125,33 @@ impl Timer {
|
|||
return;
|
||||
}
|
||||
|
||||
let (sender, rx) = channel();
|
||||
{
|
||||
// if we're counting up, do the right thing
|
||||
let remaining = match self.direction {
|
||||
CountDirection::Down => remaining,
|
||||
CountDirection::Up => self.duration - remaining,
|
||||
};
|
||||
// now the numbers
|
||||
let color = Color32::DARK_GRAY;
|
||||
let tsize = size * DIGIT_FACTOR;
|
||||
one_button(
|
||||
ui,
|
||||
text,
|
||||
state::NextTimerState::Paused,
|
||||
sender,
|
||||
remaining,
|
||||
color,
|
||||
tsize,
|
||||
)
|
||||
}
|
||||
|
||||
let cs = ChronoState {
|
||||
remaining,
|
||||
updated: Instant::now(),
|
||||
};
|
||||
if is_paused {
|
||||
// did we click the reset button?
|
||||
if self.state == TimerState::Unstarted {
|
||||
return;
|
||||
}
|
||||
|
||||
if rx.recv().is_ok() {
|
||||
self.state = TimerState::Paused(cs);
|
||||
} else {
|
||||
self.state = TimerState::Running(cs);
|
||||
|
@ -164,60 +159,61 @@ impl Timer {
|
|||
}
|
||||
|
||||
fn paused(&mut self, ui: &mut Ui, vsize: f32, cs: ChronoState) {
|
||||
let mut is_running = false;
|
||||
let tsize = vsize * TEXT_FACTOR;
|
||||
|
||||
let remaining = cs.remaining;
|
||||
StripBuilder::new(ui)
|
||||
.size(Size::relative(0.33333))
|
||||
.size(Size::remainder())
|
||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||
.vertical(|mut strip| {
|
||||
strip.strip(|pstrip| {
|
||||
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_running = true;
|
||||
}
|
||||
});
|
||||
pstrip.cell(|ui| {
|
||||
let reset = RichText::new("RESET")
|
||||
.color(Color32::RED)
|
||||
.font(FontId::monospace(tsize));
|
||||
if ui.button(reset).clicked() {
|
||||
self.state = TimerState::Unstarted;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
let color = {
|
||||
let blink = (Instant::now() - self.tstart).as_secs() % 2 == 0;
|
||||
if blink {
|
||||
Color32::BLACK
|
||||
} else {
|
||||
Color32::DARK_GRAY
|
||||
}
|
||||
};
|
||||
// if we're counting up, do the right thing
|
||||
let remaining = match self.direction {
|
||||
CountDirection::Down => remaining,
|
||||
CountDirection::Up => self.duration - remaining,
|
||||
};
|
||||
display_digits(&mut strip, remaining, color, vsize * DIGIT_FACTOR);
|
||||
});
|
||||
let resume = RichText::new("RESUME")
|
||||
.color(Color32::GREEN)
|
||||
.font(FontId::monospace(tsize));
|
||||
let reset = RichText::new("RESET")
|
||||
.color(Color32::RED)
|
||||
.font(FontId::monospace(tsize));
|
||||
|
||||
if is_running {
|
||||
let cs = ChronoState {
|
||||
remaining,
|
||||
updated: Instant::now(),
|
||||
let (sender, rx) = channel();
|
||||
{
|
||||
let color = {
|
||||
let blink = (Instant::now() - self.tstart).as_secs() % 2 == 0;
|
||||
if blink {
|
||||
Color32::BLACK
|
||||
} else {
|
||||
Color32::DARK_GRAY
|
||||
}
|
||||
};
|
||||
self.state = TimerState::Running(cs);
|
||||
// if we're counting up, do the right thing
|
||||
let remaining = match self.direction {
|
||||
CountDirection::Down => remaining,
|
||||
CountDirection::Up => self.duration - remaining,
|
||||
};
|
||||
|
||||
two_button(
|
||||
ui,
|
||||
resume,
|
||||
reset,
|
||||
NextTimerState::Running,
|
||||
NextTimerState::Unstarted,
|
||||
sender,
|
||||
remaining,
|
||||
color,
|
||||
vsize * DIGIT_FACTOR,
|
||||
);
|
||||
}
|
||||
|
||||
let cs = ChronoState {
|
||||
remaining,
|
||||
updated: Instant::now(),
|
||||
};
|
||||
if let Ok(s) = rx.recv() {
|
||||
match s {
|
||||
NextTimerState::Running => {
|
||||
self.state = TimerState::Running(cs);
|
||||
}
|
||||
NextTimerState::Unstarted => {
|
||||
self.state = TimerState::Unstarted;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
self.state = TimerState::Paused(cs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,36 +222,32 @@ impl Timer {
|
|||
CountDirection::Up => self.duration,
|
||||
CountDirection::Down => Duration::from_nanos(0),
|
||||
};
|
||||
StripBuilder::new(ui)
|
||||
.size(Size::relative(0.33333))
|
||||
.size(Size::remainder())
|
||||
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight))
|
||||
.vertical(|mut strip| {
|
||||
strip.strip(|pstrip| {
|
||||
pstrip
|
||||
.size(Size::remainder())
|
||||
.cell_layout(Layout::centered_and_justified(Direction::TopDown))
|
||||
.horizontal(|mut pstrip| {
|
||||
pstrip.cell(|ui| {
|
||||
let tsize = vsize * 0.3;
|
||||
let reset = RichText::new("RESTART")
|
||||
.color(Color32::DARK_GREEN)
|
||||
.font(FontId::monospace(tsize));
|
||||
if ui.button(reset).clicked() {
|
||||
self.state = TimerState::Unstarted;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
let color = {
|
||||
let blink = (Instant::now() - self.tstart).as_secs() % 2 == 0;
|
||||
if blink {
|
||||
Color32::BLACK
|
||||
} else {
|
||||
Color32::DARK_GRAY
|
||||
}
|
||||
};
|
||||
display_digits(&mut strip, remaining, color, vsize * DIGIT_FACTOR);
|
||||
});
|
||||
|
||||
let tsize = vsize * 0.3;
|
||||
let reset = RichText::new("RESTART")
|
||||
.color(Color32::DARK_GREEN)
|
||||
.font(FontId::monospace(tsize));
|
||||
let color = {
|
||||
let blink = (Instant::now() - self.tstart).as_secs() % 2 == 0;
|
||||
if blink {
|
||||
Color32::BLACK
|
||||
} else {
|
||||
Color32::DARK_GRAY
|
||||
}
|
||||
};
|
||||
let (sender, rx) = channel();
|
||||
|
||||
one_button(
|
||||
ui,
|
||||
reset,
|
||||
NextTimerState::Unstarted,
|
||||
sender,
|
||||
remaining,
|
||||
color,
|
||||
tsize,
|
||||
);
|
||||
if rx.recv().is_ok() {
|
||||
self.state = TimerState::Unstarted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,16 @@ pub(crate) enum TimerState {
|
|||
Finished,
|
||||
}
|
||||
|
||||
// this is a bit of a hack to deat with not being able to have const instances of the regular
|
||||
// timerstate.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) enum NextTimerState {
|
||||
Unstarted,
|
||||
Paused,
|
||||
Running,
|
||||
// no need for finished, there will never be a button to click on that says "finished"
|
||||
}
|
||||
|
||||
impl PartialEq for TimerState {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
matches!(
|
||||
|
@ -21,6 +31,7 @@ impl PartialEq for TimerState {
|
|||
}
|
||||
|
||||
impl Eq for TimerState {}
|
||||
impl Eq for NextTimerState {}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct ChronoState {
|
||||
|
|
Loading…
Reference in a new issue