use std::thread;
use std::sync::mpsc::{self, Sender, Receiver};
use tui::Terminal;
use tui::backend::CrosstermBackend;
use crossterm::{KeyEvent, InputEvent, input, AlternateScreen};
use super::{Event, Window};
use crate::windows::EventResult;
pub struct WindowManager {
windows: Vec<Box<dyn Window>>,
terminal: Terminal<CrosstermBackend>,
tx: Sender<Event<KeyEvent>>,
rx: Receiver<Event<KeyEvent>>,
pub tick_rate: u64
}
impl WindowManager {
pub fn new() -> Result<WindowManager, std::io::Error> {
let (tx, rx) = mpsc::channel();
let screen = AlternateScreen::to_alternate(true)?;
let backend = CrosstermBackend::with_alternate_screen(screen)?;
let mut terminal = Terminal::new(backend)?;
terminal.hide_cursor()?;
Ok(WindowManager {
windows: vec!(),
terminal,
tx,
rx,
tick_rate: 500
})
}
pub fn get_tx(&self) -> &Sender<Event<KeyEvent>> {
&self.tx
}
pub fn push_window(&mut self, window: Box<dyn Window>) {
self.windows.push(window);
}
pub fn run(&mut self, initial_window: Box<dyn Window>) -> Result<(), std::io::Error> {
self.push_window(initial_window);
{
let tx = self.tx.clone();
thread::spawn(move || {
let input = input();
let reader = input.read_sync();
for event in reader {
match event {
InputEvent::Keyboard(key) => {
if let Err(_) = tx.send(Event::Input(key.clone())) {
return;
}
},
_ => {}
}
}
});
}
{
let tx = self.tx.clone();
let tick_rate = self.tick_rate;
thread::spawn(move || {
loop {
tx.send(Event::Tick).unwrap();
thread::sleep(std::time::Duration::from_millis(tick_rate));
}
});
}
while self.windows.is_empty() == false {
if let Some(window) = self.windows.last_mut() {
if window.should_close() {
self.windows.pop();
continue;
}
window.render(&mut self.terminal)?;
let result = match self.rx.recv() {
Ok(Event::Input(event)) => {
match event {
KeyEvent::Ctrl(c) => {
if c == 'c' {
return Ok(());
}
Some(window.handle_key_event(event))
},
_ => Some(window.handle_key_event(event))
}
},
Ok(Event::Tick) => Some(window.handle_tick(self.tick_rate)),
Ok(event) => Some(window.handle_event(event)),
_ => None
};
if let Some(event_result) = result {
self.apply_event_result(event_result);
}
};
}
Ok(())
}
fn apply_event_result(&mut self, event_result: EventResult) {
if event_result.remove {
self.windows.pop();
}
if let Some(child) = event_result.child {
self.windows.push(child);
}
}
}