• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

veeso / tui-realm-stdlib / 20396003855

20 Dec 2025 02:54PM UTC coverage: 68.423% (-0.02%) from 68.439%
20396003855

push

github

web-flow
perf: Smoother ProgressBars (#41)

* fix(progress_bar): enable Gauge option "use_unicode"

* chore(examples/progress_bar): showcase use_unicode functionality

By having one bar load fast and one slowly.
Also add text for keyboard shortcuts.

---------

Co-authored-by: Christian Visintin <christian.visintin@veeso.dev>

0 of 2 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

3038 of 4440 relevant lines covered (68.42%)

1.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

49.59
/src/components/progress_bar.rs
1
//! ## ProgressBar
2
//!
3
//! `ProgressBar` provides a component which shows the progress. It is possible to set the style for the progress bar and the text shown above it.
4

5
use tuirealm::command::{Cmd, CmdResult};
6
use tuirealm::props::{
7
    Alignment, AttrValue, Attribute, Borders, Color, PropPayload, PropValue, Props, Style,
8
    TextModifiers,
9
};
10
use tuirealm::ratatui::{layout::Rect, widgets::Gauge};
11
use tuirealm::{Frame, MockComponent, State};
12

13
// -- Component
14

15
/// ## ProgressBar
16
///
17
/// provides a component which shows the progress. It is possible to set the style for the progress bar and the text shown above it.
18
#[derive(Default)]
19
#[must_use]
20
pub struct ProgressBar {
21
    props: Props,
22
}
23

24
impl ProgressBar {
25
    pub fn foreground(mut self, fg: Color) -> Self {
2✔
26
        self.attr(Attribute::Foreground, AttrValue::Color(fg));
2✔
27
        self
2✔
28
    }
2✔
29

30
    pub fn background(mut self, bg: Color) -> Self {
2✔
31
        self.attr(Attribute::Background, AttrValue::Color(bg));
2✔
32
        self
2✔
33
    }
2✔
34

35
    pub fn borders(mut self, b: Borders) -> Self {
1✔
36
        self.attr(Attribute::Borders, AttrValue::Borders(b));
1✔
37
        self
1✔
38
    }
1✔
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 {
1✔
46
        self.attr(Attribute::Title, AttrValue::Title((t.into(), a)));
1✔
47
        self
1✔
48
    }
1✔
49

50
    pub fn label<S: Into<String>>(mut self, s: S) -> Self {
1✔
51
        self.attr(Attribute::Text, AttrValue::String(s.into()));
1✔
52
        self
1✔
53
    }
1✔
54

55
    pub fn progress(mut self, p: f64) -> Self {
2✔
56
        Self::assert_progress(p);
2✔
57
        self.attr(
2✔
58
            Attribute::Value,
2✔
59
            AttrValue::Payload(PropPayload::One(PropValue::F64(p))),
2✔
60
        );
61
        self
2✔
62
    }
2✔
63

64
    fn assert_progress(p: f64) {
3✔
65
        assert!(
3✔
66
            (0.0..=1.0).contains(&p),
3✔
67
            "Progress value must be in range [0.0, 1.0]"
68
        );
69
    }
2✔
70
}
71

72
impl MockComponent for ProgressBar {
73
    fn view(&mut self, render: &mut Frame, area: Rect) {
×
74
        // Make a Span
75
        if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
×
76
            // Text
77
            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
            // Get percentage
105
            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

115
            let normal_style = Style::default()
×
116
                .fg(foreground)
×
117
                .bg(background)
×
118
                .add_modifier(modifiers);
×
119

120
            let div = crate::utils::get_block(borders, title, true, None);
×
121
            // Make progress bar
122
            render.render_widget(
×
123
                Gauge::default()
×
124
                    .block(div)
×
125
                    .style(normal_style)
×
126
                    .gauge_style(normal_style)
×
127
                    .label(label)
×
NEW
128
                    .ratio(percentage)
×
NEW
129
                    .use_unicode(true),
×
UNCOV
130
                area,
×
131
            );
132
        }
×
133
    }
×
134

135
    fn query(&self, attr: Attribute) -> Option<AttrValue> {
×
136
        self.props.get(attr)
×
137
    }
×
138

139
    fn attr(&mut self, attr: Attribute, value: AttrValue) {
8✔
140
        if let Attribute::Value = attr {
8✔
141
            if let AttrValue::Payload(p) = value.clone() {
1✔
142
                Self::assert_progress(p.unwrap_one().unwrap_f64());
1✔
143
            }
1✔
144
        }
7✔
145
        self.props.set(attr, value);
8✔
146
    }
8✔
147

148
    fn state(&self) -> State {
1✔
149
        State::None
1✔
150
    }
1✔
151

152
    fn perform(&mut self, _cmd: Cmd) -> CmdResult {
×
153
        CmdResult::None
×
154
    }
×
155
}
156

157
#[cfg(test)]
158
mod test {
159

160
    use super::*;
161

162
    use pretty_assertions::assert_eq;
163

164
    #[test]
165
    fn test_components_progress_bar() {
1✔
166
        let component = ProgressBar::default()
1✔
167
            .background(Color::Red)
1✔
168
            .foreground(Color::White)
1✔
169
            .progress(0.60)
1✔
170
            .title("Downloading file...", Alignment::Center)
1✔
171
            .label("60% - ETA 00:20")
1✔
172
            .borders(Borders::default());
1✔
173
        // Get value
174
        assert_eq!(component.state(), State::None);
1✔
175
    }
1✔
176

177
    #[test]
178
    #[should_panic = "Progress value must be in range [0.0, 1.0]"]
179
    fn test_components_progress_bar_bad_prog() {
1✔
180
        let _ = ProgressBar::default()
1✔
181
            .background(Color::Red)
1✔
182
            .foreground(Color::White)
1✔
183
            .progress(6.0)
1✔
184
            .title("Downloading file...", Alignment::Center)
1✔
185
            .label("60% - ETA 00:20")
1✔
186
            .borders(Borders::default());
1✔
187
    }
1✔
188
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc