mirror of
https://github.com/fdehau/tui-rs.git
synced 2024-11-12 19:10:45 +00:00
Improve canvas functionalities and fix clippy warnings
This commit is contained in:
parent
25bb360f13
commit
f0979dfeee
@ -98,7 +98,7 @@ impl Terminal {
|
||||
bg = cell.bg;
|
||||
inst += 1;
|
||||
}
|
||||
string.push_str(&format!("{}", cell.symbol));
|
||||
string.push_str(&cell.symbol);
|
||||
inst += 1;
|
||||
}
|
||||
string.push_str(&format!("{}{}", Color::Reset.fg(), Color::Reset.bg()));
|
||||
|
65
src/widgets/canvas/line.rs
Normal file
65
src/widgets/canvas/line.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use super::Shape;
|
||||
use style::Color;
|
||||
|
||||
pub struct Line {
|
||||
pub x1: f64,
|
||||
pub y1: f64,
|
||||
pub x2: f64,
|
||||
pub y2: f64,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
pub struct LineIterator {
|
||||
x: f64,
|
||||
y: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
dir_x: f64,
|
||||
dir_y: f64,
|
||||
current: f64,
|
||||
end: f64,
|
||||
}
|
||||
|
||||
impl Iterator for LineIterator {
|
||||
type Item = (f64, f64);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.current += 1.0;
|
||||
if self.current < self.end + 1.0 {
|
||||
Some((self.x + (self.current * self.dx) / self.end * self.dir_x,
|
||||
self.y + (self.current * self.dy) / self.end * self.dir_y))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Line {
|
||||
type Item = (f64, f64);
|
||||
type IntoIter = LineIterator;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let dx = self.x1.max(self.x2) - self.x1.min(self.x2);
|
||||
let dy = self.y1.max(self.y2) - self.y1.min(self.y2);
|
||||
let dir_x = if self.x1 <= self.x2 { 1.0 } else { -1.0 };
|
||||
let dir_y = if self.y1 <= self.y2 { 1.0 } else { -1.0 };
|
||||
let end = dx.max(dy);
|
||||
LineIterator {
|
||||
x: self.x1,
|
||||
y: self.y1,
|
||||
dx: dx,
|
||||
dy: dy,
|
||||
dir_x: dir_x,
|
||||
dir_y: dir_y,
|
||||
current: 0.0,
|
||||
end: end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shape<'a> for Line {
|
||||
fn color(&self) -> Color {
|
||||
self.color
|
||||
}
|
||||
fn points(&'a self) -> Box<Iterator<Item = (f64, f64)> + 'a> {
|
||||
Box::new(self.into_iter())
|
||||
}
|
||||
}
|
@ -1,3 +1,9 @@
|
||||
mod points;
|
||||
mod line;
|
||||
|
||||
pub use self::points::Points;
|
||||
pub use self::line::Line;
|
||||
|
||||
use style::Color;
|
||||
use buffer::Buffer;
|
||||
use widgets::{Block, Widget};
|
||||
@ -8,37 +14,16 @@ pub const DOTS: [[u16; 2]; 4] =
|
||||
pub const BRAILLE_OFFSET: u16 = 0x2800;
|
||||
pub const BRAILLE_BLANK: char = '⠀';
|
||||
|
||||
pub struct Shape<'a> {
|
||||
data: &'a [(f64, f64)],
|
||||
color: Color,
|
||||
}
|
||||
|
||||
impl<'a> Default for Shape<'a> {
|
||||
fn default() -> Shape<'a> {
|
||||
Shape {
|
||||
data: &[],
|
||||
color: Color::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shape<'a> {
|
||||
pub fn data(mut self, data: &'a [(f64, f64)]) -> Shape<'a> {
|
||||
self.data = data;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn color(mut self, color: Color) -> Shape<'a> {
|
||||
self.color = color;
|
||||
self
|
||||
}
|
||||
pub trait Shape<'a> {
|
||||
fn color(&self) -> Color;
|
||||
fn points(&'a self) -> Box<Iterator<Item = (f64, f64)> + 'a>;
|
||||
}
|
||||
|
||||
pub struct Canvas<'a> {
|
||||
block: Option<Block<'a>>,
|
||||
x_bounds: [f64; 2],
|
||||
y_bounds: [f64; 2],
|
||||
shapes: &'a [Shape<'a>],
|
||||
shapes: &'a [&'a Shape<'a>],
|
||||
}
|
||||
|
||||
impl<'a> Default for Canvas<'a> {
|
||||
@ -65,7 +50,7 @@ impl<'a> Canvas<'a> {
|
||||
self.y_bounds = bounds;
|
||||
self
|
||||
}
|
||||
pub fn shapes(&mut self, shapes: &'a [Shape<'a>]) -> &mut Canvas<'a> {
|
||||
pub fn shapes(&mut self, shapes: &'a [&'a Shape<'a>]) -> &mut Canvas<'a> {
|
||||
self.shapes = shapes;
|
||||
self
|
||||
}
|
||||
@ -80,34 +65,42 @@ impl<'a> Widget for Canvas<'a> {
|
||||
}
|
||||
None => *area,
|
||||
};
|
||||
|
||||
let width = canvas_area.width as usize;
|
||||
let height = canvas_area.height as usize;
|
||||
|
||||
let mut grid: Vec<u16> = vec![BRAILLE_OFFSET; width * height + 1];
|
||||
let mut x_bounds = self.x_bounds.clone();
|
||||
let mut colors: Vec<Color> = vec![Color::Reset; width * height + 1];
|
||||
|
||||
let mut x_bounds = self.x_bounds;
|
||||
x_bounds.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
let mut y_bounds = self.y_bounds.clone();
|
||||
let mut y_bounds = self.y_bounds;
|
||||
y_bounds.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
|
||||
for shape in self.shapes {
|
||||
for &(x, y) in shape.data.iter().filter(|&&(x, y)| {
|
||||
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 /
|
||||
(self.y_bounds[1] - self.y_bounds[0])) as usize;
|
||||
let dx = ((self.x_bounds[1] - x) * canvas_area.width as f64 * 2.0 /
|
||||
(self.x_bounds[1] - self.x_bounds[0])) as usize;
|
||||
grid[dy / 4 * width + dx / 2] |= DOTS[dy % 4][dx % 2];
|
||||
let index = dy / 4 * width + dx / 2;
|
||||
grid[index] |= DOTS[dy % 4][dx % 2];
|
||||
colors[index] = shape.color();
|
||||
}
|
||||
let string = String::from_utf16(&grid).unwrap();
|
||||
for (i, ch) in string.chars().enumerate() {
|
||||
if ch != BRAILLE_BLANK {
|
||||
let (x, y) = (i % width, i / width);
|
||||
buf.update_cell(x as u16 + canvas_area.left(), y as u16 + area.top(), |c| {
|
||||
c.symbol.clear();
|
||||
c.symbol.push(ch);
|
||||
c.fg = shape.color;
|
||||
c.bg = Color::Reset;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
buf.update_cell(x as u16 + canvas_area.left(), y as u16 + area.top(), |c| {
|
||||
c.symbol.clear();
|
||||
c.symbol.push(ch);
|
||||
c.fg = color;
|
||||
c.bg = Color::Reset;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
54
src/widgets/canvas/points.rs
Normal file
54
src/widgets/canvas/points.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use super::Shape;
|
||||
use style::Color;
|
||||
|
||||
pub struct Points<'a> {
|
||||
pub coords: &'a [(f64, f64)],
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
impl<'a> Shape<'a> for Points<'a> {
|
||||
fn color(&self) -> Color {
|
||||
self.color
|
||||
}
|
||||
fn points(&'a self) -> Box<Iterator<Item = (f64, f64)> + 'a> {
|
||||
Box::new(self.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for Points<'a> {
|
||||
fn default() -> Points<'a> {
|
||||
Points {
|
||||
coords: &[],
|
||||
color: Color::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Points<'a> {
|
||||
type Item = (f64, f64);
|
||||
type IntoIter = PointsIterator<'a>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
PointsIterator {
|
||||
coords: self.coords,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PointsIterator<'a> {
|
||||
coords: &'a [(f64, f64)],
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PointsIterator<'a> {
|
||||
type Item = (f64, f64);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let point = if self.index < self.coords.len() {
|
||||
Some(self.coords[self.index])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.index += 1;
|
||||
point
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ use std::cmp::max;
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use widgets::{Widget, Block, Canvas, Shape};
|
||||
use widgets::{Widget, Block, Canvas, Points};
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::Color;
|
||||
@ -325,7 +325,10 @@ impl<'a> Widget for Chart<'a> {
|
||||
Canvas::default()
|
||||
.x_bounds(self.x_axis.bounds)
|
||||
.y_bounds(self.y_axis.bounds)
|
||||
.shapes(&[Shape::default().data(dataset.data).color(dataset.color)])
|
||||
.shapes(&[&Points {
|
||||
coords: dataset.data,
|
||||
color: dataset.color,
|
||||
}])
|
||||
.buffer(&graph_area, buf);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use widgets::{Widget, Block, Canvas, Shape};
|
||||
use widgets::{Widget, Block, Canvas, Points};
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::Color;
|
||||
|
||||
pub struct Map<'a> {
|
||||
block: Option<Block<'a>>,
|
||||
@ -32,7 +33,10 @@ impl<'a> Widget for Map<'a> {
|
||||
Canvas::default()
|
||||
.x_bounds([180.0, -180.0])
|
||||
.y_bounds([-90.0, 90.0])
|
||||
.shapes(&[Shape::default().data(&WORLD)])
|
||||
.shapes(&[&Points {
|
||||
coords: &WORLD,
|
||||
color: Color::Reset,
|
||||
}])
|
||||
.buffer(&map_area, buf);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub use self::sparkline::Sparkline;
|
||||
pub use self::chart::{Chart, Axis, Dataset, Marker};
|
||||
pub use self::barchart::BarChart;
|
||||
pub use self::tabs::Tabs;
|
||||
pub use self::canvas::{Canvas, Shape};
|
||||
pub use self::canvas::{Canvas, Shape, Line, Points};
|
||||
pub use self::map::Map;
|
||||
|
||||
use buffer::Buffer;
|
||||
|
Loading…
Reference in New Issue
Block a user