diff --git a/examples/gauge.rs b/examples/gauge.rs index fd0e706..3182846 100644 --- a/examples/gauge.rs +++ b/examples/gauge.rs @@ -106,7 +106,8 @@ fn main() -> Result<(), Box> { .add_modifier(Modifier::ITALIC), ) .percent(app.progress4) - .label(label); + .label(label) + .use_unicode(false); f.render_widget(gauge, chunks[3]); })?; diff --git a/src/widgets/gauge.rs b/src/widgets/gauge.rs index c86e07b..f518f0b 100644 --- a/src/widgets/gauge.rs +++ b/src/widgets/gauge.rs @@ -24,6 +24,7 @@ pub struct Gauge<'a> { block: Option>, ratio: f64, label: Option>, + use_unicode: bool, style: Style, gauge_style: Style, } @@ -34,6 +35,7 @@ impl<'a> Default for Gauge<'a> { block: None, ratio: 0.0, label: None, + use_unicode: true, style: Style::default(), gauge_style: Style::default(), } @@ -82,6 +84,11 @@ impl<'a> Gauge<'a> { self.gauge_style = style; self } + + pub fn use_unicode(mut self, unicode: bool) -> Gauge<'a> { + self.use_unicode = unicode; + self + } } 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 width = (f64::from(gauge_area.width) * self.ratio).round() as u16; - let end = gauge_area.left() + width; + let width = f64::from(gauge_area.width) * self.ratio; + //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 let ratio = self.ratio; let label = self @@ -114,14 +127,25 @@ impl<'a> Widget for Gauge<'a> { 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 { let label_width = label.width() as u16; let middle = (gauge_area.width - label_width) / 2 + gauge_area.left(); 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 - for x in gauge_area.left()..end { + for x in gauge_area.left()..color_end { buf.get_mut(x, y) .set_fg(self.gauge_style.bg.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. /// /// # Examples: diff --git a/tests/widgets_gauge.rs b/tests/widgets_gauge.rs index 2dc304a..c39b311 100644 --- a/tests/widgets_gauge.rs +++ b/tests/widgets_gauge.rs @@ -22,11 +22,80 @@ fn widgets_gauge_renders() { let gauge = Gauge::default() .block(Block::default().title("Percentage").borders(Borders::ALL)) + .gauge_style(Style::default().bg(Color::Blue).fg(Color::Red)) .percent(43); 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); + .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]); }) .unwrap();