mirror of
https://github.com/ratatui/ratatui.git
synced 2025-10-02 07:21:24 +00:00
Update chart widget and fix colors in all widgets
This commit is contained in:
parent
15c3471f0b
commit
7a427c06d4
@ -81,6 +81,7 @@ struct App {
|
|||||||
data: Vec<u64>,
|
data: Vec<u64>,
|
||||||
data2: Vec<(f64, f64)>,
|
data2: Vec<(f64, f64)>,
|
||||||
data3: Vec<(f64, f64)>,
|
data3: Vec<(f64, f64)>,
|
||||||
|
window: [f64; 2],
|
||||||
colors: [Color; 2],
|
colors: [Color; 2],
|
||||||
color_index: usize,
|
color_index: usize,
|
||||||
}
|
}
|
||||||
@ -115,15 +116,21 @@ fn main() {
|
|||||||
selected: 0,
|
selected: 0,
|
||||||
show_chart: true,
|
show_chart: true,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
data: rand_signal.clone().take(100).collect(),
|
data: rand_signal.clone().take(200).collect(),
|
||||||
data2: sin_signal.clone().take(100).collect(),
|
data2: sin_signal.clone().take(20).collect(),
|
||||||
data3: sin_signal2.clone().take(100).collect(),
|
data3: sin_signal2.clone().take(20).collect(),
|
||||||
|
window: [0.0, 20.0],
|
||||||
colors: [Color::Magenta, Color::Red],
|
colors: [Color::Magenta, Color::Red],
|
||||||
color_index: 0,
|
color_index: 0,
|
||||||
};
|
};
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let input_tx = tx.clone();
|
let input_tx = tx.clone();
|
||||||
|
|
||||||
|
for i in 0..20 {
|
||||||
|
sin_signal.next();
|
||||||
|
sin_signal2.next();
|
||||||
|
}
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
for c in stdin.keys() {
|
for c in stdin.keys() {
|
||||||
@ -139,7 +146,7 @@ fn main() {
|
|||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
loop {
|
loop {
|
||||||
tx.send(Event::Tick).unwrap();
|
tx.send(Event::Tick).unwrap();
|
||||||
thread::sleep(time::Duration::from_millis(1000));
|
thread::sleep(time::Duration::from_millis(200));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -184,6 +191,8 @@ fn main() {
|
|||||||
app.data2.push(sin_signal.next().unwrap());
|
app.data2.push(sin_signal.next().unwrap());
|
||||||
app.data3.remove(0);
|
app.data3.remove(0);
|
||||||
app.data3.push(sin_signal2.next().unwrap());
|
app.data3.push(sin_signal2.next().unwrap());
|
||||||
|
app.window[0] += 1.0;
|
||||||
|
app.window[1] += 1.0;
|
||||||
app.selected += 1;
|
app.selected += 1;
|
||||||
if app.selected >= app.items.len() {
|
if app.selected >= app.items.len() {
|
||||||
app.selected = 0;
|
app.selected = 0;
|
||||||
@ -202,15 +211,9 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||||||
|
|
||||||
let size = Terminal::size().unwrap();
|
let size = Terminal::size().unwrap();
|
||||||
|
|
||||||
Block::default()
|
|
||||||
.borders(border::ALL)
|
|
||||||
.title(&app.name)
|
|
||||||
.render(&size, t);
|
|
||||||
|
|
||||||
Group::default()
|
Group::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.alignment(Alignment::Left)
|
.alignment(Alignment::Left)
|
||||||
.margin(1)
|
|
||||||
.chunks(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)])
|
.chunks(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)])
|
||||||
.render(t, &size, |t, chunks| {
|
.render(t, &size, |t, chunks| {
|
||||||
Block::default().borders(border::ALL).title("Graphs").render(&chunks[0], t);
|
Block::default().borders(border::ALL).title("Graphs").render(&chunks[0], t);
|
||||||
@ -222,7 +225,7 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||||||
.render(t, &chunks[0], |t, chunks| {
|
.render(t, &chunks[0], |t, chunks| {
|
||||||
Gauge::default()
|
Gauge::default()
|
||||||
.block(Block::default().title("Gauge:"))
|
.block(Block::default().title("Gauge:"))
|
||||||
.bg(Color::Yellow)
|
.bg(Color::Magenta)
|
||||||
.percent(app.progress)
|
.percent(app.progress)
|
||||||
.render(&chunks[0], t);
|
.render(&chunks[0], t);
|
||||||
Sparkline::default()
|
Sparkline::default()
|
||||||
@ -246,11 +249,19 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||||||
.render(&chunks[0], t);
|
.render(&chunks[0], t);
|
||||||
if app.show_chart {
|
if app.show_chart {
|
||||||
Chart::default()
|
Chart::default()
|
||||||
.block(Block::default()
|
.block(Block::default().title("Chart"))
|
||||||
.borders(border::ALL)
|
.x_axis(Axis::default()
|
||||||
.title("Chart"))
|
.title("X Axis")
|
||||||
.x_axis(Axis::default().title("X").bounds([0.0, 100.0]))
|
.color(Color::Gray)
|
||||||
.y_axis(Axis::default().title("Y").bounds([0.0, 40.0]))
|
.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")
|
||||||
|
.color(Color::Gray)
|
||||||
|
.bounds([0.0, 40.0])
|
||||||
|
.labels(&["0", "20", "40"]))
|
||||||
.datasets(&[Dataset::default().color(Color::Cyan).data(&app.data2),
|
.datasets(&[Dataset::default().color(Color::Cyan).data(&app.data2),
|
||||||
Dataset::default().color(Color::Yellow).data(&app.data3)])
|
Dataset::default().color(Color::Yellow).data(&app.data3)])
|
||||||
.render(&chunks[1], t);
|
.render(&chunks[1], t);
|
||||||
@ -259,7 +270,7 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||||||
Text::default()
|
Text::default()
|
||||||
.block(Block::default().borders(border::ALL).title("Footer"))
|
.block(Block::default().borders(border::ALL).title("Footer"))
|
||||||
.fg(app.colors[app.color_index])
|
.fg(app.colors[app.color_index])
|
||||||
.text("This żółw is a footer")
|
.text("日本国 UTF-8 charaters")
|
||||||
.render(&chunks[2], t);
|
.render(&chunks[2], t);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ impl<'a> Default for Cell<'a> {
|
|||||||
fn default() -> Cell<'a> {
|
fn default() -> Cell<'a> {
|
||||||
Cell {
|
Cell {
|
||||||
symbol: "",
|
symbol: "",
|
||||||
fg: Color::White,
|
fg: Color::Reset,
|
||||||
bg: Color::Black,
|
bg: Color::Reset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,11 +130,18 @@ impl<'a> Buffer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_cell<F>(&mut self, x: u16, y: u16, f: F)
|
pub fn update_colors(&mut self, x: u16, y: u16, fg: Color, bg: Color) {
|
||||||
where F: Fn(&mut Cell)
|
|
||||||
{
|
|
||||||
if let Some(i) = self.index_of(x, y) {
|
if let Some(i) = self.index_of(x, y) {
|
||||||
f(&mut self.content[i]);
|
self.content[i].fg = fg;
|
||||||
|
self.content[i].bg = bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_cell(&mut self, x: u16, y: u16, symbol: &'a str, fg: Color, bg: Color) {
|
||||||
|
if let Some(i) = self.index_of(x, y) {
|
||||||
|
self.content[i].symbol = symbol;
|
||||||
|
self.content[i].fg = fg;
|
||||||
|
self.content[i].bg = bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use termion;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
pub enum Color {
|
pub enum Color {
|
||||||
|
Reset,
|
||||||
Black,
|
Black,
|
||||||
Red,
|
Red,
|
||||||
Green,
|
Green,
|
||||||
@ -22,6 +23,7 @@ pub enum Color {
|
|||||||
impl Color {
|
impl Color {
|
||||||
pub fn fg(&self) -> String {
|
pub fn fg(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
|
Color::Reset => format!("{}", termion::color::Fg(termion::color::Reset)),
|
||||||
Color::Black => format!("{}", termion::color::Fg(termion::color::Black)),
|
Color::Black => format!("{}", termion::color::Fg(termion::color::Black)),
|
||||||
Color::Red => format!("{}", termion::color::Fg(termion::color::Red)),
|
Color::Red => format!("{}", termion::color::Fg(termion::color::Red)),
|
||||||
Color::Green => format!("{}", termion::color::Fg(termion::color::Green)),
|
Color::Green => format!("{}", termion::color::Fg(termion::color::Green)),
|
||||||
@ -41,6 +43,7 @@ impl Color {
|
|||||||
}
|
}
|
||||||
pub fn bg(&self) -> String {
|
pub fn bg(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
|
Color::Reset => format!("{}", termion::color::Bg(termion::color::Reset)),
|
||||||
Color::Black => format!("{}", termion::color::Bg(termion::color::Black)),
|
Color::Black => format!("{}", termion::color::Bg(termion::color::Black)),
|
||||||
Color::Red => format!("{}", termion::color::Bg(termion::color::Red)),
|
Color::Red => format!("{}", termion::color::Bg(termion::color::Red)),
|
||||||
Color::Green => format!("{}", termion::color::Bg(termion::color::Green)),
|
Color::Green => format!("{}", termion::color::Bg(termion::color::Green)),
|
||||||
|
@ -34,3 +34,4 @@ pub mod line {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const DOT: &'static str = "•";
|
pub const DOT: &'static str = "•";
|
||||||
|
pub const BLACK_CIRCLE: &'static str = "●";
|
||||||
|
@ -8,22 +8,20 @@ use symbols::line;
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Block<'a> {
|
pub struct Block<'a> {
|
||||||
title: Option<&'a str>,
|
title: Option<&'a str>,
|
||||||
title_fg: Color,
|
title_color: Color,
|
||||||
title_bg: Color,
|
|
||||||
borders: border::Flags,
|
borders: border::Flags,
|
||||||
border_fg: Color,
|
border_color: Color,
|
||||||
border_bg: Color,
|
bg: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Block<'a> {
|
impl<'a> Default for Block<'a> {
|
||||||
fn default() -> Block<'a> {
|
fn default() -> Block<'a> {
|
||||||
Block {
|
Block {
|
||||||
title: None,
|
title: None,
|
||||||
title_fg: Color::White,
|
title_color: Color::Reset,
|
||||||
title_bg: Color::Black,
|
|
||||||
borders: border::NONE,
|
borders: border::NONE,
|
||||||
border_fg: Color::White,
|
border_color: Color::Reset,
|
||||||
border_bg: Color::Black,
|
bg: Color::Reset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,27 +32,21 @@ impl<'a> Block<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title_fg(mut self, color: Color) -> Block<'a> {
|
pub fn title_color(mut self, color: Color) -> Block<'a> {
|
||||||
self.title_fg = color;
|
self.title_color = color;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title_bg(mut self, color: Color) -> Block<'a> {
|
pub fn border_color(mut self, color: Color) -> Block<'a> {
|
||||||
self.title_bg = color;
|
self.border_color = color;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn border_fg(mut self, color: Color) -> Block<'a> {
|
pub fn bg(mut self, color: Color) -> Block<'a> {
|
||||||
self.border_fg = color;
|
self.bg = color;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn border_bg(mut self, color: Color) -> Block<'a> {
|
|
||||||
self.border_bg = color;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn borders(mut self, flag: border::Flags) -> Block<'a> {
|
pub fn borders(mut self, flag: border::Flags) -> Block<'a> {
|
||||||
self.borders = flag;
|
self.borders = flag;
|
||||||
self
|
self
|
||||||
@ -95,40 +87,24 @@ impl<'a> Widget<'a> for Block<'a> {
|
|||||||
// Sides
|
// Sides
|
||||||
if self.borders.intersects(border::LEFT) {
|
if self.borders.intersects(border::LEFT) {
|
||||||
for y in 0..area.height {
|
for y in 0..area.height {
|
||||||
buf.update_cell(0, y, |c| {
|
buf.update_cell(0, y, line::VERTICAL, self.border_color, self.bg);
|
||||||
c.symbol = line::VERTICAL;
|
|
||||||
c.fg = self.border_fg;
|
|
||||||
c.bg = self.border_bg;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.borders.intersects(border::TOP) {
|
if self.borders.intersects(border::TOP) {
|
||||||
for x in 0..area.width {
|
for x in 0..area.width {
|
||||||
buf.update_cell(x, 0, |c| {
|
buf.update_cell(x, 0, line::HORIZONTAL, self.border_color, self.bg);
|
||||||
c.symbol = line::HORIZONTAL;
|
|
||||||
c.fg = self.border_fg;
|
|
||||||
c.bg = self.border_bg;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.borders.intersects(border::RIGHT) {
|
if self.borders.intersects(border::RIGHT) {
|
||||||
let x = area.width - 1;
|
let x = area.width - 1;
|
||||||
for y in 0..area.height {
|
for y in 0..area.height {
|
||||||
buf.update_cell(x, y, |c| {
|
buf.update_cell(x, y, line::VERTICAL, self.border_color, self.bg);
|
||||||
c.symbol = line::VERTICAL;
|
|
||||||
c.fg = self.border_fg;
|
|
||||||
c.bg = self.border_bg;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.borders.intersects(border::BOTTOM) {
|
if self.borders.intersects(border::BOTTOM) {
|
||||||
let y = area.height - 1;
|
let y = area.height - 1;
|
||||||
for x in 0..area.width {
|
for x in 0..area.width {
|
||||||
buf.update_cell(x, y, |c| {
|
buf.update_cell(x, y, line::HORIZONTAL, self.border_color, self.bg);
|
||||||
c.symbol = line::HORIZONTAL;
|
|
||||||
c.fg = self.border_fg;
|
|
||||||
c.bg = self.border_bg;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +127,7 @@ impl<'a> Widget<'a> for Block<'a> {
|
|||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
buf.set_string(margin_x, 0, title, self.title_fg, self.title_bg);
|
buf.set_string(margin_x, 0, title, self.title_color, self.bg);
|
||||||
}
|
}
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::cmp::{min, max};
|
use std::cmp::max;
|
||||||
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
@ -10,16 +10,22 @@ use symbols;
|
|||||||
|
|
||||||
pub struct Axis<'a> {
|
pub struct Axis<'a> {
|
||||||
title: Option<&'a str>,
|
title: Option<&'a str>,
|
||||||
|
title_color: Color,
|
||||||
bounds: [f64; 2],
|
bounds: [f64; 2],
|
||||||
labels: Option<&'a [&'a str]>,
|
labels: Option<&'a [&'a str]>,
|
||||||
|
labels_color: Color,
|
||||||
|
color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Axis<'a> {
|
impl<'a> Default for Axis<'a> {
|
||||||
fn default() -> Axis<'a> {
|
fn default() -> Axis<'a> {
|
||||||
Axis {
|
Axis {
|
||||||
title: None,
|
title: None,
|
||||||
|
title_color: Color::Reset,
|
||||||
bounds: [0.0, 0.0],
|
bounds: [0.0, 0.0],
|
||||||
labels: None,
|
labels: None,
|
||||||
|
labels_color: Color::Reset,
|
||||||
|
color: Color::Reset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,6 +36,11 @@ impl<'a> Axis<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn title_color(mut self, color: Color) -> Axis<'a> {
|
||||||
|
self.title_color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bounds(mut self, bounds: [f64; 2]) -> Axis<'a> {
|
pub fn bounds(mut self, bounds: [f64; 2]) -> Axis<'a> {
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
self
|
self
|
||||||
@ -40,18 +51,14 @@ impl<'a> Axis<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title_width(&self) -> u16 {
|
pub fn labels_color(mut self, color: Color) -> Axis<'a> {
|
||||||
match self.title {
|
self.labels_color = color;
|
||||||
Some(title) => title.width() as u16,
|
self
|
||||||
None => 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_label_width(&self) -> u16 {
|
pub fn color(mut self, color: Color) -> Axis<'a> {
|
||||||
match self.labels {
|
self.color = color;
|
||||||
Some(labels) => labels.iter().fold(0, |acc, l| max(l.width(), acc)) as u16,
|
self
|
||||||
None => 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +71,7 @@ impl<'a> Default for Dataset<'a> {
|
|||||||
fn default() -> Dataset<'a> {
|
fn default() -> Dataset<'a> {
|
||||||
Dataset {
|
Dataset {
|
||||||
data: &[],
|
data: &[],
|
||||||
color: Color::White,
|
color: Color::Reset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,12 +102,36 @@ impl<'a> Default for Chart<'a> {
|
|||||||
block: None,
|
block: None,
|
||||||
x_axis: Axis::default(),
|
x_axis: Axis::default(),
|
||||||
y_axis: Axis::default(),
|
y_axis: Axis::default(),
|
||||||
bg: Color::Black,
|
bg: Color::Reset,
|
||||||
datasets: &[],
|
datasets: &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ChartLayout {
|
||||||
|
legend_x: Option<(u16, u16)>,
|
||||||
|
legend_y: Option<(u16, u16)>,
|
||||||
|
label_x: Option<u16>,
|
||||||
|
label_y: Option<u16>,
|
||||||
|
axis_x: Option<u16>,
|
||||||
|
axis_y: Option<u16>,
|
||||||
|
graph_area: Rect,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ChartLayout {
|
||||||
|
fn default() -> ChartLayout {
|
||||||
|
ChartLayout {
|
||||||
|
legend_x: None,
|
||||||
|
legend_y: None,
|
||||||
|
label_x: None,
|
||||||
|
label_y: None,
|
||||||
|
axis_x: None,
|
||||||
|
axis_y: None,
|
||||||
|
graph_area: Rect::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Chart<'a> {
|
impl<'a> Chart<'a> {
|
||||||
pub fn block(&'a mut self, block: Block<'a>) -> &mut Chart<'a> {
|
pub fn block(&'a mut self, block: Block<'a>) -> &mut Chart<'a> {
|
||||||
self.block = Some(block);
|
self.block = Some(block);
|
||||||
@ -126,6 +157,54 @@ impl<'a> Chart<'a> {
|
|||||||
self.datasets = datasets;
|
self.datasets = datasets;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn layout(&self, inner: &Rect, outer: &Rect) -> ChartLayout {
|
||||||
|
let mut layout = ChartLayout::default();
|
||||||
|
let mut x = inner.x - outer.x;
|
||||||
|
let mut y = inner.height - 1 + (inner.y - outer.y);
|
||||||
|
|
||||||
|
if self.x_axis.labels.is_some() && y > 1 {
|
||||||
|
layout.label_x = Some(y);
|
||||||
|
y -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(labels) = self.y_axis.labels {
|
||||||
|
let max_width = labels.iter().fold(0, |acc, l| max(l.width(), acc)) as u16;
|
||||||
|
if x + max_width < inner.width {
|
||||||
|
layout.label_y = Some(x);
|
||||||
|
x += max_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.x_axis.labels.is_some() && y > 1 {
|
||||||
|
layout.axis_x = Some(y);
|
||||||
|
y -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.y_axis.labels.is_some() && x + 1 < inner.width {
|
||||||
|
layout.axis_y = Some(x);
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if x < inner.width && y > 1 {
|
||||||
|
layout.graph_area = Rect::new(outer.x + x, inner.y, inner.width - x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(title) = self.x_axis.title {
|
||||||
|
let w = title.width() as u16;
|
||||||
|
if w < layout.graph_area.width && layout.graph_area.height > 2 {
|
||||||
|
layout.legend_x = Some((x + layout.graph_area.width - w, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(title) = self.y_axis.title {
|
||||||
|
let w = title.width() as u16;
|
||||||
|
if w + 1 < layout.graph_area.width && layout.graph_area.height > 2 {
|
||||||
|
layout.legend_y = Some((x + 1, inner.y - outer.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget<'a> for Chart<'a> {
|
impl<'a> Widget<'a> for Chart<'a> {
|
||||||
@ -135,24 +214,93 @@ impl<'a> Widget<'a> for Chart<'a> {
|
|||||||
None => (Buffer::empty(*area), *area),
|
None => (Buffer::empty(*area), *area),
|
||||||
};
|
};
|
||||||
|
|
||||||
let margin_x = chart_area.x - area.x;
|
let layout = self.layout(&chart_area, &area);
|
||||||
let margin_y = chart_area.y - area.y;
|
let width = layout.graph_area.width;
|
||||||
|
let height = layout.graph_area.height;
|
||||||
|
let margin_x = layout.graph_area.x - area.x;
|
||||||
|
let margin_y = layout.graph_area.y - area.y;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(y) = layout.label_x {
|
||||||
|
let labels = self.x_axis.labels.unwrap();
|
||||||
|
let total_width = labels.iter().fold(0, |acc, l| l.width() + acc) as u16;
|
||||||
|
let labels_len = labels.len() as u16;
|
||||||
|
if total_width < width && labels_len > 1 {
|
||||||
|
for (i, label) in labels.iter().enumerate() {
|
||||||
|
buf.set_string(margin_x + i as u16 * (width - 1) / (labels_len - 1) -
|
||||||
|
label.width() as u16,
|
||||||
|
y,
|
||||||
|
label,
|
||||||
|
self.x_axis.labels_color,
|
||||||
|
self.bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x) = layout.label_y {
|
||||||
|
let labels = self.y_axis.labels.unwrap();
|
||||||
|
let labels_len = labels.len() as u16;
|
||||||
|
if labels_len > 1 {
|
||||||
|
for (i, label) in labels.iter().rev().enumerate() {
|
||||||
|
buf.set_string(x,
|
||||||
|
margin_y + i as u16 * (height - 1) / (labels_len - 1),
|
||||||
|
label,
|
||||||
|
self.y_axis.labels_color,
|
||||||
|
self.bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(y) = layout.axis_x {
|
||||||
|
for x in 0..width {
|
||||||
|
buf.update_cell(margin_x + x,
|
||||||
|
y,
|
||||||
|
symbols::line::HORIZONTAL,
|
||||||
|
self.x_axis.color,
|
||||||
|
self.bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x) = layout.axis_y {
|
||||||
|
for y in 0..height {
|
||||||
|
buf.update_cell(x,
|
||||||
|
margin_y + y,
|
||||||
|
symbols::line::VERTICAL,
|
||||||
|
self.y_axis.color,
|
||||||
|
self.bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(y) = layout.axis_x {
|
||||||
|
if let Some(x) = layout.axis_y {
|
||||||
|
buf.update_cell(x, y, symbols::line::BOTTOM_LEFT, self.x_axis.color, self.bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for dataset in self.datasets {
|
for dataset in self.datasets {
|
||||||
for &(x, y) in dataset.data.iter() {
|
for &(x, y) in dataset.data.iter() {
|
||||||
if x <= self.x_axis.bounds[0] || x > self.x_axis.bounds[1] ||
|
if x < self.x_axis.bounds[0] || x > self.x_axis.bounds[1] ||
|
||||||
y <= self.y_axis.bounds[0] || y > self.y_axis.bounds[1] {
|
y < self.y_axis.bounds[0] || y > self.y_axis.bounds[1] {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let dy = (self.y_axis.bounds[1] - y) * (chart_area.height - 1) as f64 /
|
let dy = (self.y_axis.bounds[1] - y) * height as f64 /
|
||||||
(self.y_axis.bounds[1] - self.y_axis.bounds[0]);
|
(self.y_axis.bounds[1] - self.y_axis.bounds[0]);
|
||||||
let dx = (self.x_axis.bounds[1] - x) * (chart_area.width - 1) as f64 /
|
let dx = (self.x_axis.bounds[1] - x) * width as f64 /
|
||||||
(self.x_axis.bounds[1] - self.x_axis.bounds[0]);
|
(self.x_axis.bounds[1] - self.x_axis.bounds[0]);
|
||||||
buf.update_cell(dx as u16 + margin_x, dy as u16 + margin_y, |c| {
|
buf.update_cell(dx as u16 + margin_x,
|
||||||
c.symbol = symbols::DOT;
|
dy as u16 + margin_y,
|
||||||
c.fg = dataset.color;
|
symbols::BLACK_CIRCLE,
|
||||||
c.bg = self.bg;
|
dataset.color,
|
||||||
})
|
self.bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf
|
buf
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::cmp::{max, min};
|
||||||
|
|
||||||
use widgets::{Widget, Block};
|
use widgets::{Widget, Block};
|
||||||
use buffer::Buffer;
|
use buffer::Buffer;
|
||||||
use style::Color;
|
use style::Color;
|
||||||
@ -31,8 +33,8 @@ impl<'a> Default for Gauge<'a> {
|
|||||||
block: None,
|
block: None,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
percent_string: String::from("0%"),
|
percent_string: String::from("0%"),
|
||||||
bg: Color::White,
|
bg: Color::Reset,
|
||||||
fg: Color::Black,
|
fg: Color::Reset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,18 +75,16 @@ impl<'a> Widget<'a> for Gauge<'a> {
|
|||||||
let margin_y = gauge_area.y - area.y;
|
let margin_y = gauge_area.y - area.y;
|
||||||
// Gauge
|
// Gauge
|
||||||
let width = (gauge_area.width * self.percent) / 100;
|
let width = (gauge_area.width * self.percent) / 100;
|
||||||
|
for i in 0..width {
|
||||||
|
buf.update_cell(margin_x + i, margin_y, " ", self.fg, self.bg);
|
||||||
|
}
|
||||||
// Label
|
// Label
|
||||||
let len = self.percent_string.len() as u16;
|
let len = self.percent_string.len() as u16;
|
||||||
let middle = gauge_area.width / 2 - len / 2;
|
let middle = gauge_area.width / 2 - len / 2;
|
||||||
buf.set_string(middle, margin_y, &self.percent_string, self.bg, self.fg);
|
buf.set_string(middle, margin_y, &self.percent_string, self.bg, self.fg);
|
||||||
for i in 0..width {
|
let bound = max(middle, min(middle + len, width));
|
||||||
buf.update_cell(margin_x + i, margin_y, |c| {
|
for i in middle..bound {
|
||||||
if c.symbol == "" {
|
buf.update_colors(margin_x + i, margin_y, self.fg, self.bg);
|
||||||
c.symbol = " "
|
|
||||||
};
|
|
||||||
c.fg = self.fg;
|
|
||||||
c.bg = self.bg;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf
|
buf
|
||||||
|
@ -18,8 +18,8 @@ impl<'a> Default for Sparkline<'a> {
|
|||||||
fn default() -> Sparkline<'a> {
|
fn default() -> Sparkline<'a> {
|
||||||
Sparkline {
|
Sparkline {
|
||||||
block: None,
|
block: None,
|
||||||
fg: Color::White,
|
fg: Color::Reset,
|
||||||
bg: Color::Black,
|
bg: Color::Reset,
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
max: None,
|
max: None,
|
||||||
}
|
}
|
||||||
@ -76,8 +76,7 @@ impl<'a> Widget<'a> for Sparkline<'a> {
|
|||||||
.collect::<Vec<u64>>();
|
.collect::<Vec<u64>>();
|
||||||
for j in (0..spark_area.height).rev() {
|
for j in (0..spark_area.height).rev() {
|
||||||
for (i, d) in data.iter_mut().take(max_index).enumerate() {
|
for (i, d) in data.iter_mut().take(max_index).enumerate() {
|
||||||
buf.update_cell(margin_x + i as u16, margin_y + j, |c| {
|
let symbol = match *d {
|
||||||
c.symbol = match *d {
|
|
||||||
0 => " ",
|
0 => " ",
|
||||||
1 => bar::ONE_EIGHTH,
|
1 => bar::ONE_EIGHTH,
|
||||||
2 => bar::ONE_QUATER,
|
2 => bar::ONE_QUATER,
|
||||||
@ -88,9 +87,8 @@ impl<'a> Widget<'a> for Sparkline<'a> {
|
|||||||
7 => bar::SEVEN_EIGHTHS,
|
7 => bar::SEVEN_EIGHTHS,
|
||||||
_ => bar::FULL,
|
_ => bar::FULL,
|
||||||
};
|
};
|
||||||
c.fg = self.fg;
|
buf.update_cell(margin_x + i as u16, margin_y + j, symbol, self.fg, self.bg);
|
||||||
c.bg = self.bg;
|
|
||||||
});
|
|
||||||
if *d > 8 {
|
if *d > 8 {
|
||||||
*d -= 8;
|
*d -= 8;
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,8 +17,8 @@ impl<'a> Default for Text<'a> {
|
|||||||
fn default() -> Text<'a> {
|
fn default() -> Text<'a> {
|
||||||
Text {
|
Text {
|
||||||
block: None,
|
block: None,
|
||||||
fg: Color::White,
|
fg: Color::Reset,
|
||||||
bg: Color::Black,
|
bg: Color::Reset,
|
||||||
text: "",
|
text: "",
|
||||||
colors: &[],
|
colors: &[],
|
||||||
}
|
}
|
||||||
@ -67,10 +67,8 @@ impl<'a> Widget<'a> for Text<'a> {
|
|||||||
}
|
}
|
||||||
for &(x, y, width, fg, bg) in self.colors {
|
for &(x, y, width, fg, bg) in self.colors {
|
||||||
for i in 0..width {
|
for i in 0..width {
|
||||||
buf.update_cell(x + i, y + margin_y, |c| {
|
buf.set_fg(x + i, y + margin_y, fg);
|
||||||
c.fg = fg;
|
buf.set_bg(x + i, y + margin_y, fg);
|
||||||
c.bg = bg;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf
|
buf
|
||||||
|
Loading…
x
Reference in New Issue
Block a user