Convert backends to conditionnal features for compilation

This commit is contained in:
Florian Dehau 2016-11-28 09:52:51 +01:00
parent d00c89ac48
commit feefa5d54f
22 changed files with 361 additions and 322 deletions

View file

@ -3,21 +3,24 @@ name = "tui"
version = "0.1.0"
authors = ["Florian Dehau <work@fdehau.com>"]
description = """
A library to build rich user interfaces or dashboard for terminals
A library to build rich terminal user interfaces or dashboards
"""
keywords = ["tui", "terminal"]
keywords = ["tui", "terminal", "dashboard"]
repository = "https://github.com/fdehau/tui-rs"
license = "MIT"
exclude = ["docs", ".travis.yml"]
[features]
default = ["rustbox", "termion"]
[dependencies]
termion = "1.1.1"
rustbox = "0.9.0"
bitflags = "0.7"
cassowary = "0.2.0"
log = "0.3"
unicode-segmentation = "0.1.2"
unicode-width = "0.1.3"
termion = { version = "1.1.1", optional = true }
rustbox = { version = "0.9.0", optional = true }
[dev-dependencies]
log4rs = "0.5.0"

View file

@ -9,7 +9,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, BarChart};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

View file

@ -5,7 +5,8 @@ use std::io;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

View file

@ -9,7 +9,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border};
use tui::widgets::canvas::{Canvas, Map, MapResolution, Line};
use tui::layout::{Group, Rect, Direction, Size};

View file

@ -12,7 +12,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Chart, Axis, Marker, Dataset};
use tui::style::{Style, Color, Modifier};

View file

@ -1,6 +1,7 @@
extern crate tui;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::Widget;
use tui::buffer::Buffer;
use tui::layout::Rect;

View file

@ -2,7 +2,6 @@
extern crate log;
extern crate tui;
#[macro_use]
extern crate termion;
mod util;
@ -16,7 +15,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, SelectableList, List, Gauge, Sparkline, Paragraph, border,
Chart, Axis, Dataset, BarChart, Marker, Tabs, Table};
use tui::widgets::canvas::{Canvas, Map, MapResolution, Line};

View file

@ -9,7 +9,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Gauge};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

View file

@ -9,7 +9,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, SelectableList, List};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

View file

@ -5,7 +5,8 @@ use std::io;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, Paragraph};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color};

View file

@ -4,7 +4,8 @@ extern crate rustbox;
use std::error::Error;
use rustbox::Key;
use tui::{Terminal, RustboxBackend};
use tui::Terminal;
use tui::backend::RustboxBackend;
use tui::widgets::{Widget, Block, border, Paragraph};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

View file

@ -12,7 +12,8 @@ use std::sync::mpsc;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Sparkline};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color};

View file

@ -6,7 +6,8 @@ use std::io;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Table};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

View file

@ -8,7 +8,8 @@ use std::io;
use termion::event;
use termion::input::TermRead;
use tui::{Terminal, TermionBackend};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, Tabs};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color};

24
src/backend/mod.rs Normal file
View file

