tui_realm_stdlib/components/
sparkline.rs1use tuirealm::command::{Cmd, CmdResult};
6use tuirealm::props::{
7 Alignment, AttrValue, Attribute, Borders, Color, PropPayload, PropValue, Props, Style,
8};
9use tuirealm::ratatui::{layout::Rect, widgets::Sparkline as TuiSparkline};
10use tuirealm::{Frame, MockComponent, State};
11
12#[derive(Default)]
18#[must_use]
19pub struct Sparkline {
20 props: Props,
21}
22
23impl Sparkline {
24 pub fn foreground(mut self, fg: Color) -> Self {
25 self.attr(Attribute::Foreground, AttrValue::Color(fg));
26 self
27 }
28
29 pub fn background(mut self, bg: Color) -> Self {
30 self.attr(Attribute::Background, AttrValue::Color(bg));
31 self
32 }
33
34 pub fn borders(mut self, b: Borders) -> Self {
35 self.attr(Attribute::Borders, AttrValue::Borders(b));
36 self
37 }
38
39 pub fn title<S: Into<String>>(mut self, t: S, a: Alignment) -> Self {
40 self.attr(Attribute::Title, AttrValue::Title((t.into(), a)));
41 self
42 }
43
44 pub fn max_entries(mut self, max: usize) -> Self {
45 self.attr(Attribute::Width, AttrValue::Length(max));
46 self
47 }
48
49 pub fn data(mut self, data: &[u64]) -> Self {
50 self.attr(
51 Attribute::Dataset,
52 AttrValue::Payload(PropPayload::Vec(
53 data.iter().map(|x| PropValue::U64(*x)).collect(),
54 )),
55 );
56 self
57 }
58
59 fn data_len(&self) -> usize {
63 self.props
64 .get(Attribute::Dataset)
65 .map_or(0, |x| x.unwrap_payload().unwrap_vec().len())
66 }
67
68 fn get_data(&self, max: usize) -> Vec<u64> {
72 match self
73 .props
74 .get(Attribute::Dataset)
75 .map(|x| x.unwrap_payload())
76 {
77 Some(PropPayload::Vec(list)) => {
78 let mut data: Vec<u64> = Vec::with_capacity(max);
79 list.iter()
80 .take(max)
81 .cloned()
82 .map(|x| x.unwrap_u64())
83 .for_each(|x| data.push(x));
84 data
85 }
86 _ => Vec::new(),
87 }
88 }
89}
90
91impl MockComponent for Sparkline {
92 fn view(&mut self, render: &mut Frame, area: Rect) {
93 if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
94 let foreground = self
95 .props
96 .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
97 .unwrap_color();
98 let background = self
99 .props
100 .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
101 .unwrap_color();
102 let title = crate::utils::get_title_or_center(&self.props);
103 let borders = self
104 .props
105 .get_or(Attribute::Borders, AttrValue::Borders(Borders::default()))
106 .unwrap_borders();
107 let max_entries = self
108 .props
109 .get_or(Attribute::Width, AttrValue::Length(self.data_len()))
110 .unwrap_length();
111 let data: Vec<u64> = self.get_data(max_entries);
113 let widget: TuiSparkline = TuiSparkline::default()
115 .block(crate::utils::get_block(borders, Some(&title), false, None))
116 .data(data.as_slice())
117 .max(max_entries as u64)
118 .style(Style::default().fg(foreground).bg(background));
119 render.render_widget(widget, area);
121 }
122 }
123
124 fn query(&self, attr: Attribute) -> Option<AttrValue> {
125 self.props.get(attr)
126 }
127
128 fn attr(&mut self, attr: Attribute, value: AttrValue) {
129 self.props.set(attr, value);
130 }
131
132 fn state(&self) -> State {
133 State::None
134 }
135
136 fn perform(&mut self, _cmd: Cmd) -> CmdResult {
137 CmdResult::None
138 }
139}
140
141#[cfg(test)]
142mod test {
143
144 use super::*;
145
146 use pretty_assertions::assert_eq;
147
148 #[test]
149 fn test_components_sparkline() {
150 let component = Sparkline::default()
151 .background(Color::White)
152 .foreground(Color::Black)
153 .title("bandwidth", Alignment::Center)
154 .borders(Borders::default())
155 .max_entries(8)
156 .data(&[
157 60, 80, 90, 88, 76, 101, 98, 93, 96, 102, 110, 99, 88, 75, 34, 45, 67, 102,
158 ]);
159 assert_eq!(component.state(), State::None);
161 assert_eq!(component.data_len(), 18);
163 assert_eq!(component.get_data(4), vec![60, 80, 90, 88]);
164 }
165}