diff options
Diffstat (limited to 'ticket/src/tui.rs')
-rw-r--r-- | ticket/src/tui.rs | 134 |
1 files changed, 52 insertions, 82 deletions
diff --git a/ticket/src/tui.rs b/ticket/src/tui.rs index 57c8aca..85f60aa 100644 --- a/ticket/src/tui.rs +++ b/ticket/src/tui.rs @@ -7,24 +7,30 @@ use crate::{ Ticket, }; use anyhow::Result; +use crossterm::{ + cursor::Hide, + event::{ + self, + DisableMouseCapture, + EnableMouseCapture, + Event as CEvent, + KeyCode, + }, + queue, + terminal::*, +}; use std::{ collections::BTreeMap, - io, + io::{ + self, + Write, + }, sync::mpsc, thread, time::Duration, }; -use termion::{ - event::Key, - input::{ - MouseTerminal, - TermRead, - }, - raw::IntoRawMode, - screen::AlternateScreen, -}; use tui::{ - backend::TermionBackend, + backend::CrosstermBackend, layout::{ Alignment, Constraint, @@ -110,88 +116,31 @@ impl TicketState { } } } -/// 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<Key>>, - input_handle: thread::JoinHandle<()>, - tick_handle: thread::JoinHandle<()>, -} - struct App<'a> { tabs: TabsState<'a>, tickets: TicketState, + should_quit: bool, } #[derive(Debug, Clone, Copy)] pub struct Config { - pub exit_key: Key, + pub exit_key: KeyCode, pub tick_rate: Duration, } impl Default for Config { fn default() -> Self { Self { - exit_key: Key::Char('q'), + exit_key: KeyCode::Char('q'), tick_rate: Duration::from_millis(250), } } } - -impl Events { - pub fn new() -> Self { - Self::with_config(Config::default()) - } - - pub fn with_config(config: Config) -> Self { - let (tx, rx) = mpsc::channel(); - let input_handle = { - let tx = tx.clone(); - thread::spawn(move || { - let stdin = io::stdin(); - for evt in stdin.keys() { - if let Ok(key) = evt { - if tx.send(Event::Input(key)).is_err() { - return; - } - if key == config.exit_key { - return; - } - } - } - }) - }; - let tick_handle = { - let tx = tx.clone(); - thread::spawn(move || { - let tx = tx.clone(); - loop { - tx.send(Event::Tick).unwrap(); - thread::sleep(config.tick_rate); - } - }) - }; - Self { - rx, - input_handle, - tick_handle, - } - } - - pub fn next(&self) -> Result<Event<Key>, mpsc::RecvError> { - self.rx.recv() - } -} pub fn run() -> Result<()> { // Terminal initialization - let stdout = io::stdout().into_raw_mode()?; - let stdout = MouseTerminal::from(stdout); - let stdout = AlternateScreen::from(stdout); - let backend = TermionBackend::new(stdout); + enable_raw_mode()?; + queue!(io::stdout(), EnterAlternateScreen, EnableMouseCapture, Hide)?; + let backend = CrosstermBackend::new(io::stdout()); let mut terminal = Terminal::new(backend)?; - terminal.hide_cursor()?; - - let events = Events::new(); // App let mut app = App { @@ -202,8 +151,24 @@ pub fn run() -> Result<()> { let _ = map.insert("Closed".into(), get_closed_tickets()?); TicketState::new(map) }, + should_quit: false, }; + terminal.clear()?; + let (tx, rx) = mpsc::channel(); + let _ = thread::spawn(move || { + loop { + // poll for tick rate duration, if no events, sent tick event. + if event::poll(Duration::from_millis(250)).unwrap() { + if let CEvent::Key(key) = event::read().unwrap() { + tx.send(Event::Input(key)).unwrap(); + } + } + + tx.send(Event::Tick).unwrap(); + } + }); + // Main loop loop { terminal.draw(|mut f| { @@ -251,32 +216,37 @@ pub fn run() -> Result<()> { } })?; - match events.next()? { - Event::Input(input) => match input { - Key::Char('q') => { - break; + match rx.recv()? { + Event::Input(event) => match event.code { + KeyCode::Char('q') => { + app.should_quit = true; } - Key::Right => { + KeyCode::Right => { if app.tabs.index == 0 { app.tickets.status = Status::Closed; app.tickets.index = 0; } app.tabs.next(); } - Key::Left => { + KeyCode::Left => { if app.tabs.index != 0 { app.tickets.status = Status::Open; app.tickets.index = 0; } app.tabs.previous(); } - Key::Up => app.tickets.previous(), - Key::Down => app.tickets.next(), + KeyCode::Up => app.tickets.previous(), + KeyCode::Down => app.tickets.next(), _ => {} }, Event::Tick => continue, } + if app.should_quit { + break; + } } + queue!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?; + disable_raw_mode()?; Ok(()) } |