@ -0,0 +1,24 @@
use std::io;
use buffer::Cell;
use layout::Rect;
#[cfg(feature = "rustbox")]
mod rustbox;
#[cfg(feature = "rustbox")]
pub use self::rustbox::RustboxBackend;
#[cfg(feature = "termion")]
mod termion;
#[cfg(feature = "termion")]
pub use self::termion::TermionBackend;
pub trait Backend {
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where I: Iterator<Item = (u16, u16, &'a Cell)>;
fn hide_cursor(&mut self) -> Result<(), io::Error>;
fn show_cursor(&mut self) -> Result<(), io::Error>;
fn clear(&mut self) -> Result<(), io::Error>;
fn size(&self) -> Result<Rect, io::Error>;
fn flush(&mut self) -> Result<(), io::Error>;
}

99
src/backend/rustbox.rs Normal file
View file

@ -0,0 +1,99 @@
extern crate rustbox;
use std::io;
use super::Backend;
use buffer::Cell;
use layout::Rect;
use style::{Color, Modifier};
pub struct RustboxBackend {
rustbox: rustbox::RustBox,
}
impl RustboxBackend {
pub fn new() -> Result<RustboxBackend, rustbox::InitError> {
let rustbox = try!(rustbox::RustBox::init(Default::default()));
Ok(RustboxBackend { rustbox: rustbox })
}
pub fn with_rustbox(instance: rustbox::RustBox) -> RustboxBackend {
RustboxBackend { rustbox: instance }
}
pub fn rustbox(&self) -> &rustbox::RustBox {
&self.rustbox
}
}
impl Backend for RustboxBackend {
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where I: Iterator<Item = (u16, u16, &'a Cell)>
{
let mut inst = 0;
for (x, y, cell) in content {
inst += 1;
self.rustbox.print(x as usize,
y as usize,
cell.style.modifier.into(),
cell.style.fg.into(),
cell.style.bg.into(),
&cell.symbol);
}
debug!("{} instructions outputed", inst);
Ok(())
}
fn hide_cursor(&mut self) -> Result<(), io::Error> {
Ok(())
}
fn show_cursor(&mut self) -> Result<(), io::Error> {
Ok(())
}
fn clear(&mut self) -> Result<(), io::Error> {
self.rustbox.clear();
Ok(())
}
fn size(&self) -> Result<Rect, io::Error> {
Ok((Rect {
x: 0,
y: 0,
width: self.rustbox.width() as u16,
height: self.rustbox.height() as u16,
}))
}
fn flush(&mut self) -> Result<(), io::Error> {
self.rustbox.present();
Ok(())
}
}
fn rgb_to_byte(r: u8, g: u8, b: u8) -> u16 {
((((r & 255 & 0xC0) + ((g & 255 & 0xE0) >> 2) + ((b & 0xE0) >> 5))) & 0xFF) as u16
}
impl Into<rustbox::Color> for Color {
fn into(self) -> rustbox::Color {
match self {
Color::Reset => rustbox::Color::Default,
Color::Black | Color::Gray | Color::DarkGray => rustbox::Color::Black,
Color::Red | Color::LightRed => rustbox::Color::Red,
Color::Green | Color::LightGreen => rustbox::Color::Green,
Color::Yellow | Color::LightYellow => rustbox::Color::Yellow,
Color::Magenta | Color::LightMagenta => rustbox::Color::Magenta,
Color::Cyan | Color::LightCyan => rustbox::Color::Cyan,
Color::White => rustbox::Color::White,
Color::Rgb(r, g, b) => rustbox::Color::Byte(rgb_to_byte(r, g, b)),
}
}
}
impl Into<rustbox::Style> for Modifier {
fn into(self) -> rustbox::Style {
match self {
Modifier::Bold => rustbox::RB_BOLD,
Modifier::Underline => rustbox::RB_UNDERLINE,
Modifier::Invert => rustbox::RB_REVERSE,
_ => rustbox::RB_NORMAL,
}
}
}

195
src/backend/termion.rs Normal file
View file

@ -0,0 +1,195 @@
extern crate termion;
use std::io;
use std::io::Write;
use self::termion::raw::{IntoRawMode, RawTerminal};
use super::Backend;
use buffer::Cell;
use layout::Rect;
use style::{Style, Color, Modifier};
pub struct TermionBackend {
stdout: RawTerminal<io::Stdout>,
}
impl TermionBackend {
pub fn new() -> Result<TermionBackend, io::Error> {
let stdout = try!(io::stdout().into_raw_mode());
Ok(TermionBackend { stdout: stdout })
}
}
impl Backend for TermionBackend {
/// Clears the entire screen and move the cursor to the top left of the screen
fn clear(&mut self) -> Result<(), io::Error> {
write!(self.stdout, "{}", termion::clear::All)?;
write!(self.stdout, "{}", termion::cursor::Goto(1, 1))?;
self.stdout.flush()?;
Ok(())
}
/// Hides cursor
fn hide_cursor(&mut self) -> Result<(), io::Error> {
write!(self.stdout, "{}", termion::cursor::Hide)?;
self.stdout.flush()?;
Ok(())
}
/// Shows cursor
fn show_cursor(&mut self) -> Result<(), io::Error> {
write!(self.stdout, "{}", termion::cursor::Show)?;
self.stdout.flush()?;
Ok(())
}
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where I: Iterator<Item = (u16, u16, &'a Cell)>
{
let mut string = String::with_capacity(content.size_hint().0 * 3);
let mut style = Style::default();
let mut last_y = 0;
let mut last_x = 0;
let mut inst = 0;
for (x, y, cell) in content {
if y != last_y || x != last_x + 1 {
string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1)));
inst += 1;
}
last_x = x;
last_y = y;
if cell.style.modifier != style.modifier {
string.push_str(&cell.style.modifier.termion_modifier());
style.modifier = cell.style.modifier;
if style.modifier == Modifier::Reset {
style.bg = Color::Reset;
style.fg = Color::Reset;
}
inst += 1;
}
if cell.style.fg != style.fg {
string.push_str(&cell.style.fg.termion_fg());
style.fg = cell.style.fg;
inst += 1;
}
if cell.style.bg != style.bg {
string.push_str(&cell.style.bg.termion_bg());
style.bg = cell.style.bg;
inst += 1;
}
string.push_str(&cell.symbol);
inst += 1;
}
debug!("{} instructions outputed.", inst);
write!(self.stdout,
"{}{}{}{}",
string,
Color::Reset.termion_fg(),
Color::Reset.termion_bg(),
Modifier::Reset.termion_modifier())?;
Ok(())
}
/// Return the size of the terminal
fn size(&self) -> Result<Rect, io::Error> {
let terminal = try!(termion::terminal_size());
Ok(Rect {
x: 0,
y: 0,
width: terminal.0,
height: terminal.1,
})
}
fn flush(&mut self) -> Result<(), io::Error> {
try!(self.stdout.flush());
Ok(())
}
}
macro_rules! termion_fg {
($color:ident) => (format!("{}", termion::color::Fg(termion::color::$color)));
}
macro_rules! termion_fg_rgb {
($r:expr, $g:expr, $b:expr) => (format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b))));
}
macro_rules! termion_bg {
($color:ident) => (format!("{}", termion::color::Bg(termion::color::$color)));
}
macro_rules! termion_bg_rgb {
($r:expr, $g:expr, $b:expr) => (format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b))));
}
macro_rules! termion_modifier {
($style:ident) => (format!("{}", termion::style::$style));
}
impl Color {
pub fn termion_fg(&self) -> String {
match *self {
Color::Reset => termion_fg!(Reset),
Color::Black => termion_fg!(Black),
Color::Red => termion_fg!(Red),
Color::Green => termion_fg!(Green),
Color::Yellow => termion_fg!(Yellow),
Color::Magenta => termion_fg!(Magenta),
Color::Cyan => termion_fg!(Cyan),
Color::Gray => termion_fg_rgb!(146, 131, 116),
Color::DarkGray => termion_fg_rgb!(80, 73, 69),
Color::LightRed => termion_fg!(LightRed),
Color::LightGreen => termion_fg!(LightGreen),
Color::LightYellow => termion_fg!(LightYellow),
Color::LightMagenta => termion_fg!(LightMagenta),
Color::LightCyan => termion_fg!(LightCyan),
Color::White => termion_fg!(White),
Color::Rgb(r, g, b) => termion_fg_rgb!(r, g, b),
}
}
pub fn termion_bg(&self) -> String {
match *self {
Color::Reset => termion_bg!(Reset),
Color::Black => termion_bg!(Black),
Color::Red => termion_bg!(Red),
Color::Green => termion_bg!(Green),
Color::Yellow => termion_bg!(Yellow),
Color::Magenta => termion_bg!(Magenta),
Color::Cyan => termion_bg!(Cyan),
Color::Gray => termion_bg_rgb!(146, 131, 116),
Color::DarkGray => termion_bg_rgb!(80, 73, 69),
Color::LightRed => termion_bg!(LightRed),
Color::LightGreen => termion_bg!(LightGreen),
Color::LightYellow => termion_bg!(LightYellow),
Color::LightMagenta => termion_bg!(LightMagenta),
Color::LightCyan => termion_bg!(LightCyan),
Color::White => termion_bg!(White),
Color::Rgb(r, g, b) => termion_bg_rgb!(r, g, b),
}
}
}
impl Modifier {
pub fn termion_modifier(&self) -> String {
match *self {
Modifier::Blink => termion_modifier!(Blink),
Modifier::Bold => termion_modifier!(Bold),
Modifier::CrossedOut => termion_modifier!(CrossedOut),
Modifier::Faint => termion_modifier!(Faint),
Modifier::Framed => termion_modifier!(Framed),
Modifier::Invert => termion_modifier!(Invert),
Modifier::Italic => termion_modifier!(Italic),
Modifier::NoBlink => termion_modifier!(NoBlink),
Modifier::NoBold => termion_modifier!(NoBold),
Modifier::NoCrossedOut => termion_modifier!(NoCrossedOut),
Modifier::NoFaint => termion_modifier!(NoFaint),
Modifier::NoInvert => termion_modifier!(NoInvert),
Modifier::NoItalic => termion_modifier!(NoItalic),
Modifier::NoUnderline => termion_modifier!(NoUnderline),
Modifier::Reset => termion_modifier!(Reset),
Modifier::Underline => termion_modifier!(Underline),
}
}
}

