tui_realm_stdlib/components/
progress_bar.rs1use tuirealm::command::{Cmd, CmdResult};
6use tuirealm::props::{
7 Alignment, AttrValue, Attribute, Borders, Color, PropPayload, PropValue, Props, Style,
8 TextModifiers,
9};
10use tuirealm::ratatui::{layout::Rect, widgets::Gauge};
11use tuirealm::{Frame, MockComponent, State};
12
13#[derive(Default)]
19#[must_use]
20pub struct ProgressBar {
21 props: Props,
22}
23
24impl ProgressBar {
25 pub fn foreground(mut self, fg: Color) -> Self {
26 self.attr(Attribute::Foreground, AttrValue::Color(fg));
27 self
28 }
29
30 pub fn background(mut self, bg: Color) -> Self {
31 self.attr(Attribute::Background, AttrValue::Color(bg));
32 self
33 }
34
35 pub fn borders(mut self, b: Borders) -> Self {
36 self.attr(Attribute::Borders, AttrValue::Borders(b));
37 self
38 }
39
40 pub fn modifiers(mut self, m: TextModifiers) -> Self {
41 self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
42 self
43 }
44
45 pub fn title<S: Into<String>>(mut self, t: S, a: Alignment) -> Self {
46 self.attr(Attribute::Title, AttrValue::Title((t.into(), a)));
47 self
48 }
49
50 pub fn label<S: Into<String>>(mut self, s: S) -> Self {
51 self.attr(Attribute::Text, AttrValue::String(s.into()));
52 self
53 }
54
55 pub fn progress(mut self, p: f64) -> Self {
56 Self::assert_progress(p);
57 self.attr(
58 Attribute::Value,
59 AttrValue::Payload(PropPayload::One(PropValue::F64(p))),
60 );
61 self
62 }
63
64 fn assert_progress(p: f64) {
65 assert!(
66 (0.0..=1.0).contains(&p),
67 "Progress value must be in range [0.0, 1.0]"
68 );
69 }
70}
71
72impl MockComponent for ProgressBar {
73 fn view(&mut self, render: &mut Frame, area: Rect) {
74 if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
76 let label = self
78 .props
79 .get_or(Attribute::Text, AttrValue::String(String::default()))
80 .unwrap_string();
81 let foreground = self
82 .props
83 .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
84 .unwrap_color();
85 let background = self
86 .props
87 .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
88 .unwrap_color();
89 let modifiers = self
90 .props
91 .get_or(
92 Attribute::TextProps,
93 AttrValue::TextModifiers(TextModifiers::empty()),
94 )
95 .unwrap_text_modifiers();
96 let borders = self
97 .props
98 .get_or(Attribute::Borders, AttrValue::Borders(Borders::default()))
99 .unwrap_borders();
100 let title = self
101 .props
102 .get_ref(Attribute::Title)
103 .and_then(|x| x.as_title());
104 let percentage = self
106 .props
107 .get_or(
108 Attribute::Value,
109 AttrValue::Payload(PropPayload::One(PropValue::F64(0.0))),
110 )
111 .unwrap_payload()
112 .unwrap_one()
113 .unwrap_f64();
114 let div = crate::utils::get_block(borders, title, true, None);
115 render.render_widget(
117 Gauge::default()
118 .block(div)
119 .gauge_style(
120 Style::default()
121 .fg(foreground)
122 .bg(background)
123 .add_modifier(modifiers),
124 )
125 .label(label)
126 .ratio(percentage),
127 area,
128 );
129 }
130 }
131
132 fn query(&self, attr: Attribute) -> Option<AttrValue> {
133 self.props.get(attr)
134 }
135
136 fn attr(&mut self, attr: Attribute, value: AttrValue) {
137 if let Attribute::Value = attr {
138 if let AttrValue::Payload(p) = value.clone() {
139 Self::assert_progress(p.unwrap_one().unwrap_f64());
140 }
141 }
142 self.props.set(attr, value);
143 }
144
145 fn state(&self) -> State {
146 State::None
147 }
148
149 fn perform(&mut self, _cmd: Cmd) -> CmdResult {
150 CmdResult::None
151 }
152}
153
154#[cfg(test)]
155mod test {
156
157 use super::*;
158
159 use pretty_assertions::assert_eq;
160
161 #[test]
162 fn test_components_progress_bar() {
163 let component = ProgressBar::default()
164 .background(Color::Red)
165 .foreground(Color::White)
166 .progress(0.60)
167 .title("Downloading file...", Alignment::Center)
168 .label("60% - ETA 00:20")
169 .borders(Borders::default());
170 assert_eq!(component.state(), State::None);
172 }
173
174 #[test]
175 #[should_panic = "Progress value must be in range [0.0, 1.0]"]
176 fn test_components_progress_bar_bad_prog() {
177 let _ = ProgressBar::default()
178 .background(Color::Red)
179 .foreground(Color::White)
180 .progress(6.0)
181 .title("Downloading file...", Alignment::Center)
182 .label("60% - ETA 00:20")
183 .borders(Borders::default());
184 }
185}