feat(widgets/gauge): allow gauge to use unicode block for more descriptive progress (#377)

* gauge now uses unicode blocks for more descriptive progress

* removed unnecessary if

* changed function name to better reflect unicode

* standardized block symbols, added no unicode option, added tests

* formatting

* improved readability

* gauge tests now check color

* formatted
pull/423/head
DashEightMate 4 years ago committed by GitHub
parent 0030eb4a13
commit 0a05579a1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -106,7 +106,8 @@ fn main() -> Result<(), Box<dyn Error>> {
.add_modifier(Modifier::ITALIC), .add_modifier(Modifier::ITALIC),
) )
.percent(app.progress4) .percent(app.progress4)
.label(label); .label(label)
.use_unicode(false);
f.render_widget(gauge, chunks[3]); f.render_widget(gauge, chunks[3]);
})?; })?;

@ -24,6 +24,7 @@ pub struct Gauge<'a> {
block: Option<Block<'a>>, block: Option<Block<'a>>,
ratio: f64, ratio: f64,
label: Option<Span<'a>>, label: Option<Span<'a>>,
use_unicode: bool,
style: Style, style: Style,
gauge_style: Style, gauge_style: Style,
} }
@ -34,6 +35,7 @@ impl<'a> Default for Gauge<'a> {
block: None, block: None,
ratio: 0.0, ratio: 0.0,
label: None, label: None,
use_unicode: true,
style: Style::default(), style: Style::default(),
gauge_style: Style::default(), gauge_style: Style::default(),
} }
@ -82,6 +84,11 @@ impl<'a> Gauge<'a> {
self.gauge_style = style; self.gauge_style = style;
self self
} }
pub fn use_unicode(mut self, unicode: bool) -> Gauge<'a> {
self.use_unicode = unicode;
self
}
} }
impl<'a> Widget for Gauge<'a> { impl<'a> Widget for Gauge<'a> {
@ -101,8 +108,14 @@ impl<'a> Widget for Gauge<'a> {
} }
let center = gauge_area.height / 2 + gauge_area.top(); let center = gauge_area.height / 2 + gauge_area.top();
let width = (f64::from(gauge_area.width) * self.ratio).round() as u16; let width = f64::from(gauge_area.width) * self.ratio;
let end = gauge_area.left() + width; //go to regular rounding behavior if we're not using unicode blocks
let end = gauge_area.left()
+ if self.use_unicode {
width.floor() as u16
} else {
width.round() as u16
};
// Label // Label
let ratio = self.ratio; let ratio = self.ratio;
let label = self let label = self
@ -114,14 +127,25 @@ impl<'a> Widget for Gauge<'a> {
buf.get_mut(x, y).set_symbol(" "); buf.get_mut(x, y).set_symbol(" ");
} }
//set unicode block
if self.use_unicode && self.ratio < 1.0 {
buf.get_mut(end, y)
.set_symbol(get_unicode_block(width % 1.0));
}
let mut color_end = end;
if y == center { if y == center {
let label_width = label.width() as u16; let label_width = label.width() as u16;
let middle = (gauge_area.width - label_width) / 2 + gauge_area.left(); let middle = (gauge_area.width - label_width) / 2 + gauge_area.left();
buf.set_span(middle, y, &label, gauge_area.right() - middle); buf.set_span(middle, y, &label, gauge_area.right() - middle);
if self.use_unicode && end >= middle && end < middle + label_width {
color_end = gauge_area.left() + (width.round() as u16); //set color on the label to the rounded gauge level
}
} }
// Fix colors // Fix colors
for x in gauge_area.left()..end { for x in gauge_area.left()..color_end {
buf.get_mut(x, y) buf.get_mut(x, y)
.set_fg(self.gauge_style.bg.unwrap_or(Color::Reset)) .set_fg(self.gauge_style.bg.unwrap_or(Color::Reset))
.set_bg(self.gauge_style.fg.unwrap_or(Color::Reset)); .set_bg(self.gauge_style.fg.unwrap_or(Color::Reset));
@ -130,6 +154,20 @@ impl<'a> Widget for Gauge<'a> {
} }
} }
fn get_unicode_block<'a>(frac: f64) -> &'a str {
match (frac * 8.0).round() as u16 {
//get how many eighths the fraction is closest to
1 => symbols::block::ONE_EIGHTH,
2 => symbols::block::ONE_QUARTER,
3 => symbols::block::THREE_EIGHTHS,
4 => symbols::block::HALF,
5 => symbols::block::FIVE_EIGHTHS,
6 => symbols::block::THREE_QUARTERS,
7 => symbols::block::SEVEN_EIGHTHS,
8 => symbols::block::FULL,
_ => " ",
}
}
/// A compact widget to display a task progress over a single line. /// A compact widget to display a task progress over a single line.
/// ///
/// # Examples: /// # Examples:

@ -22,11 +22,80 @@ fn widgets_gauge_renders() {
let gauge = Gauge::default() let gauge = Gauge::default()
.block(Block::default().title("Percentage").borders(Borders::ALL)) .block(Block::default().title("Percentage").borders(Borders::ALL))
.gauge_style(Style::default().bg(Color::Blue).fg(Color::Red))
.percent(43); .percent(43);
f.render_widget(gauge, chunks[0]); f.render_widget(gauge, chunks[0]);
let gauge = Gauge::default() let gauge = Gauge::default()
.block(Block::default().title("Ratio").borders(Borders::ALL)) .block(Block::default().title("Ratio").borders(Borders::ALL))
.ratio(0.211_313_934_313_1); .gauge_style(Style::default().bg(Color::Blue).fg(Color::Red))
.ratio(0.511_313_934_313_1);
f.render_widget(gauge, chunks[1]);
})
.unwrap();
let mut expected = Buffer::with_lines(vec![
" ",
" ",
" ┌Percentage────────────────────────┐ ",
" │ ▋43% │ ",
" └──────────────────────────────────┘ ",
" ┌Ratio─────────────────────────────┐ ",
" │ 51% │ ",
" └──────────────────────────────────┘ ",
" ",
" ",
]);
for i in 3..17 {
expected
.get_mut(i, 3)
.set_bg(Color::Red)
.set_fg(Color::Blue);
}
for i in 17..37 {
expected
.get_mut(i, 3)
.set_bg(Color::Blue)
.set_fg(Color::Red);
}
for i in 3..20 {
expected
.get_mut(i, 6)
.set_bg(Color::Red)
.set_fg(Color::Blue);
}
for i in 20..37 {
expected
.get_mut(i, 6)
.set_bg(Color::Blue)
.set_fg(Color::Red);
}
terminal.backend().assert_buffer(&expected);
}
#[test]
fn widgets_gauge_renders_no_unicode() {
let backend = TestBackend::new(40, 10);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(2)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(f.size());
let gauge = Gauge::default()
.block(Block::default().title("Percentage").borders(Borders::ALL))
.percent(43)
.use_unicode(false);
f.render_widget(gauge, chunks[0]);
let gauge = Gauge::default()
.block(Block::default().title("Ratio").borders(Borders::ALL))
.ratio(0.211_313_934_313_1)
.use_unicode(false);
f.render_widget(gauge, chunks[1]); f.render_widget(gauge, chunks[1]);
}) })
.unwrap(); .unwrap();

Loading…
Cancel
Save