Separate out event logic again
This commit is contained in:
parent
df59e45b80
commit
8d6446d886
45
src/main.rs
45
src/main.rs
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user