tui_temp_fork/widgets/
sparkline.rs1use std::cmp::min;
2
3use crate::buffer::Buffer;
4use crate::layout::Rect;
5use crate::style::Style;
6use crate::symbols::bar;
7use crate::widgets::{Block, Widget};
8
9pub struct Sparkline<'a> {
25 block: Option<Block<'a>>,
27 style: Style,
29 data: &'a [u64],
31 max: Option<u64>,
34}
35
36impl<'a> Default for Sparkline<'a> {
37 fn default() -> Sparkline<'a> {
38 Sparkline {
39 block: None,
40 style: Default::default(),
41 data: &[],
42 max: None,
43 }
44 }
45}
46
47impl<'a> Sparkline<'a> {
48 pub fn block(mut self, block: Block<'a>) -> Sparkline<'a> {
49 self.block = Some(block);
50 self
51 }
52
53 pub fn style(mut self, style: Style) -> Sparkline<'a> {
54 self.style = style;
55 self
56 }
57
58 pub fn data(mut self, data: &'a [u64]) -> Sparkline<'a> {
59 self.data = data;
60 self
61 }
62
63 pub fn max(mut self, max: u64) -> Sparkline<'a> {
64 self.max = Some(max);
65 self
66 }
67}
68
69impl<'a> Widget for Sparkline<'a> {
70 fn draw(&mut self, area: Rect, buf: &mut Buffer) {
71 let spark_area = match self.block {
72 Some(ref mut b) => {
73 b.draw(area, buf);
74 b.inner(area)
75 }
76 None => area,
77 };
78
79 if spark_area.height < 1 {
80 return;
81 }
82
83 let max = match self.max {
84 Some(v) => v,
85 None => *self.data.iter().max().unwrap_or(&1u64),
86 };
87 let max_index = min(spark_area.width as usize, self.data.len());
88 let mut data = self
89 .data
90 .iter()
91 .take(max_index)
92 .map(|e| {
93 if max != 0 {
94 e * u64::from(spark_area.height) * 8 / max
95 } else {
96 0
97 }
98 })
99 .collect::<Vec<u64>>();
100 for j in (0..spark_area.height).rev() {
101 for (i, d) in data.iter_mut().enumerate() {
102 let symbol = match *d {
103 0 => " ",
104 1 => bar::ONE_EIGHTH,
105 2 => bar::ONE_QUARTER,
106 3 => bar::THREE_EIGHTHS,
107 4 => bar::HALF,
108 5 => bar::FIVE_EIGHTHS,
109 6 => bar::THREE_QUARTERS,
110 7 => bar::SEVEN_EIGHTHS,
111 _ => bar::FULL,
112 };
113 buf.get_mut(spark_area.left() + i as u16, spark_area.top() + j)
114 .set_symbol(symbol)
115 .set_fg(self.style.fg)
116 .set_bg(self.style.bg);
117
118 if *d > 8 {
119 *d -= 8;
120 } else {
121 *d = 0;
122 }
123 }
124 }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn it_does_not_panic_if_max_is_zero() {
134 let mut widget = Sparkline::default().data(&[0, 0, 0]);
135 let area = Rect::new(0, 0, 3, 1);
136 let mut buffer = Buffer::empty(area);
137 widget.draw(area, &mut buffer);
138 }
139
140 #[test]
141 fn it_does_not_panic_if_max_is_set_to_zero() {
142 let mut widget = Sparkline::default().data(&[0, 1, 2]).max(0);
143 let area = Rect::new(0, 0, 3, 1);
144 let mut buffer = Buffer::empty(area);
145 widget.draw(area, &mut buffer);
146 }
147}