use channels to send signals

This commit is contained in:
Joe Ardent 2022-10-22 17:25:52 -07:00
parent 4ccc2e4738
commit 58319dffff
3 changed files with 187 additions and 113 deletions

71
src/timer/gui.rs Normal file
View 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);
});
}

View file

@ -1,14 +1,17 @@
use std::sync::mpsc::channel;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use clap::Parser; use clap::Parser;
use egui::{Color32, Direction, FontId, Layout, RichText, Ui}; use egui::{Color32, FontId, Layout, RichText, Ui};
use egui_extras::{Size, StripBuilder}; use egui_extras::{Size, StripBuilder};
use crate::{cli::Cli, util::*, AIRHORN, DIGIT_FACTOR, PREDATOR_FONT, TEXT_FACTOR}; use crate::{cli::Cli, util::*, AIRHORN, DIGIT_FACTOR, PREDATOR_FONT, TEXT_FACTOR};
mod state; mod state;
use state::{ChronoState, TimerState}; use state::{ChronoState, NextTimerState, TimerState};
mod eframe_app; mod eframe_app;
mod gui;
use gui::*;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum CountDirection { pub enum CountDirection {
@ -111,34 +114,8 @@ impl Timer {
.font(FontId::monospace(tsize)) .font(FontId::monospace(tsize))
.color(Color32::GOLD); .color(Color32::GOLD);
let mut is_paused = false;
let elapsed = Instant::now() - cs.updated; let elapsed = Instant::now() - cs.updated;
let remaining = cs.remaining.saturating_sub(elapsed); 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 remaining.is_zero() {
if let Some(alarm_file) = &self.alarm { if let Some(alarm_file) = &self.alarm {
let alarm_file = alarm_file.to_owned(); let alarm_file = alarm_file.to_owned();
@ -148,15 +125,33 @@ impl Timer {
return; 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 { let cs = ChronoState {
remaining, remaining,
updated: Instant::now(), updated: Instant::now(),
}; };
if is_paused {
// did we click the reset button? if rx.recv().is_ok() {
if self.state == TimerState::Unstarted {
return;
}
self.state = TimerState::Paused(cs); self.state = TimerState::Paused(cs);
} else { } else {
self.state = TimerState::Running(cs); self.state = TimerState::Running(cs);
@ -164,60 +159,61 @@ impl Timer {
} }
fn paused(&mut self, ui: &mut Ui, vsize: f32, cs: ChronoState) { fn paused(&mut self, ui: &mut Ui, vsize: f32, cs: ChronoState) {
let mut is_running = false;
let tsize = vsize * TEXT_FACTOR; let tsize = vsize * TEXT_FACTOR;
let remaining = cs.remaining; let remaining = cs.remaining;
StripBuilder::new(ui) let resume = RichText::new("RESUME")
.size(Size::relative(0.33333)) .color(Color32::GREEN)
.size(Size::remainder()) .font(FontId::monospace(tsize));
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight)) let reset = RichText::new("RESET")
.vertical(|mut strip| { .color(Color32::RED)
strip.strip(|pstrip| { .font(FontId::monospace(tsize));
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);
});
if is_running { let (sender, rx) = channel();
let cs = ChronoState { {
remaining, let color = {
updated: Instant::now(), 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::Up => self.duration,
CountDirection::Down => Duration::from_nanos(0), CountDirection::Down => Duration::from_nanos(0),
}; };
StripBuilder::new(ui)
.size(Size::relative(0.33333)) let tsize = vsize * 0.3;
.size(Size::remainder()) let reset = RichText::new("RESTART")
.cell_layout(Layout::centered_and_justified(Direction::LeftToRight)) .color(Color32::DARK_GREEN)
.vertical(|mut strip| { .font(FontId::monospace(tsize));
strip.strip(|pstrip| { let color = {
pstrip let blink = (Instant::now() - self.tstart).as_secs() % 2 == 0;
.size(Size::remainder()) if blink {
.cell_layout(Layout::centered_and_justified(Direction::TopDown)) Color32::BLACK
.horizontal(|mut pstrip| { } else {
pstrip.cell(|ui| { Color32::DARK_GRAY
let tsize = vsize * 0.3; }
let reset = RichText::new("RESTART") };
.color(Color32::DARK_GREEN) let (sender, rx) = channel();
.font(FontId::monospace(tsize));
if ui.button(reset).clicked() { one_button(
self.state = TimerState::Unstarted; ui,
} reset,
}); NextTimerState::Unstarted,
}); sender,
}); remaining,
let color = { color,
let blink = (Instant::now() - self.tstart).as_secs() % 2 == 0; tsize,
if blink { );
Color32::BLACK if rx.recv().is_ok() {
} else { self.state = TimerState::Unstarted;
Color32::DARK_GRAY }
}
};
display_digits(&mut strip, remaining, color, vsize * DIGIT_FACTOR);
});
} }
} }

View file

@ -8,6 +8,16 @@ pub(crate) enum TimerState {
Finished, 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 { impl PartialEq for TimerState {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
matches!( matches!(
@ -21,6 +31,7 @@ impl PartialEq for TimerState {
} }
impl Eq for TimerState {} impl Eq for TimerState {}
impl Eq for NextTimerState {}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) struct ChronoState { pub(crate) struct ChronoState {