From a36e20f2172d6f8e00eed8108fe0ba2acac3a16b Mon Sep 17 00:00:00 2001 From: Florian Dehau Date: Wed, 2 Nov 2016 17:08:52 +0100 Subject: [PATCH] Add background_color support for all existing wigets --- examples/block.rs | 37 ++++++++++++++++----- examples/prototype.rs | 47 +++++++++++++++----------- src/widgets/barchart.rs | 18 +++++++--- src/widgets/block.rs | 46 ++++++++++++++++++-------- src/widgets/canvas/map.rs | 11 ++----- src/widgets/canvas/mod.rs | 20 ++++++++---- src/widgets/chart.rs | 59 +++++++++++++++++++++------------ src/widgets/gauge.rs | 42 +++++++++++++----------- src/widgets/list.rs | 46 ++++++++++++++------------ src/widgets/mod.rs | 8 +++++ src/widgets/sparkline.rs | 69 ++++++++++++++++++++------------------- src/widgets/table.rs | 46 +++++++++++++++++++++----- src/widgets/tabs.rs | 25 ++++++++++---- src/widgets/text.rs | 40 ++++++++++++++--------- 14 files changed, 331 insertions(+), 183 deletions(-) diff --git a/examples/block.rs b/examples/block.rs index f07d9e3..2543a0e 100644 --- a/examples/block.rs +++ b/examples/block.rs @@ -15,12 +15,13 @@ fn main() { let stdin = io::stdin(); terminal.clear(); terminal.hide_cursor(); + draw(&mut terminal); for c in stdin.keys() { + draw(&mut terminal); let evt = c.unwrap(); if evt == event::Key::Char('q') { break; } - draw(&mut terminal); } terminal.show_cursor(); } @@ -29,18 +30,38 @@ fn draw(t: &mut Terminal) { Group::default() .direction(Direction::Vertical) - .sizes(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)]) + .sizes(&[Size::Fixed(7), Size::Min(0), Size::Fixed(7)]) .render(t, &Terminal::size().unwrap(), |t, chunks| { Block::default() - .title("Block") - .title_color(Color::Red) - .borders(border::ALL) + .title("Top") + .title_color(Color::Magenta) + .background_color(Color::White) + .border_color(Color::Magenta) + .borders(border::BOTTOM) .render(&chunks[0], t); Group::default() - .direction(Direction::Vertical) - .sizes(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)]) + .direction(Direction::Horizontal) + .sizes(&[Size::Fixed(7), Size::Min(0), Size::Fixed(7)]) .render(t, &chunks[1], |t, chunks| { - Block::default().title("Block").render(&chunks[0], t); + Block::default().title("Left").title_color(Color::Yellow).render(&chunks[0], t); + Block::default() + .title("Middle") + .title_color(Color::Cyan) + .border_color(Color::Cyan) + .borders(border::LEFT | border::RIGHT) + .render(&chunks[1], t); + Block::default() + .title("Right") + .title_color(Color::Green) + .render(&chunks[2], t); }); + Block::default() + .title("Bottom") + .title_color(Color::Red) + .border_color(Color::Red) + .borders(border::TOP) + .render(&chunks[2], t); }); + + t.finish(); } diff --git a/examples/prototype.rs b/examples/prototype.rs index 2b28658..28aeebd 100644 --- a/examples/prototype.rs +++ b/examples/prototype.rs @@ -70,9 +70,10 @@ impl SinSignal { impl Iterator for SinSignal { type Item = (f64, f64); - fn next(&mut self) -> Option<(f64, f64)> { + fn next(&mut self) -> Option { + let point = (self.x, (self.x * 1.0 / self.period).sin() * self.scale); self.x += self.interval; - Some((self.x, ((self.x * 1.0 / self.period).sin() + 1.0) * self.scale)) + Some(point) } } @@ -131,7 +132,7 @@ fn main() { info!("Start"); let mut rand_signal = RandomSignal::new(Range::new(0, 100)); - let mut sin_signal = SinSignal::new(1.0, 4.0, 20.0); + let mut sin_signal = SinSignal::new(0.2, 5.0, 20.0); let mut sin_signal2 = SinSignal::new(0.1, 2.0, 10.0); let mut app = App { @@ -149,7 +150,7 @@ fn main() { show_chart: true, progress: 0, data: rand_signal.clone().take(200).collect(), - data2: sin_signal.clone().take(30).collect(), + data2: sin_signal.clone().take(100).collect(), data3: sin_signal2.clone().take(200).collect(), data4: vec![("B1", 9), ("B2", 12), @@ -173,7 +174,7 @@ fn main() { let (tx, rx) = mpsc::channel(); let input_tx = tx.clone(); - for _ in 0..30 { + for _ in 0..100 { sin_signal.next(); } for _ in 0..200 { @@ -246,12 +247,12 @@ fn main() { } app.data.insert(0, rand_signal.next().unwrap()); app.data.pop(); - app.data2.remove(0); - app.data2.push(sin_signal.next().unwrap()); - for _ in 0..10 { - app.data3.remove(0); + for _ in 0..5 { + app.data2.remove(0); + app.data2.push(sin_signal.next().unwrap()); } for _ in 0..10 { + app.data3.remove(0); app.data3.push(sin_signal2.next().unwrap()); } let i = app.data4.pop().unwrap(); @@ -279,6 +280,7 @@ fn draw(t: &mut Terminal, app: &App) { Tabs::default() .block(Block::default().borders(border::ALL).title("Tabs")) .titles(&app.tabs.titles) + .color(Color::Green) .highlight_color(Color::Yellow) .select(app.tabs.selection) .render(&chunks[0], t); @@ -292,15 +294,22 @@ fn draw(t: &mut Terminal, app: &App) { .sizes(&[Size::Percent(50), Size::Percent(50)]) .render(t, &chunks[1], |t, chunks| { Table::default() - .block(Block::default().title("Servers").borders(border::ALL)) - .titles(&["Server", "Location", "Status"]) + .block(Block::default() + .title("Servers") + .borders(border::ALL)) + .header(&["Server", "Location", "Status"]) + .header_color(Color::Red) .widths(&[20, 20, 20]) .rows(&[&["Europe#1", "Paris", "Up"], &["Europe#2", "Berlin", "Up"]]) + .color(Color::Green) .render(&chunks[0], t); Canvas::default() .block(Block::default().title("World").borders(border::ALL)) - .layers(&[&[Map::default().resolution(MapResolution::High)]]) + .layers(&[&[&Map { + color: Color::Green, + resolution: MapResolution::High, + }]]) .x_bounds([-180.0, 180.0]) .y_bounds([-90.0, 90.0]) .render(&chunks[1], t); @@ -360,8 +369,8 @@ fn draw_main(t: &mut Terminal, app: &App, area: &Rect) { .title("List")) .items(&app.items) .select(app.selected) - .selection_color(Color::Yellow) - .selection_symbol(">") + .highlight_color(Color::Yellow) + .highlight_symbol(">") .render(&chunks[0], t); List::default() .block(Block::default() @@ -395,8 +404,8 @@ fn draw_main(t: &mut Terminal, app: &App, area: &Rect) { .y_axis(Axis::default() .title("Y Axis") .color(Color::Gray) - .bounds([0.0, 40.0]) - .labels(&["0", "20", "40"])) + .bounds([-25.0, 25.0]) + .labels(&["-25", "0", "25"])) .datasets(&[Dataset::default() .marker(Marker::Dot) .color(Color::Cyan) @@ -411,9 +420,9 @@ fn draw_main(t: &mut Terminal, app: &App, area: &Rect) { Text::default() .block(Block::default().borders(border::ALL).title("Footer")) .wrap(true) - .fg(app.colors[app.color_index]) - .text("This a paragraph with several lines.\nYou can change the \ - color.\nUse \\{[color] [text]} to highlight the text with the \ + .color(app.colors[app.color_index]) + .text("This is a paragraph with several lines.\nYou can change the \ + color.\nUse \\{[color] [text]} to highlight the text with a \ color. For example, {red u}{green n}{yellow d}{magenta e}{cyan r} \ {gray t}{light_gray h}{light_red e} {light_green r}{light_yellow \ a}{light_magenta i}{light_cyan n}{white b}{red o}{green w}.\nOh, \ diff --git a/src/widgets/barchart.rs b/src/widgets/barchart.rs index 37f7300..00719f8 100644 --- a/src/widgets/barchart.rs +++ b/src/widgets/barchart.rs @@ -16,6 +16,7 @@ pub struct BarChart<'a> { bar_color: Color, value_color: Color, label_color: Color, + background_color: Color, data: &'a [(&'a str, u64)], values: Vec, } @@ -25,13 +26,14 @@ impl<'a> Default for BarChart<'a> { BarChart { block: None, max: None, + data: &[], + values: Vec::new(), bar_width: 1, bar_gap: 1, bar_color: Color::Reset, value_color: Color::Reset, label_color: Color::Reset, - data: &[], - values: Vec::new(), + background_color: Color::Reset, } } } @@ -75,6 +77,10 @@ impl<'a> BarChart<'a> { self.label_color = color; self } + pub fn background_color(&'a mut self, color: Color) -> &mut BarChart<'a> { + self.background_color = color; + self + } } impl<'a> Widget for BarChart<'a> { @@ -91,6 +97,10 @@ impl<'a> Widget for BarChart<'a> { return; } + if self.background_color != Color::Reset { + self.background(&chart_area, buf, self.background_color); + } + let max = self.max.unwrap_or(self.data.iter().fold(0, |acc, &(_, v)| max(v, acc))); let max_index = min((chart_area.width / (self.bar_width + self.bar_gap)) as usize, self.data.len()); @@ -119,7 +129,7 @@ impl<'a> Widget for BarChart<'a> { chart_area.top() + j, symbol, self.bar_color, - Color::Reset); + self.background_color); } if d.1 > 8 { @@ -149,7 +159,7 @@ impl<'a> Widget for BarChart<'a> { label, self.bar_width as usize, self.label_color, - Color::Reset); + self.background_color); } } } diff --git a/src/widgets/block.rs b/src/widgets/block.rs index 8b8877d..04132b3 100644 --- a/src/widgets/block.rs +++ b/src/widgets/block.rs @@ -6,11 +6,11 @@ use symbols::line; #[derive(Clone, Copy)] pub struct Block<'a> { - title: Option<&'a str>, - title_color: Color, - borders: border::Flags, - border_color: Color, - bg: Color, + pub title: Option<&'a str>, + pub title_color: Color, + pub borders: border::Flags, + pub border_color: Color, + pub background_color: Color, } impl<'a> Default for Block<'a> { @@ -20,7 +20,7 @@ impl<'a> Default for Block<'a> { title_color: Color::Reset, borders: border::NONE, border_color: Color::Reset, - bg: Color::Reset, + background_color: Color::Reset, } } } @@ -41,8 +41,8 @@ impl<'a> Block<'a> { self } - pub fn bg(mut self, color: Color) -> Block<'a> { - self.bg = color; + pub fn background_color(mut self, color: Color) -> Block<'a> { + self.background_color = color; self } @@ -81,27 +81,47 @@ impl<'a> Widget for Block<'a> { return; } + if self.background_color != Color::Reset { + self.background(area, buf, self.background_color) + } + // Sides if self.borders.intersects(border::LEFT) { for y in area.top()..area.bottom() { - buf.set_cell(area.left(), y, line::VERTICAL, self.border_color, self.bg); + buf.set_cell(area.left(), + y, + line::VERTICAL, + self.border_color, + self.background_color); } } if self.borders.intersects(border::TOP) { for x in area.left()..area.right() { - buf.set_cell(x, area.top(), line::HORIZONTAL, self.border_color, self.bg); + buf.set_cell(x, + area.top(), + line::HORIZONTAL, + self.border_color, + self.background_color); } } if self.borders.intersects(border::RIGHT) { let x = area.right() - 1; for y in area.top()..area.bottom() { - buf.set_cell(x, y, line::VERTICAL, self.border_color, self.bg); + buf.set_cell(x, + y, + line::VERTICAL, + self.border_color, + self.background_color); } } if self.borders.intersects(border::BOTTOM) { let y = area.bottom() - 1; for x in area.left()..area.right() { - buf.set_cell(x, y, line::HORIZONTAL, self.border_color, self.bg); + buf.set_cell(x, + y, + line::HORIZONTAL, + self.border_color, + self.background_color); } } @@ -137,7 +157,7 @@ impl<'a> Widget for Block<'a> { title, width as usize, self.title_color, - self.bg); + self.background_color); } } } diff --git a/src/widgets/canvas/map.rs b/src/widgets/canvas/map.rs index 89df233..fb5ae6c 100644 --- a/src/widgets/canvas/map.rs +++ b/src/widgets/canvas/map.rs @@ -19,8 +19,8 @@ impl MapResolution { } pub struct Map { - resolution: MapResolution, - color: Color, + pub resolution: MapResolution, + pub color: Color, } impl Default for Map { @@ -41,13 +41,6 @@ impl<'a> Shape<'a> for Map { } } -impl Map { - pub fn resolution(&mut self, resolution: MapResolution) -> &mut Map { - self.resolution = resolution; - self - } -} - impl<'a> IntoIterator for &'a Map { type Item = (f64, f64); type IntoIter = PointsIterator<'a>; diff --git a/src/widgets/canvas/mod.rs b/src/widgets/canvas/mod.rs index 55418ae..0c2e53c 100644 --- a/src/widgets/canvas/mod.rs +++ b/src/widgets/canvas/mod.rs @@ -29,6 +29,7 @@ pub struct Canvas<'a> { x_bounds: [f64; 2], y_bounds: [f64; 2], layers: &'a [&'a [&'a Shape<'a>]], + background_color: Color, } impl<'a> Default for Canvas<'a> { @@ -38,6 +39,7 @@ impl<'a> Default for Canvas<'a> { x_bounds: [0.0, 0.0], y_bounds: [0.0, 0.0], layers: &[], + background_color: Color::Reset, } } } @@ -59,6 +61,11 @@ impl<'a> Canvas<'a> { self.layers = layers; self } + + pub fn background_color(&'a mut self, color: Color) -> &mut Canvas<'a> { + self.background_color = color; + self + } } impl<'a> Widget for Canvas<'a> { @@ -81,17 +88,17 @@ impl<'a> Widget for Canvas<'a> { for layer in self.layers { - let mut grid: Vec = vec![BRAILLE_OFFSET; width * height + 1]; - let mut colors: Vec = vec![Color::Reset; width * height + 1]; + let mut grid: Vec = vec![BRAILLE_OFFSET; width * height]; + let mut colors: Vec = vec![Color::Reset; width * height]; for shape in layer.iter() { for (x, y) in shape.points().filter(|&(x, y)| { !(x < x_bounds[0] || x > x_bounds[1] || y < y_bounds[0] || y > y_bounds[1]) }) { - let dy = ((self.y_bounds[1] - y) * canvas_area.height as f64 * 4.0 / + let dy = ((self.y_bounds[1] - y) * (canvas_area.height - 1) as f64 * 4.0 / (self.y_bounds[1] - self.y_bounds[0])) as usize; - let dx = ((x - self.x_bounds[0]) * canvas_area.width as f64 * 2.0 / + let dx = ((x - self.x_bounds[0]) * (canvas_area.width - 1) as f64 * 2.0 / (self.x_bounds[1] - self.x_bounds[0])) as usize; let index = dy / 4 * width + dx / 2; @@ -100,8 +107,7 @@ impl<'a> Widget for Canvas<'a> { } } - let mut string = String::from_utf16(&grid).unwrap(); - string.pop(); + let string = String::from_utf16(&grid).unwrap(); for (i, (ch, color)) in string.chars().zip(colors.into_iter()).enumerate() { if ch != BRAILLE_BLANK { let (x, y) = (i % width, i / width); @@ -111,7 +117,7 @@ impl<'a> Widget for Canvas<'a> { c.symbol.clear(); c.symbol.push(ch); c.fg = color; - c.bg = Color::Reset; + c.bg = self.background_color; }); } } diff --git a/src/widgets/chart.rs b/src/widgets/chart.rs index 71273eb..dda25c5 100644 --- a/src/widgets/chart.rs +++ b/src/widgets/chart.rs @@ -131,7 +131,7 @@ pub struct Chart<'a> { x_axis: Axis<'a>, y_axis: Axis<'a>, datasets: &'a [Dataset<'a>], - bg: Color, + background_color: Color, } impl<'a> Default for Chart<'a> { @@ -140,7 +140,7 @@ impl<'a> Default for Chart<'a> { block: None, x_axis: Axis::default(), y_axis: Axis::default(), - bg: Color::Reset, + background_color: Color::Reset, datasets: &[], } } @@ -152,8 +152,8 @@ impl<'a> Chart<'a> { self } - pub fn bg(&mut self, bg: Color) -> &mut Chart<'a> { - self.bg = bg; + pub fn background_color(&mut self, background_color: Color) -> &mut Chart<'a> { + self.background_color = background_color; self } @@ -237,18 +237,22 @@ impl<'a> Widget for Chart<'a> { let layout = self.layout(&chart_area); let graph_area = layout.graph_area; - if graph_area.width == 0 || graph_area.height == 0 { + if graph_area.width < 1 || graph_area.height < 1 { return; } + if self.background_color != Color::Reset { + self.background(&chart_area, buf, self.background_color); + } + if let Some((x, y)) = layout.legend_x { let title = self.x_axis.title.unwrap(); - buf.set_string(x, y, title, self.x_axis.title_color, self.bg); + buf.set_string(x, y, title, self.x_axis.title_color, self.background_color); } if let Some((x, y)) = layout.legend_y { let title = self.y_axis.title.unwrap(); - buf.set_string(x, y, title, self.y_axis.title_color, self.bg); + buf.set_string(x, y, title, self.y_axis.title_color, self.background_color); } if let Some(y) = layout.label_x { @@ -263,7 +267,7 @@ impl<'a> Widget for Chart<'a> { y, label, self.x_axis.labels_color, - self.bg); + self.background_color); } } } @@ -278,26 +282,38 @@ impl<'a> Widget for Chart<'a> { graph_area.bottom() - 1 - dy, label, self.y_axis.labels_color, - self.bg); + self.background_color); } } } if let Some(y) = layout.axis_x { for x in graph_area.left()..graph_area.right() { - buf.set_cell(x, y, symbols::line::HORIZONTAL, self.x_axis.color, self.bg); + buf.set_cell(x, + y, + symbols::line::HORIZONTAL, + self.x_axis.color, + self.background_color); } } if let Some(x) = layout.axis_y { for y in graph_area.top()..graph_area.bottom() { - buf.set_cell(x, y, symbols::line::VERTICAL, self.y_axis.color, self.bg); + buf.set_cell(x, + y, + symbols::line::VERTICAL, + self.y_axis.color, + self.background_color); } } if let Some(y) = layout.axis_x { if let Some(x) = layout.axis_y { - buf.set_cell(x, y, symbols::line::BOTTOM_LEFT, self.x_axis.color, self.bg); + buf.set_cell(x, + y, + symbols::line::BOTTOM_LEFT, + self.x_axis.color, + self.background_color); } } @@ -309,20 +325,23 @@ impl<'a> Widget for Chart<'a> { y < self.y_axis.bounds[0] || y > self.y_axis.bounds[1]) }) { - let dy = (self.y_axis.bounds[1] - y) * graph_area.height as f64 / - (self.y_axis.bounds[1] - self.y_axis.bounds[0]); - let dx = (x - self.x_axis.bounds[0]) * graph_area.width as f64 / - (self.x_axis.bounds[1] - self.x_axis.bounds[0]); - - buf.set_cell(dx as u16 + graph_area.left(), - dy as u16 + graph_area.top(), + let dy = ((self.y_axis.bounds[1] - y) * (graph_area.height - 1) as f64 / + (self.y_axis.bounds[1] - + self.y_axis.bounds[0])) as u16; + let dx = ((x - self.x_axis.bounds[0]) * (graph_area.width - 1) as f64 / + (self.x_axis.bounds[1] - + self.x_axis.bounds[0])) as u16; + + buf.set_cell(graph_area.left() + dx, + graph_area.top() + dy, symbols::BLACK_CIRCLE, dataset.color, - self.bg); + self.background_color); } } Marker::Braille => { Canvas::default() + .background_color(self.background_color) .x_bounds(self.x_axis.bounds) .y_bounds(self.y_axis.bounds) .layers(&[&[&Points { diff --git a/src/widgets/gauge.rs b/src/widgets/gauge.rs index 3f9ae01..7a12cc7 100644 --- a/src/widgets/gauge.rs +++ b/src/widgets/gauge.rs @@ -70,28 +70,32 @@ impl<'a> Widget for Gauge<'a> { }; if gauge_area.height < 1 { return; - } else { - // Gauge - let width = (gauge_area.width * self.percent) / 100; - let end = gauge_area.left() + width; + } - for x in gauge_area.left()..end { - buf.set_symbol(x, gauge_area.top(), " "); - } + if self.background_color != Color::Reset { + self.background(&gauge_area, buf, self.background_color); + } - // Label - let label = format!("{}%", self.percent); - let label_width = label.width() as u16; - let middle = (gauge_area.width - label_width) / 2 + gauge_area.left(); - buf.set_string(middle, - gauge_area.top(), - &label, - self.color, - self.background_color); + // Gauge + let width = (gauge_area.width * self.percent) / 100; + let end = gauge_area.left() + width; - for x in gauge_area.left()..end { - buf.set_colors(x, gauge_area.top(), self.background_color, self.color); - } + for x in gauge_area.left()..end { + buf.set_symbol(x, gauge_area.top(), " "); + } + + // Label + let label = format!("{}%", self.percent); + let label_width = label.width() as u16; + let middle = (gauge_area.width - label_width) / 2 + gauge_area.left(); + buf.set_string(middle, + gauge_area.top(), + &label, + self.color, + self.background_color); + + for x in gauge_area.left()..end { + buf.set_colors(x, gauge_area.top(), self.background_color, self.color); } } } diff --git a/src/widgets/list.rs b/src/widgets/list.rs index e5e1110..1f356e6 100644 --- a/src/widgets/list.rs +++ b/src/widgets/list.rs @@ -9,24 +9,24 @@ use style::Color; pub struct List<'a> { block: Option>, + items: &'a [&'a str], selected: usize, - selection_symbol: Option<&'a str>, - selection_color: Color, color: Color, background_color: Color, - items: &'a [&'a str], + highlight_color: Color, + highlight_symbol: Option<&'a str>, } impl<'a> Default for List<'a> { fn default() -> List<'a> { List { block: None, + items: &[], selected: 0, - selection_symbol: None, - selection_color: Color::Reset, color: Color::Reset, background_color: Color::Reset, - items: &[], + highlight_color: Color::Reset, + highlight_symbol: None, } } } @@ -52,13 +52,13 @@ impl<'a> List<'a> { self } - pub fn selection_symbol(&'a mut self, selection_symbol: &'a str) -> &mut List<'a> { - self.selection_symbol = Some(selection_symbol); + pub fn highlight_symbol(&'a mut self, highlight_symbol: &'a str) -> &mut List<'a> { + self.highlight_symbol = Some(highlight_symbol); self } - pub fn selection_color(&'a mut self, selection_color: Color) -> &mut List<'a> { - self.selection_color = selection_color; + pub fn highlight_color(&'a mut self, highlight_color: Color) -> &mut List<'a> { + self.highlight_color = highlight_color; self } @@ -79,10 +79,14 @@ impl<'a> Widget for List<'a> { None => *area, }; - if list_area.height < 1 { + if list_area.width < 1 || list_area.height < 1 { return; } + if self.background_color != Color::Reset { + self.background(&list_area, buf, self.background_color); + } + let list_length = self.items.len(); let list_height = list_area.height as usize; let bound = min(list_height, list_length); @@ -91,7 +95,8 @@ impl<'a> Widget for List<'a> { } else { 0 }; - let x = match self.selection_symbol { + + let x = match self.highlight_symbol { Some(s) => (s.width() + 1) as u16 + list_area.left(), None => list_area.left(), }; @@ -102,7 +107,7 @@ impl<'a> Widget for List<'a> { let index = i + offset; let item = self.items[index]; let color = if index == self.selected { - self.selection_color + self.highlight_color } else { self.color }; @@ -113,13 +118,14 @@ impl<'a> Widget for List<'a> { color, self.background_color); } - } - if let Some(s) = self.selection_symbol { - buf.set_string(list_area.left(), - list_area.top() + (self.selected - offset) as u16, - s, - self.selection_color, - self.background_color); + + if let Some(s) = self.highlight_symbol { + buf.set_string(list_area.left(), + list_area.top() + (self.selected - offset) as u16, + s, + self.highlight_color, + self.background_color); + } } } } diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 8e5092b..e652b79 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -22,6 +22,7 @@ pub use self::table::Table; use buffer::Buffer; use layout::Rect; use terminal::Terminal; +use style::Color; pub mod border { bitflags! { @@ -38,6 +39,13 @@ pub mod border { pub trait Widget { fn buffer(&self, area: &Rect, buf: &mut Buffer); + fn background(&self, area: &Rect, buf: &mut Buffer, color: Color) { + for y in area.top()..area.bottom() { + for x in area.left()..area.right() { + buf.set_bg(x, y, color); + } + } + } fn render(&self, area: &Rect, t: &mut Terminal) where Self: Sized { diff --git a/src/widgets/sparkline.rs b/src/widgets/sparkline.rs index ee672b8..c6fce3d 100644 --- a/src/widgets/sparkline.rs +++ b/src/widgets/sparkline.rs @@ -63,43 +63,44 @@ impl<'a> Widget for Sparkline<'a> { } None => *area, }; + if spark_area.height < 1 { return; - } else { - let max = match self.max { - Some(v) => v, - None => *self.data.iter().max().unwrap_or(&1u64), - }; - let max_index = min(spark_area.width as usize, self.data.len()); - let mut data = self.data - .iter() - .take(max_index) - .map(|e| e * spark_area.height as u64 * 8 / max) - .collect::>(); - for j in (0..spark_area.height).rev() { - for (i, d) in data.iter_mut().enumerate() { - let symbol = match *d { - 0 => " ", - 1 => bar::ONE_EIGHTH, - 2 => bar::ONE_QUATER, - 3 => bar::THREE_EIGHTHS, - 4 => bar::HALF, - 5 => bar::FIVE_EIGHTHS, - 6 => bar::THREE_QUATERS, - 7 => bar::SEVEN_EIGHTHS, - _ => bar::FULL, - }; - buf.set_cell(spark_area.left() + i as u16, - spark_area.top() + j, - symbol, - self.color, - self.background_color); + } + + let max = match self.max { + Some(v) => v, + None => *self.data.iter().max().unwrap_or(&1u64), + }; + let max_index = min(spark_area.width as usize, self.data.len()); + let mut data = self.data + .iter() + .take(max_index) + .map(|e| e * spark_area.height as u64 * 8 / max) + .collect::>(); + for j in (0..spark_area.height).rev() { + for (i, d) in data.iter_mut().enumerate() { + let symbol = match *d { + 0 => " ", + 1 => bar::ONE_EIGHTH, + 2 => bar::ONE_QUATER, + 3 => bar::THREE_EIGHTHS, + 4 => bar::HALF, + 5 => bar::FIVE_EIGHTHS, + 6 => bar::THREE_QUATERS, + 7 => bar::SEVEN_EIGHTHS, + _ => bar::FULL, + }; + buf.set_cell(spark_area.left() + i as u16, + spark_area.top() + j, + symbol, + self.color, + self.background_color); - if *d > 8 { - *d -= 8; - } else { - *d = 0; - } + if *d > 8 { + *d -= 8; + } else { + *d = 0; } } } diff --git a/src/widgets/table.rs b/src/widgets/table.rs index d0b2dca..45da765 100644 --- a/src/widgets/table.rs +++ b/src/widgets/table.rs @@ -9,20 +9,26 @@ use style::Color; pub struct Table<'a> { block: Option>, - titles: &'a [&'a str], + header: &'a [&'a str], + header_color: Color, widths: &'a [u16], rows: &'a [&'a [&'a str]], + color: Color, column_spacing: u16, + background_color: Color, } impl<'a> Default for Table<'a> { fn default() -> Table<'a> { Table { block: None, - titles: &[], + header: &[], + header_color: Color::Reset, widths: &[], rows: &[], + color: Color::Reset, column_spacing: 1, + background_color: Color::Reset, } } } @@ -33,8 +39,13 @@ impl<'a> Table<'a> { self } - pub fn titles(&mut self, titles: &'a [&'a str]) -> &mut Table<'a> { - self.titles = titles; + pub fn header(&mut self, header: &'a [&'a str]) -> &mut Table<'a> { + self.header = header; + self + } + + pub fn header_color(&mut self, color: Color) -> &mut Table<'a> { + self.header_color = color; self } @@ -48,14 +59,26 @@ impl<'a> Table<'a> { self } + pub fn color(&mut self, color: Color) -> &mut Table<'a> { + self.color = color; + self + } + pub fn column_spacing(&mut self, spacing: u16) -> &mut Table<'a> { self.column_spacing = spacing; self } + + pub fn background_color(&mut self, color: Color) -> &mut Table<'a> { + self.background_color = color; + self + } } impl<'a> Widget for Table<'a> { fn buffer(&self, area: &Rect, buf: &mut Buffer) { + + // Render block if necessary and get the drawing area let table_area = match self.block { Some(ref b) => { b.buffer(area, buf); @@ -64,9 +87,14 @@ impl<'a> Widget for Table<'a> { None => *area, }; + // Set the background + if self.background_color != Color::Reset { + self.background(&table_area, buf, self.background_color); + } + let mut x = 0; let mut widths = Vec::with_capacity(self.widths.len()); - for (width, title) in self.widths.iter().zip(self.titles.iter()) { + for (width, title) in self.widths.iter().zip(self.header.iter()) { let w = max(title.width() as u16, *width); if x + w < table_area.width { widths.push(w); @@ -78,8 +106,8 @@ impl<'a> Widget for Table<'a> { if y < table_area.bottom() { x = table_area.left(); - for (w, t) in widths.iter().zip(self.titles.iter()) { - buf.set_string(x, y, t, Color::Reset, Color::Reset); + for (w, t) in widths.iter().zip(self.header.iter()) { + buf.set_string(x, y, t, self.header_color, self.background_color); x += *w + self.column_spacing; } } @@ -94,8 +122,8 @@ impl<'a> Widget for Table<'a> { y + i as u16, elt, *w as usize, - Color::Reset, - Color::Reset); + self.color, + self.background_color); x += *w + self.column_spacing; } } diff --git a/src/widgets/tabs.rs b/src/widgets/tabs.rs index db5c66f..493cf78 100644 --- a/src/widgets/tabs.rs +++ b/src/widgets/tabs.rs @@ -10,8 +10,9 @@ pub struct Tabs<'a> { block: Option>, titles: &'a [&'a str], selected: usize, - highlight_color: Color, color: Color, + background_color: Color, + highlight_color: Color, } impl<'a> Default for Tabs<'a> { @@ -20,8 +21,9 @@ impl<'a> Default for Tabs<'a> { block: None, titles: &[], selected: 0, - highlight_color: Color::Reset, color: Color::Reset, + background_color: Color::Reset, + highlight_color: Color::Reset, } } } @@ -47,6 +49,11 @@ impl<'a> Tabs<'a> { self } + pub fn background_color(&mut self, color: Color) -> &mut Tabs<'a> { + self.background_color = color; + self + } + pub fn highlight_color(&mut self, color: Color) -> &mut Tabs<'a> { self.highlight_color = color; self @@ -55,6 +62,7 @@ impl<'a> Tabs<'a> { impl<'a> Widget for Tabs<'a> { fn buffer(&self, area: &Rect, buf: &mut Buffer) { + let tabs_area = match self.block { Some(b) => { b.buffer(area, buf); @@ -62,10 +70,15 @@ impl<'a> Widget for Tabs<'a> { } None => *area, }; + if tabs_area.height < 1 { return; } + if self.background_color != Color::Reset { + self.background(&tabs_area, buf, self.background_color); + } + let mut x = tabs_area.left(); for (title, color) in self.titles.iter().enumerate().map(|(i, t)| if i == self.selected { (t, self.highlight_color) @@ -76,16 +89,16 @@ impl<'a> Widget for Tabs<'a> { if x > tabs_area.right() { break; } else { - buf.set_string(x, tabs_area.top(), title, color, Color::Reset); + buf.set_string(x, tabs_area.top(), title, color, self.background_color); x += title.width() as u16 + 1; - if x > tabs_area.right() { + if x >= tabs_area.right() { break; } else { buf.set_cell(x, tabs_area.top(), line::VERTICAL, - Color::Reset, - Color::Reset); + self.color, + self.background_color); x += 1; } } diff --git a/src/widgets/text.rs b/src/widgets/text.rs index 510bb0b..85072a7 100644 --- a/src/widgets/text.rs +++ b/src/widgets/text.rs @@ -7,8 +7,8 @@ use style::Color; pub struct Text<'a> { block: Option>, - fg: Color, - bg: Color, + color: Color, + background_color: Color, wrapping: bool, text: &'a str, colors: &'a [(u16, u16, u16, Color, Color)], @@ -18,8 +18,8 @@ impl<'a> Default for Text<'a> { fn default() -> Text<'a> { Text { block: None, - fg: Color::Reset, - bg: Color::Reset, + color: Color::Reset, + background_color: Color::Reset, wrapping: false, text: "", colors: &[], @@ -38,13 +38,13 @@ impl<'a> Text<'a> { self } - pub fn bg(&mut self, bg: Color) -> &mut Text<'a> { - self.bg = bg; + pub fn background_color(&mut self, background_color: Color) -> &mut Text<'a> { + self.background_color = background_color; self } - pub fn fg(&mut self, fg: Color) -> &mut Text<'a> { - self.fg = fg; + pub fn color(&mut self, color: Color) -> &mut Text<'a> { + self.color = color; self } @@ -64,17 +64,19 @@ struct Parser<'a> { mark: bool, color_string: String, color: Color, + base_color: Color, escaping: bool, coloring: bool, } impl<'a> Parser<'a> { - fn new(text: &'a str) -> Parser<'a> { + fn new(text: &'a str, base_color: Color) -> Parser<'a> { Parser { text: UnicodeSegmentation::graphemes(text, true).rev().collect::>(), mark: false, color_string: String::from(""), - color: Color::Reset, + color: base_color, + base_color: base_color, escaping: false, coloring: false, } @@ -103,8 +105,8 @@ impl<'a> Parser<'a> { fn reset(&mut self) { self.coloring = false; self.mark = false; - self.color = Color::Reset; - self.color_string = String::from(""); + self.color = self.base_color; + self.color_string.clear(); } } @@ -125,7 +127,7 @@ impl<'a> Iterator for Parser<'a> { self.escaping = false; Some((s, self.color)) } else { - self.color = Color::Reset; + self.color = self.base_color; self.mark = true; self.next() } @@ -162,9 +164,13 @@ impl<'a> Widget for Text<'a> { return; } + if self.background_color != Color::Reset { + self.background(&text_area, buf, self.background_color); + } + let mut x = 0; let mut y = 0; - for (s, c) in Parser::new(self.text) { + for (s, c) in Parser::new(self.text, self.color) { if s == "\n" { x = 0; y += 1; @@ -182,7 +188,11 @@ impl<'a> Widget for Text<'a> { break; } - buf.set_cell(text_area.left() + x, text_area.top() + y, s, c, self.bg); + buf.set_cell(text_area.left() + x, + text_area.top() + y, + s, + c, + self.background_color); x += 1; }