Separate out event logic again

This commit is contained in:
Austen Adler 2021-05-14 19:25:01 -04:00
parent df59e45b80
commit 8d6446d886
2 changed files with 67 additions and 125 deletions

View File

@ -2,8 +2,9 @@
#![allow(dead_code)]
mod calc;
mod util;
mod format;
mod util;
use util::event::{Event, Events};
use calc::constants::{CalculatorDisplayMode, CalculatorState, RegisterState};
use calc::errors::CalculatorResult;
@ -19,9 +20,7 @@ use std::convert::TryFrom;
use std::io::Write;
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};
use std::{error::Error, io};
// use termion::{event::Key, raw::IntoRawMode, screen::AlternateScreen};
use tui::{
backend::CrosstermBackend,
layout::{Constraint, Direction, Layout},
@ -31,9 +30,6 @@ use tui::{
widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
Terminal,
};
use util::event::Event;
const TICK_RATE: Duration = Duration::from_millis(250);
struct Dimensions {
width: u16,
@ -78,29 +74,9 @@ fn main() -> Result<(), Box<dyn Error>> {
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let (tx, rx) = mpsc::channel();
let events = Events::new(250);
let mut app = App::default();
thread::spawn(move || {
let mut last_tick = Instant::now();
loop {
// poll for tick rate duration, if no events, sent tick event.
let timeout = TICK_RATE
.checked_sub(last_tick.elapsed())
.unwrap_or_else(|| Duration::from_secs(0));
if event::poll(timeout).unwrap() {
if let CEvent::Key(key) = event::read().unwrap() {
tx.send(Event::Input(key)).unwrap();
}
}
if last_tick.elapsed() >= TICK_RATE {
tx.send(Event::Tick).unwrap();
last_tick = Instant::now();
}
}
});
'outer: loop {
terminal.draw(|f| {
let chunks = Layout::default()
@ -304,7 +280,7 @@ fn main() -> Result<(), Box<dyn Error>> {
}
})?;
if let Event::Input(key) = rx.recv()? {
if let Event::Input(key) = events.next()? {
app.error_msg = match handle_key(&mut app, key) {
// Exit the program
Ok(CalculatorResponse::Quit) => break 'outer,
@ -314,7 +290,7 @@ fn main() -> Result<(), Box<dyn Error>> {
}
// Slurp events without a redraw
for e in rx.try_iter() {
for e in events.try_iter() {
match e {
Event::Input(key) => {
app.error_msg = match handle_key(&mut app, key) {
@ -366,7 +342,7 @@ fn handle_key(app: &mut App, key: KeyEvent) -> CalculatorResult<CalculatorRespon
app.state = AppState::Help;
}
KeyEvent {
code: KeyCode::Char('\n'),
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
}
| KeyEvent {
@ -399,6 +375,14 @@ fn handle_key(app: &mut App, key: KeyEvent) -> CalculatorResult<CalculatorRespon
} => {
app.calculator.take_input(c)?;
}
KeyEvent {
code: KeyCode::Char(c),
modifiers: KeyModifiers::SHIFT,
} => {
for c in (c.to_uppercase()) {
app.calculator.take_input(c)?;
}
}
_ => {}
},
(AppState::Help, _) => match key {
@ -486,4 +470,3 @@ fn draw_clippy_rect<T: std::io::Write>(c: ClippyRectangle, f: &mut Frame<Crosste
.block(Block::default().borders(Borders::ALL).title(c.title));
f.render_widget(help_message, area);
}

View File

@ -1,105 +1,64 @@
// use std::io;
// use std::sync::mpsc;
// use std::sync::mpsc::TryIter;
// use std::sync::{
// atomic::{AtomicBool, Ordering},
// Arc,
// };
// use std::thread;
// use std::time::Duration;
use std::io;
use std::sync::mpsc;
use std::sync::mpsc::TryIter;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::thread;
use std::time::{Duration, Instant};
// use crossterm::event::{KeyEvent, KeyCode, KeyModifiers};
use crossterm::event::{self, Event as CEvent, KeyCode, KeyEvent, KeyModifiers};
pub enum Event<I> {
Input(I),
Tick,
}
// /// A small event handler that wrap termion input and tick events. Each event
// /// type is handled in its own thread and returned to a common `Receiver`
// #[allow(dead_code)]
// pub struct Events {
// rx: mpsc::Receiver<Event<KeyEvent>>,
// tx: mpsc::Sender<Event<KeyEvent>>,
// input_handle: thread::JoinHandle<()>,
// ignore_exit_key: Arc<AtomicBool>,
// tick_handle: thread::JoinHandle<()>,
// }
pub struct Events {
rx: mpsc::Receiver<Event<KeyEvent>>,
tx: mpsc::Sender<Event<KeyEvent>>,
tick_handle: thread::JoinHandle<()>,
}
// #[derive(Debug, Clone, Copy)]
// pub struct Config {
// pub exit_key: KeyEvent,
// pub tick_rate: Duration,
// }
impl Events {
pub fn new(tick_rate: u64) -> Events {
let (tx, rx) = mpsc::channel();
let tick_handle = {
let tx = tx.clone();
thread::spawn(move || {
let mut last_tick = Instant::now();
let tick_rate = Duration::from_millis(tick_rate);
loop {
// poll for tick rate duration, if no events, sent tick event.
let timeout = tick_rate
.checked_sub(last_tick.elapsed())
.unwrap_or_else(|| Duration::from_secs(0));
if event::poll(timeout).unwrap() {
if let CEvent::Key(key) = event::read().unwrap() {
tx.send(Event::Input(key)).unwrap();
}
}
// impl Default for Config {
// fn default() -> Self {
// Config {
// exit_key: KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE),
// tick_rate: Duration::from_millis(250),
// }
// }
// }
if last_tick.elapsed() >= tick_rate {
tx.send(Event::Tick).unwrap();
last_tick = Instant::now();
}
}
})
};
Events {
tx: tx,
rx: rx,
tick_handle,
}
}
// impl Events {
// pub fn new() -> Events {
// Events::with_config(Config::default())
// }
pub fn next(&self) -> Result<Event<KeyEvent>, mpsc::RecvError> {
self.rx.recv()
}
// pub fn with_config(config: Config) -> Events {
// let (tx, rx) = mpsc::channel();
// let mac_tx = tx.clone();
// let ignore_exit_key = Arc::new(AtomicBool::new(true));
// let input_handle = {
// let tx = tx.clone();
// let ignore_exit_key = ignore_exit_key.clone();
// thread::spawn(move || {
// let stdin = io::stdin();
// for evt in stdin.keys() {
// if let Ok(key) = evt {
// if let Err(err) = tx.send(Event::Input(key)) {
// eprintln!("{}", err);
// return;
// }
// if !ignore_exit_key.load(Ordering::Relaxed) && key == config.exit_key {
// return;
// }
// }
// }
// })
// };
// let tick_handle = {
// thread::spawn(move || loop {
// if tx.send(Event::Tick).is_err() {
// break;
// }
// thread::sleep(config.tick_rate);
// })
// };
// Events {
// rx,
// tx: mac_tx,
// ignore_exit_key,
// input_handle,
// tick_handle,
// }
// }
// pub fn next(&self) -> Result<Event<KeyEvent>, mpsc::RecvError> {
// self.rx.recv()
// }
// pub fn try_iter(&self) -> TryIter<Event<KeyEvent>> {
// self.rx.try_iter()
// }
// #[allow(dead_code)]
// pub fn disable_exit_key(&mut self) {
// self.ignore_exit_key.store(true, Ordering::Relaxed);
// }
// #[allow(dead_code)]
// pub fn enable_exit_key(&mut self) {
// self.ignore_exit_key.store(false, Ordering::Relaxed);
// }
// }
pub fn try_iter(&self) -> TryIter<Event<KeyEvent>> {
self.rx.try_iter()
}
}