extern crate failure; extern crate termion; extern crate tui; #[allow(dead_code)] mod util; use std::io; use termion::event::Key; use termion::input::MouseTerminal; use termion::raw::IntoRawMode; use termion::screen::AlternateScreen; use tui::backend::TermionBackend; use tui::layout::Rect; use tui::style::{Color, Modifier, Style}; use tui::widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Widget}; use tui::Terminal; use util::event::{Event, Events}; use util::SinSignal; struct App { size: Rect, signal1: SinSignal, data1: Vec<(f64, f64)>, signal2: SinSignal, data2: Vec<(f64, f64)>, window: [f64; 2], } impl App { fn new() -> App { let mut signal1 = SinSignal::new(0.2, 3.0, 18.0); let mut signal2 = SinSignal::new(0.1, 2.0, 10.0); let data1 = signal1.by_ref().take(200).collect::>(); let data2 = signal2.by_ref().take(200).collect::>(); App { size: Rect::default(), signal1, data1, signal2, data2, window: [0.0, 20.0], } } fn update(&mut self) { for _ in 0..5 { self.data1.remove(0); } self.data1.extend(self.signal1.by_ref().take(5)); for _ in 0..10 { self.data2.remove(0); } self.data2.extend(self.signal2.by_ref().take(10)); self.window[0] += 1.0; self.window[1] += 1.0; } } fn main() -> Result<(), failure::Error> { // Terminal initialization let stdout = io::stdout().into_raw_mode()?; let stdout = MouseTerminal::from(stdout); let stdout = AlternateScreen::from(stdout); let backend = TermionBackend::new(stdout); let mut terminal = Terminal::new(backend)?; terminal.hide_cursor()?; let events = Events::new(); // App let mut app = App::new(); loop { let size = terminal.size()?; if app.size != size { terminal.resize(size)?; app.size = size; } terminal.draw(|mut f| { Chart::default() .block( Block::default() .title("Chart") .title_style(Style::default().fg(Color::Cyan).modifier(Modifier::Bold)) .borders(Borders::ALL), ).x_axis( Axis::default() .title("X Axis") .style(Style::default().fg(Color::Gray)) .labels_style(Style::default().modifier(Modifier::Italic)) .bounds(app.window) .labels(&[ &format!("{}", app.window[0]), &format!("{}", (app.window[0] + app.window[1]) / 2.0), &format!("{}", app.window[1]), ]), ).y_axis( Axis::default() .title("Y Axis") .style(Style::default().fg(Color::Gray)) .labels_style(Style::default().modifier(Modifier::Italic)) .bounds([-20.0, 20.0]) .labels(&["-20", "0", "20"]), ).datasets(&[ Dataset::default() .name("data2") .marker(Marker::Dot) .style(Style::default().fg(Color::Cyan)) .data(&app.data1), Dataset::default() .name("data3") .marker(Marker::Braille) .style(Style::default().fg(Color::Yellow)) .data(&app.data2), ]).render(&mut f, app.size); })?; match events.next()? { Event::Input(input) => if input == Key::Char('q') { break; }, Event::Tick => { app.update(); } } } Ok(()) }