#[macro_use]
extern crate log;
extern crate chrono;
extern crate termit_ion as termion;
extern crate unicode_segmentation;
pub mod color;
pub mod command;
pub mod geometry;
pub mod graphics;
pub mod input;
pub mod mion;
pub mod screen;
pub mod widget;
use self::widget::*;
use crate::command::*;
use crate::geometry::*;
use crate::input::*;
use crate::screen::Screen;
use std::fmt;
use std::io;
use std::mem;
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
pub trait GUI {
fn react(&mut self) -> io::Result<()>;
}
pub trait GrinApp {
fn run(&mut self) -> io::Result<()>;
fn quit(&mut self);
}
pub struct Grin<GUI, Root> {
command: Sender<GrinCommand>,
input: Receiver<Result<GrinInput, io::Error>>,
quitting: bool,
gui: GUI,
size: Point,
root: Root,
inputs: Vec<GrinInput>,
}
impl<GUI, Root> Grin<GUI, Root> {
pub fn new(
gui: GUI,
command: Sender<GrinCommand>,
input: Receiver<Result<GrinInput, io::Error>>,
root: Root,
) -> Self {
Self {
command,
input,
gui,
root,
quitting: false,
size: Default::default(),
inputs: vec![],
}
}
}
impl<GUI, Root> Grin<GUI, Root>
where
Root: Widget,
{
fn receive_inputs(&mut self) -> io::Result<()> {
loop {
let input = self.input.try_recv();
match input {
Err(TryRecvError::Empty) => break,
Err(TryRecvError::Disconnected) => {
error!("ui disconnected");
self.quit_priv();
break;
}
Ok(input) => {
match input {
Ok(GrinInput::Resize(size)) => self.size = size,
Ok(GrinInput::Key(KeyEvent {
key: Key::Char(' '),
..
})) => {
info!("quit!");
self.quit_priv();
break;
}
_ => {}
}
self.log(format!("Input: {:?}", input));
if let Ok(input) = input {
self.inputs.push(input);
}
}
}
}
Ok(())
}
fn handle_inputs(&mut self) -> io::Result<()> {
let inputs = mem::replace(&mut self.inputs, vec![]);
let mut screen = Screen::new(self.size);
{
self.root.arrange(screen.get_area());
self.root.consume(inputs);
self.root.render(&mut screen)?;
}
for drawing in screen.into_iter() {
self.command.send(GrinCommand::Draw(drawing)).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Failed to send command, {}", e),
)
})?;
}
Ok(())
}
}
impl<UI, Root> GrinApp for Grin<UI, Root>
where
UI: GUI,
Root: Widget,
{
fn run(&mut self) -> io::Result<()> {
self.send(GrinCommand::ShowCursor(false));
while !self.quitting {
self.gui.react()?;
self.receive_inputs()?;
if !self.inputs.is_empty() {
self.handle_inputs()?;
}
}
Ok(())
}
fn quit(&mut self) {
self.quit_priv()
}
}
impl<UI, Root> Grin<UI, Root> {
fn quit_priv(&mut self) {
self.quitting = true;
self.send(GrinCommand::Quit);
}
fn send(&mut self, event: GrinCommand) {
let dbg = format!("{:?}", event);
self.command
.send(event)
.unwrap_or_else(|e| error!("unable to send grin event {:?}. {}", dbg, e))
}
fn log<T: fmt::Display>(&mut self, what: T) {
info!("{}", what)
}
}
impl<UI, Root> Drop for Grin<UI, Root> {
fn drop(&mut self) {
self.quit_priv()
}
}