Merge pull request #4 from wose/bug/example-crash

fixes panic when terminal was resized
This commit is contained in:
Florian Dehau 2017-05-17 07:42:57 +02:00 committed by GitHub
commit bd0dcdcc87
10 changed files with 132 additions and 55 deletions

View file

@ -12,16 +12,18 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, BarChart}; use tui::widgets::{Widget, Block, border, BarChart};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier}; use tui::style::{Style, Color, Modifier};
struct App<'a> { struct App<'a> {
size: Rect,
data: Vec<(&'a str, u64)>, data: Vec<(&'a str, u64)>,
} }
impl<'a> App<'a> { impl<'a> App<'a> {
fn new() -> App<'a> { fn new() -> App<'a> {
App { App {
size: Rect::default(),
data: vec![("B1", 9), data: vec![("B1", 9),
("B2", 12), ("B2", 12),
("B3", 5), ("B3", 5),
@ -96,9 +98,16 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &app); draw(&mut terminal, &app);
loop { loop {
let size = terminal.size().unwrap();
if app.size != size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = rx.recv().unwrap(); let evt = rx.recv().unwrap();
match evt { match evt {
Event::Input(input) => { Event::Input(input) => {
@ -118,13 +127,11 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &App) { fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
let size = t.size().unwrap();
Group::default() Group::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(2) .margin(2)
.sizes(&[Size::Percent(50), Size::Percent(50)]) .sizes(&[Size::Percent(50), Size::Percent(50)])
.render(t, &size, |t, chunks| { .render(t, &app.size, |t, chunks| {
BarChart::default() BarChart::default()
.block(Block::default().title("Data1").borders(border::ALL)) .block(Block::default().title("Data1").borders(border::ALL))
.data(&app.data) .data(&app.data)

View file

@ -8,7 +8,7 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border}; use tui::widgets::{Widget, Block, border};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier}; use tui::style::{Style, Color, Modifier};
fn main() { fn main() {
@ -16,9 +16,16 @@ fn main() {
let stdin = io::stdin(); let stdin = io::stdin();
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
draw(&mut terminal);
let mut term_size = terminal.size().unwrap();
draw(&mut terminal, &term_size);
for c in stdin.keys() { for c in stdin.keys() {
draw(&mut terminal); let size = terminal.size().unwrap();
if term_size != size {
terminal.resize(size).unwrap();
term_size = size;
}
draw(&mut terminal, &term_size);
let evt = c.unwrap(); let evt = c.unwrap();
if evt == event::Key::Char('q') { if evt == event::Key::Char('q') {
break; break;
@ -27,9 +34,7 @@ fn main() {
terminal.show_cursor().unwrap(); terminal.show_cursor().unwrap();
} }
fn draw(t: &mut Terminal<TermionBackend>) { fn draw(t: &mut Terminal<TermionBackend>, size: &Rect) {
let size = t.size().unwrap();
// Wrapping block for a group // Wrapping block for a group
// Just draw the block and the group on the same area and build the group // Just draw the block and the group on the same area and build the group

View file

@ -24,6 +24,8 @@ struct App {
playground: Rect, playground: Rect,
vx: u16, vx: u16,
vy: u16, vy: u16,
dir_x: bool,
dir_y: bool,
} }
@ -33,23 +35,36 @@ impl App {
size: Default::default(), size: Default::default(),
x: 0.0, x: 0.0,
y: 0.0, y: 0.0,
ball: Rect::new(20, 20, 10, 10), ball: Rect::new(10, 30, 10, 10),
playground: Rect::new(10, 10, 100, 100), playground: Rect::new(10, 10, 100, 100),
vx: 1, vx: 1,
vy: 1, vy: 1,
dir_x: true,
dir_y: true,
} }
} }
fn advance(&mut self) { fn advance(&mut self) {
if self.ball.left() < self.playground.left() || if self.ball.left() < self.playground.left() ||
self.ball.right() > self.playground.right() { self.ball.right() > self.playground.right() {
self.vx = !self.vx; self.dir_x = !self.dir_x;
} else if self.ball.top() < self.playground.top() || }
self.ball.bottom() > self.playground.bottom() { if self.ball.top() < self.playground.top() ||
self.vy = !self.vy; self.ball.bottom() > self.playground.bottom() {
self.dir_y = !self.dir_y;
}
if self.dir_x {
self.ball.x += self.vx;
} else {
self.ball.x -= self.vx;
}
if self.dir_y {
self.ball.y += self.vy;
} else {
self.ball.y -= self.vy
} }
self.ball.x += self.vx;
self.ball.y += self.vy;
} }
} }
@ -94,11 +109,16 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
let size = terminal.size().unwrap(); app.size = terminal.size().unwrap();
app.size = size;
draw(&mut terminal, &app); draw(&mut terminal, &app);
loop { loop {
let size = terminal.size().unwrap();
if size != app.size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = rx.recv().unwrap(); let evt = rx.recv().unwrap();
match evt { match evt {
Event::Input(input) => { Event::Input(input) => {
@ -126,11 +146,6 @@ fn main() {
app.advance(); app.advance();
} }
} }
let size = terminal.size().unwrap();
if size != app.size {
app.size = size;
terminal.resize(size).unwrap();
}
draw(&mut terminal, &app); draw(&mut terminal, &app);
} }

View file

@ -15,9 +15,11 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Chart, Axis, Marker, Dataset}; use tui::widgets::{Widget, Block, border, Chart, Axis, Marker, Dataset};
use tui::layout::Rect;
use tui::style::{Style, Color, Modifier}; use tui::style::{Style, Color, Modifier};
struct App { struct App {
size: Rect,
signal1: SinSignal, signal1: SinSignal,
data1: Vec<(f64, f64)>, data1: Vec<(f64, f64)>,
signal2: SinSignal, signal2: SinSignal,
@ -32,6 +34,7 @@ impl App {
let data1 = signal1.by_ref().take(200).collect::<Vec<(f64, f64)>>(); let data1 = signal1.by_ref().take(200).collect::<Vec<(f64, f64)>>();
let data2 = signal2.by_ref().take(200).collect::<Vec<(f64, f64)>>(); let data2 = signal2.by_ref().take(200).collect::<Vec<(f64, f64)>>();
App { App {
size: Rect::default(),
signal1: signal1, signal1: signal1,
data1: data1, data1: data1,
signal2: signal2, signal2: signal2,
@ -95,9 +98,16 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &app); draw(&mut terminal, &app);
loop { loop {
let size = terminal.size().unwrap();
if app.size != size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = rx.recv().unwrap(); let evt = rx.recv().unwrap();
match evt { match evt {
Event::Input(input) => { Event::Input(input) => {
@ -117,8 +127,6 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &App) { fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
let size = t.size().unwrap();
Chart::default() Chart::default()
.block(Block::default() .block(Block::default()
.title("Chart") .title("Chart")
@ -150,7 +158,7 @@ fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
.marker(Marker::Braille) .marker(Marker::Braille)
.style(Style::default().fg(Color::Yellow)) .style(Style::default().fg(Color::Yellow))
.data(&app.data2)]) .data(&app.data2)])
.render(t, &size); .render(t, &app.size);
t.draw().unwrap(); t.draw().unwrap();
} }

View file

@ -12,10 +12,11 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Gauge}; use tui::widgets::{Widget, Block, border, Gauge};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier}; use tui::style::{Style, Color, Modifier};
struct App { struct App {
size: Rect,
progress1: u16, progress1: u16,
progress2: u16, progress2: u16,
progress3: u16, progress3: u16,
@ -25,6 +26,7 @@ struct App {
impl App { impl App {
fn new() -> App { fn new() -> App {
App { App {
size: Rect::default(),
progress1: 0, progress1: 0,
progress2: 0, progress2: 0,
progress3: 0, progress3: 0,
@ -93,9 +95,16 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &app); draw(&mut terminal, &app);
loop { loop {
let size = terminal.size().unwrap();
if size != app.size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = rx.recv().unwrap(); let evt = rx.recv().unwrap();
match evt { match evt {
Event::Input(input) => { Event::Input(input) => {
@ -115,13 +124,11 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &App) { fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
let size = t.size().unwrap();
Group::default() Group::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(2) .margin(2)
.sizes(&[Size::Percent(25), Size::Percent(25), Size::Percent(25), Size::Percent(25)]) .sizes(&[Size::Percent(25), Size::Percent(25), Size::Percent(25), Size::Percent(25)])
.render(t, &size, |t, chunks| { .render(t, &app.size, |t, chunks| {
Gauge::default() Gauge::default()
.block(Block::default().title("Gauge1").borders(border::ALL)) .block(Block::default().title("Gauge1").borders(border::ALL))
.style(Style::default().fg(Color::Yellow)) .style(Style::default().fg(Color::Yellow))

View file

@ -12,10 +12,11 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, SelectableList, List}; use tui::widgets::{Widget, Block, border, SelectableList, List};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier}; use tui::style::{Style, Color, Modifier};
struct App<'a> { struct App<'a> {
size: Rect,
items: Vec<&'a str>, items: Vec<&'a str>,
selected: usize, selected: usize,
events: Vec<(&'a str, &'a str)>, events: Vec<(&'a str, &'a str)>,
@ -28,6 +29,7 @@ struct App<'a> {
impl<'a> App<'a> { impl<'a> App<'a> {
fn new() -> App<'a> { fn new() -> App<'a> {
App { App {
size: Rect::default(),
items: vec!["Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", items: vec!["Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8",
"Item9", "Item10", "Item11", "Item12", "Item13", "Item14", "Item15", "Item9", "Item10", "Item11", "Item12", "Item13", "Item14", "Item15",
"Item16", "Item17", "Item18", "Item19", "Item20", "Item21", "Item22", "Item16", "Item17", "Item18", "Item19", "Item20", "Item21", "Item22",
@ -113,9 +115,16 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &app); draw(&mut terminal, &app);
loop { loop {
let size = terminal.size().unwrap();
if size != app.size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = rx.recv().unwrap(); let evt = rx.recv().unwrap();
match evt { match evt {
Event::Input(input) => { Event::Input(input) => {
@ -151,12 +160,10 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &App) { fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
let size = t.size().unwrap();
Group::default() Group::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.sizes(&[Size::Percent(50), Size::Percent(50)]) .sizes(&[Size::Percent(50), Size::Percent(50)])
.render(t, &size, |t, chunks| { .render(t, &app.size, |t, chunks| {
SelectableList::default() SelectableList::default()
.block(Block::default() .block(Block::default()
.borders(border::ALL) .borders(border::ALL)

View file

@ -8,7 +8,7 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, Paragraph}; use tui::widgets::{Widget, Block, Paragraph};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color}; use tui::style::{Style, Color};
fn main() { fn main() {
@ -16,9 +16,18 @@ fn main() {
let stdin = io::stdin(); let stdin = io::stdin();
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
draw(&mut terminal);
let mut term_size = terminal.size().unwrap();
draw(&mut terminal, &term_size);
for c in stdin.keys() { for c in stdin.keys() {
draw(&mut terminal); let size = terminal.size().unwrap();
if size != term_size {
terminal.resize(size).unwrap();
term_size = size;
}
draw(&mut terminal, &term_size);
let evt = c.unwrap(); let evt = c.unwrap();
if evt == event::Key::Char('q') { if evt == event::Key::Char('q') {
break; break;
@ -27,9 +36,7 @@ fn main() {
terminal.show_cursor().unwrap(); terminal.show_cursor().unwrap();
} }
fn draw(t: &mut Terminal<TermionBackend>) { fn draw(t: &mut Terminal<TermionBackend>, size: &Rect) {
let size = t.size().unwrap();
Block::default() Block::default()
.style(Style::default().bg(Color::White)) .style(Style::default().bg(Color::White))

View file

@ -15,10 +15,11 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Sparkline}; use tui::widgets::{Widget, Block, border, Sparkline};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color}; use tui::style::{Style, Color};
struct App { struct App {
size: Rect,
signal: RandomSignal, signal: RandomSignal,
data1: Vec<u64>, data1: Vec<u64>,
data2: Vec<u64>, data2: Vec<u64>,
@ -32,6 +33,7 @@ impl App {
let data2 = signal.by_ref().take(200).collect::<Vec<u64>>(); let data2 = signal.by_ref().take(200).collect::<Vec<u64>>();
let data3 = signal.by_ref().take(200).collect::<Vec<u64>>(); let data3 = signal.by_ref().take(200).collect::<Vec<u64>>();
App { App {
size: Rect::default(),
signal: signal, signal: signal,
data1: data1, data1: data1,
data2: data2, data2: data2,
@ -93,9 +95,16 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &app); draw(&mut terminal, &app);
loop { loop {
let size = terminal.size().unwrap();
if size != app.size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = rx.recv().unwrap(); let evt = rx.recv().unwrap();
match evt { match evt {
Event::Input(input) => { Event::Input(input) => {
@ -115,13 +124,11 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &App) { fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
let size = t.size().unwrap();
Group::default() Group::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(2) .margin(2)
.sizes(&[Size::Fixed(3), Size::Fixed(3), Size::Fixed(7), Size::Min(0)]) .sizes(&[Size::Fixed(3), Size::Fixed(3), Size::Fixed(7), Size::Min(0)])
.render(t, &size, |t, chunks| { .render(t, &app.size, |t, chunks| {
Sparkline::default() Sparkline::default()
.block(Block::default().title("Data1").borders(border::LEFT | border::RIGHT)) .block(Block::default().title("Data1").borders(border::LEFT | border::RIGHT))
.data(&app.data1) .data(&app.data1)

View file

@ -9,10 +9,11 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Table}; use tui::widgets::{Widget, Block, border, Table};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier}; use tui::style::{Style, Color, Modifier};
struct App<'a> { struct App<'a> {
size: Rect,
items: Vec<Vec<&'a str>>, items: Vec<Vec<&'a str>>,
selected: usize, selected: usize,
} }
@ -20,6 +21,7 @@ struct App<'a> {
impl<'a> App<'a> { impl<'a> App<'a> {
fn new() -> App<'a> { fn new() -> App<'a> {
App { App {
size: Rect::default(),
items: vec![vec!["Row12", "Row12", "Row13"], items: vec![vec!["Row12", "Row12", "Row13"],
vec!["Row21", "Row22", "Row23"], vec!["Row21", "Row22", "Row23"],
vec!["Row31", "Row32", "Row33"], vec!["Row31", "Row32", "Row33"],
@ -43,11 +45,18 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &app); draw(&mut terminal, &app);
// Input // Input
let stdin = io::stdin(); let stdin = io::stdin();
for c in stdin.keys() { for c in stdin.keys() {
let size = terminal.size().unwrap();
if size != app.size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = c.unwrap(); let evt = c.unwrap();
match evt { match evt {
event::Key::Char('q') => { event::Key::Char('q') => {
@ -76,13 +85,11 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &App) { fn draw(t: &mut Terminal<TermionBackend>, app: &App) {
let size = t.size().unwrap();
Group::default() Group::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.sizes(&[Size::Percent(100)]) .sizes(&[Size::Percent(100)])
.margin(5) .margin(5)
.render(t, &size, |t, chunks| { .render(t, &app.size, |t, chunks| {
let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::Bold); let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::Bold);
let normal_style = Style::default().fg(Color::White); let normal_style = Style::default().fg(Color::White);
Table::default() Table::default()

View file

@ -11,10 +11,11 @@ use termion::input::TermRead;
use tui::Terminal; use tui::Terminal;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Tabs}; use tui::widgets::{Widget, Block, border, Tabs};
use tui::layout::{Group, Direction, Size}; use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color}; use tui::style::{Style, Color};
struct App<'a> { struct App<'a> {
size: Rect,
tabs: MyTabs<'a>, tabs: MyTabs<'a>,
} }
@ -25,6 +26,7 @@ fn main() {
// App // App
let mut app = App { let mut app = App {
size: Rect::default(),
tabs: MyTabs { tabs: MyTabs {
titles: vec!["Tab0", "Tab1", "Tab2", "Tab3"], titles: vec!["Tab0", "Tab1", "Tab2", "Tab3"],
selection: 0, selection: 0,
@ -34,11 +36,18 @@ fn main() {
// First draw call // First draw call
terminal.clear().unwrap(); terminal.clear().unwrap();
terminal.hide_cursor().unwrap(); terminal.hide_cursor().unwrap();
app.size = terminal.size().unwrap();
draw(&mut terminal, &mut app); draw(&mut terminal, &mut app);
// Main loop // Main loop
let stdin = io::stdin(); let stdin = io::stdin();
for c in stdin.keys() { for c in stdin.keys() {
let size = terminal.size().unwrap();
if size != app.size {
terminal.resize(size).unwrap();
app.size = size;
}
let evt = c.unwrap(); let evt = c.unwrap();
match evt { match evt {
event::Key::Char('q') => { event::Key::Char('q') => {
@ -56,17 +65,15 @@ fn main() {
fn draw(t: &mut Terminal<TermionBackend>, app: &mut App) { fn draw(t: &mut Terminal<TermionBackend>, app: &mut App) {
let size = t.size().unwrap();
Block::default() Block::default()
.style(Style::default().bg(Color::White)) .style(Style::default().bg(Color::White))
.render(t, &size); .render(t, &app.size);
Group::default() Group::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(5) .margin(5)
.sizes(&[Size::Fixed(3), Size::Min(0)]) .sizes(&[Size::Fixed(3), Size::Min(0)])
.render(t, &size, |t, chunks| { .render(t, &app.size, |t, chunks| {
Tabs::default() Tabs::default()
.block(Block::default().borders(border::ALL).title("Tabs")) .block(Block::default().borders(border::ALL).title("Tabs"))
.titles(&app.tabs.titles) .titles(&app.tabs.titles)