tui_temp_fork/widgets/
gauge.rs1use unicode_width::UnicodeWidthStr;
2
3use crate::buffer::Buffer;
4use crate::layout::Rect;
5use crate::style::{Color, Style};
6use crate::widgets::{Block, Widget};
7
8pub struct Gauge<'a> {
23 block: Option<Block<'a>>,
24 ratio: f64,
25 label: Option<&'a str>,
26 style: Style,
27}
28
29impl<'a> Default for Gauge<'a> {
30 fn default() -> Gauge<'a> {
31 Gauge {
32 block: None,
33 ratio: 0.0,
34 label: None,
35 style: Default::default(),
36 }
37 }
38}
39
40impl<'a> Gauge<'a> {
41 pub fn block(mut self, block: Block<'a>) -> Gauge<'a> {
42 self.block = Some(block);
43 self
44 }
45
46 pub fn percent(mut self, percent: u16) -> Gauge<'a> {
47 assert!(
48 percent <= 100,
49 "Percentage should be between 0 and 100 inclusively."
50 );
51 self.ratio = f64::from(percent) / 100.0;
52 self
53 }
54
55 pub fn ratio(mut self, ratio: f64) -> Gauge<'a> {
57 assert!(
58 ratio <= 1.0 && ratio >= 0.0,
59 "Ratio should be between 0 and 1 inclusively."
60 );
61 self.ratio = ratio;
62 self
63 }
64
65 pub fn label(mut self, string: &'a str) -> Gauge<'a> {
66 self.label = Some(string);
67 self
68 }
69
70 pub fn style(mut self, style: Style) -> Gauge<'a> {
71 self.style = style;
72 self
73 }
74}
75
76impl<'a> Widget for Gauge<'a> {
77 fn draw(&mut self, area: Rect, buf: &mut Buffer) {
78 let gauge_area = match self.block {
79 Some(ref mut b) => {
80 b.draw(area, buf);
81 b.inner(area)
82 }
83 None => area,
84 };
85 if gauge_area.height < 1 {
86 return;
87 }
88
89 if self.style.bg != Color::Reset {
90 self.background(gauge_area, buf, self.style.bg);
91 }
92
93 let center = gauge_area.height / 2 + gauge_area.top();
94 let width = (f64::from(gauge_area.width) * self.ratio).round() as u16;
95 let end = gauge_area.left() + width;
96 for y in gauge_area.top()..gauge_area.bottom() {
97 for x in gauge_area.left()..end {
99 buf.get_mut(x, y).set_symbol(" ");
100 }
101
102 if y == center {
103 let precent_label = format!("{}%", (self.ratio * 100.0).round());
105 let label = self.label.unwrap_or(&precent_label);
106 let label_width = label.width() as u16;
107 let middle = (gauge_area.width - label_width) / 2 + gauge_area.left();
108 buf.set_string(middle, y, label, self.style);
109 }
110
111 for x in gauge_area.left()..end {
113 buf.get_mut(x, y)
114 .set_fg(self.style.bg)
115 .set_bg(self.style.fg);
116 }
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 #[should_panic]
127 fn gauge_invalid_percentage() {
128 Gauge::default().percent(110);
129 }
130
131 #[test]
132 #[should_panic]
133 fn gauge_invalid_ratio_upper_bound() {
134 Gauge::default().ratio(1.1);
135 }
136
137 #[test]
138 #[should_panic]
139 fn gauge_invalid_ratio_lower_bound() {
140 Gauge::default().ratio(-0.5);
141 }
142}