View file

@ -5,7 +5,8 @@ use cassowary::{Solver, Variable, Expression, Constraint};
use cassowary::WeightedRelation::*;
use cassowary::strength::{REQUIRED, WEAK};
use terminal::{Terminal, Backend};
use terminal::Terminal;
use backend::Backend;
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
pub enum Direction {

View file

@ -1,5 +1,3 @@
extern crate termion;
extern crate rustbox;
#[macro_use]
extern crate bitflags;
#[macro_use]
@ -10,9 +8,10 @@ extern crate unicode_width;
pub mod buffer;
pub mod symbols;
pub mod backend;
pub mod terminal;
pub mod widgets;
pub mod style;
pub mod layout;
pub use self::terminal::{Terminal, Backend, TermionBackend, RustboxBackend};
pub use self::terminal::Terminal;

View file

@ -1,6 +1,3 @@
use termion;
use rustbox;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Color {
Reset,
@ -78,120 +75,3 @@ impl Style {
self
}
}
macro_rules! termion_fg {
($color:ident) => (format!("{}", termion::color::Fg(termion::color::$color)));
}
macro_rules! termion_fg_rgb {
($r:expr, $g:expr, $b:expr) => (format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b))));
}
macro_rules! termion_bg {
($color:ident) => (format!("{}", termion::color::Bg(termion::color::$color)));
}
macro_rules! termion_bg_rgb {
($r:expr, $g:expr, $b:expr) => (format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b))));
}
macro_rules! termion_modifier {
($style:ident) => (format!("{}", termion::style::$style));
}
impl Color {
pub fn termion_fg(&self) -> String {
match *self {
Color::Reset => termion_fg!(Reset),
Color::Black => termion_fg!(Black),
Color::Red => termion_fg!(Red),
Color::Green => termion_fg!(Green),
Color::Yellow => termion_fg!(Yellow),
Color::Magenta => termion_fg!(Magenta),
Color::Cyan => termion_fg!(Cyan),
Color::Gray => termion_fg_rgb!(146, 131, 116),
Color::DarkGray => termion_fg_rgb!(80, 73, 69),
Color::LightRed => termion_fg!(LightRed),
Color::LightGreen => termion_fg!(LightGreen),
Color::LightYellow => termion_fg!(LightYellow),
Color::LightMagenta => termion_fg!(LightMagenta),
Color::LightCyan => termion_fg!(LightCyan),
Color::White => termion_fg!(White),
Color::Rgb(r, g, b) => termion_fg_rgb!(r, g, b),
}
}
pub fn termion_bg(&self) -> String {
match *self {
Color::Reset => termion_bg!(Reset),
Color::Black => termion_bg!(Black),
Color::Red => termion_bg!(Red),
Color::Green => termion_bg!(Green),
Color::Yellow => termion_bg!(Yellow),
Color::Magenta => termion_bg!(Magenta),
Color::Cyan => termion_bg!(Cyan),
Color::Gray => termion_bg_rgb!(146, 131, 116),
Color::DarkGray => termion_bg_rgb!(80, 73, 69),
Color::LightRed => termion_bg!(LightRed),
Color::LightGreen => termion_bg!(LightGreen),
Color::LightYellow => termion_bg!(LightYellow),
Color::LightMagenta => termion_bg!(LightMagenta),
Color::LightCyan => termion_bg!(LightCyan),
Color::White => termion_bg!(White),
Color::Rgb(r, g, b) => termion_bg_rgb!(r, g, b),
}
}
}
fn rgb_to_byte(r: u8, g: u8, b: u8) -> u16 {
((((r & 255 & 0xC0) + ((g & 255 & 0xE0) >> 2) + ((b & 0xE0) >> 5))) & 0xFF) as u16
}
impl Into<rustbox::Color> for Color {
fn into(self) -> rustbox::Color {
match self {
Color::Reset => rustbox::Color::Default,
Color::Black | Color::Gray | Color::DarkGray => rustbox::Color::Black,
Color::Red | Color::LightRed => rustbox::Color::Red,
Color::Green | Color::LightGreen => rustbox::Color::Green,
Color::Yellow | Color::LightYellow => rustbox::Color::Yellow,
Color::Magenta | Color::LightMagenta => rustbox::Color::Magenta,
Color::Cyan | Color::LightCyan => rustbox::Color::Cyan,
Color::White => rustbox::Color::White,
Color::Rgb(r, g, b) => rustbox::Color::Byte(rgb_to_byte(r, g, b)),
}
}
}
impl Modifier {
pub fn termion_modifier(&self) -> String {
match *self {
Modifier::Blink => termion_modifier!(Blink),
Modifier::Bold => termion_modifier!(Bold),
Modifier::CrossedOut => termion_modifier!(CrossedOut),
Modifier::Faint => termion_modifier!(Faint),
Modifier::Framed => termion_modifier!(Framed),
Modifier::Invert => termion_modifier!(Invert),
Modifier::Italic => termion_modifier!(Italic),
Modifier::NoBlink => termion_modifier!(NoBlink),
Modifier::NoBold => termion_modifier!(NoBold),
Modifier::NoCrossedOut => termion_modifier!(NoCrossedOut),
Modifier::NoFaint => termion_modifier!(NoFaint),
Modifier::NoInvert => termion_modifier!(NoInvert),
Modifier::NoItalic => termion_modifier!(NoItalic),
Modifier::NoUnderline => termion_modifier!(NoUnderline),
Modifier::Reset => termion_modifier!(Reset),
Modifier::Underline => termion_modifier!(Underline),
}
}
}
impl Into<rustbox::Style> for Modifier {
fn into(self) -> rustbox::Style {
match self {
Modifier::Bold => rustbox::RB_BOLD,
Modifier::Underline => rustbox::RB_UNDERLINE,
Modifier::Invert => rustbox::RB_REVERSE,
_ => rustbox::RB_NORMAL,
}
}
}

View file

@ -1,184 +1,10 @@
use std::io;
use std::io::Write;
use std::collections::HashMap;
use termion;
use termion::raw::{IntoRawMode, RawTerminal};
use rustbox;
use buffer::{Buffer, Cell};
use backend::Backend;
use buffer::Buffer;
use layout::{Rect, Group, split};
use widgets::Widget;
use style::{Color, Modifier, Style};
pub trait Backend {
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where I: Iterator<Item = (u16, u16, &'a Cell)>;
fn hide_cursor(&mut self) -> Result<(), io::Error>;
fn show_cursor(&mut self) -> Result<(), io::Error>;
fn clear(&mut self) -> Result<(), io::Error>;
fn size(&self) -> Result<Rect, io::Error>;
fn flush(&mut self) -> Result<(), io::Error>;
}
pub struct TermionBackend {
stdout: RawTerminal<io::Stdout>,
}
impl TermionBackend {
pub fn new() -> Result<TermionBackend, io::Error> {
let stdout = try!(io::stdout().into_raw_mode());
Ok(TermionBackend { stdout: stdout })
}
}
impl Backend for TermionBackend {
/// Clears the entire screen and move the cursor to the top left of the screen
fn clear(&mut self) -> Result<(), io::Error> {
try!(write!(self.stdout, "{}", termion::clear::All));
try!(write!(self.stdout, "{}", termion::cursor::Goto(1, 1)));
try!(self.stdout.flush());
Ok(())
}
/// Hides cursor
fn hide_cursor(&mut self) -> Result<(), io::Error> {
try!(write!(self.stdout, "{}", termion::cursor::Hide));
try!(self.stdout.flush());
Ok(())
}
/// Shows cursor
fn show_cursor(&mut self) -> Result<(), io::Error> {
try!(write!(self.stdout, "{}", termion::cursor::Show));
try!(self.stdout.flush());
Ok(())
}
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where I: Iterator<Item = (u16, u16, &'a Cell)>
{
let mut string = String::with_capacity(content.size_hint().0 * 3);
let mut style = Style::default();
let mut last_y = 0;
let mut last_x = 0;
let mut inst = 0;
for (x, y, cell) in content {
if y != last_y || x != last_x + 1 {
string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1)));
inst += 1;
}
last_x = x;
last_y = y;
if cell.style.modifier != style.modifier {
string.push_str(&cell.style.modifier.termion_modifier());
style.modifier = cell.style.modifier;
if style.modifier == Modifier::Reset {
style.bg = Color::Reset;
style.fg = Color::Reset;
}
inst += 1;
}
if cell.style.fg != style.fg {
string.push_str(&cell.style.fg.termion_fg());
style.fg = cell.style.fg;
inst += 1;
}
if cell.style.bg != style.bg {
string.push_str(&cell.style.bg.termion_bg());
style.bg = cell.style.bg;
inst += 1;
}
string.push_str(&cell.symbol);
inst += 1;
}
debug!("{} instructions outputed.", inst);
try!(write!(self.stdout,
"{}{}{}{}",
string,
Color::Reset.termion_fg(),
Color::Reset.termion_bg(),
Modifier::Reset.termion_modifier()));
Ok(())
}
/// Return the size of the terminal
fn size(&self) -> Result<Rect, io::Error> {
let terminal = try!(termion::terminal_size());
Ok(Rect {
x: 0,
y: 0,
width: terminal.0,
height: terminal.1,
})
}
fn flush(&mut self) -> Result<(), io::Error> {
try!(self.stdout.flush());
Ok(())
}
}
pub struct RustboxBackend {
rustbox: rustbox::RustBox,
}
impl RustboxBackend {
pub fn new() -> Result<RustboxBackend, rustbox::InitError> {
let rustbox = try!(rustbox::RustBox::init(Default::default()));
Ok(RustboxBackend { rustbox: rustbox })
}
pub fn with_rustbox(instance: rustbox::RustBox) -> RustboxBackend {
RustboxBackend { rustbox: instance }
}
pub fn rustbox(&self) -> &rustbox::RustBox {
&self.rustbox
}
}
impl Backend for RustboxBackend {
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where I: Iterator<Item = (u16, u16, &'a Cell)>
{
let mut inst = 0;
for (x, y, cell) in content {
inst += 1;
self.rustbox.print(x as usize,
y as usize,
cell.style.modifier.into(),
cell.style.fg.into(),
cell.style.bg.into(),
&cell.symbol);
}
debug!("{} instructions outputed", inst);
Ok(())
}
fn hide_cursor(&mut self) -> Result<(), io::Error> {
Ok(())
}
fn show_cursor(&mut self) -> Result<(), io::Error> {
Ok(())
}
fn clear(&mut self) -> Result<(), io::Error> {
self.rustbox.clear();
Ok(())
}
fn size(&self) -> Result<Rect, io::Error> {
Ok((Rect {
x: 0,
y: 0,
width: self.rustbox.width() as u16,
height: self.rustbox.height() as u16,
}))
}
fn flush(&mut self) -> Result<(), io::Error> {
self.rustbox.present();
Ok(())
}
}
/// Holds a computed layout and keeps track of its use between successive draw calls
#[derive(Debug)]
@ -278,15 +104,14 @@ impl<B> Terminal<B>
self.buffers[1 - self.current].resize(area);
self.buffers[1 - self.current].reset();
self.layout_cache.clear();
try!(self.backend.clear());
Ok(())
self.backend.clear()
}
/// Flushes the current internal state and prepares the interface for the next draw call
pub fn draw(&mut self) -> Result<(), io::Error> {
// Draw to stdout
try!(self.flush());
self.flush()?;
// Clean layout cache
let hot = self.layout_cache

View file

@ -21,7 +21,8 @@ pub use self::table::Table;
use buffer::Buffer;
use layout::Rect;
use terminal::{Backend, Terminal};
use terminal::Terminal;
use backend::Backend;
use style::Color;
/// Bitflags that can be composed to set the visible borders essentially on the block widget.