diff --git a/examples/gauge.rs b/examples/gauge.rs index 8669fed..cc2805d 100644 --- a/examples/gauge.rs +++ b/examples/gauge.rs @@ -22,7 +22,7 @@ use util::event::{Event, Events}; struct App { progress1: u16, progress2: u16, - progress3: u16, + progress3: f64, progress4: u16, } @@ -31,7 +31,7 @@ impl App { App { progress1: 0, progress2: 0, - progress3: 0, + progress3: 0.0, progress4: 0, } } @@ -45,9 +45,9 @@ impl App { if self.progress2 > 100 { self.progress2 = 0; } - self.progress3 += 1; - if self.progress3 > 100 { - self.progress3 = 0; + self.progress3 += 0.001; + if self.progress3 > 1.0 { + self.progress3 = 0.0; } self.progress4 += 3; if self.progress4 > 100 { @@ -98,12 +98,12 @@ fn main() -> Result<(), failure::Error> { .label(&format!("{}/100", app.progress2)) .render(&mut f, chunks[1]); Gauge::default() - .block(Block::default().title("Gauge2").borders(Borders::ALL)) + .block(Block::default().title("Gauge3").borders(Borders::ALL)) .style(Style::default().fg(Color::Yellow)) - .percent(app.progress3) + .ratio(app.progress3) .render(&mut f, chunks[2]); Gauge::default() - .block(Block::default().title("Gauge3").borders(Borders::ALL)) + .block(Block::default().title("Gauge4").borders(Borders::ALL)) .style(Style::default().fg(Color::Cyan).modifier(Modifier::Italic)) .percent(app.progress4) .label(&format!("{}/100", app.progress2)) diff --git a/src/widgets/gauge.rs b/src/widgets/gauge.rs index 27396e6..cd1e990 100644 --- a/src/widgets/gauge.rs +++ b/src/widgets/gauge.rs @@ -22,7 +22,7 @@ use widgets::{Block, Widget}; /// ``` pub struct Gauge<'a> { block: Option>, - percent: u16, + ratio: f64, label: Option<&'a str>, style: Style, } @@ -31,7 +31,7 @@ impl<'a> Default for Gauge<'a> { fn default() -> Gauge<'a> { Gauge { block: None, - percent: 0, + ratio: 0.0, label: None, style: Default::default(), } @@ -45,7 +45,21 @@ impl<'a> Gauge<'a> { } pub fn percent(mut self, percent: u16) -> Gauge<'a> { - self.percent = percent; + assert!( + percent <= 100, + "Percentage should be between 0 and 100 inclusively." + ); + self.ratio = f64::from(percent) / 100.0; + self + } + + /// Sets ratio ([0.0, 1.0]) directly. + pub fn ratio(mut self, ratio: f64) -> Gauge<'a> { + assert!( + ratio <= 1.0 && ratio >= 0.0, + "Ratio should be between 0 and 1 inclusively." + ); + self.ratio = ratio; self } @@ -78,7 +92,7 @@ impl<'a> Widget for Gauge<'a> { } let center = gauge_area.height / 2 + gauge_area.top(); - let width = (gauge_area.width * self.percent) / 100; + let width = (f64::from(gauge_area.width) * self.ratio).round() as u16; let end = gauge_area.left() + width; for y in gauge_area.top()..gauge_area.bottom() { // Gauge @@ -88,7 +102,7 @@ impl<'a> Widget for Gauge<'a> { if y == center { // Label - let precent_label = format!("{}%", self.percent); + let precent_label = format!("{}%", (self.ratio * 100.0).round()); let label = self.label.unwrap_or(&precent_label); let label_width = label.width() as u16; let middle = (gauge_area.width - label_width) / 2 + gauge_area.left(); @@ -104,3 +118,26 @@ impl<'a> Widget for Gauge<'a> { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn gauge_invalid_percentage() { + Gauge::default().percent(110); + } + + #[test] + #[should_panic] + fn gauge_invalid_ratio_upper_bound() { + Gauge::default().ratio(1.1); + } + + #[test] + #[should_panic] + fn gauge_invalid_ratio_lower_bound() { + Gauge::default().ratio(-0.5); + } +} diff --git a/tests/gauge.rs b/tests/gauge.rs new file mode 100644 index 0000000..073221c --- /dev/null +++ b/tests/gauge.rs @@ -0,0 +1,45 @@ +extern crate tui; +extern crate unicode_width; + +use tui::backend::TestBackend; +use tui::buffer::Buffer; +use tui::layout::{Constraint, Direction, Layout}; +use tui::widgets::{Block, Borders, Gauge, Widget}; +use tui::Terminal; + +#[test] +fn gauge_render() { + let backend = TestBackend::new(40, 10); + let mut terminal = Terminal::new(backend).unwrap(); + let size = terminal.size().unwrap(); + terminal + .draw(|mut f| { + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(2) + .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) + .split(size); + + Gauge::default() + .block(Block::default().title("Percentage").borders(Borders::ALL)) + .percent(43) + .render(&mut f, chunks[0]); + Gauge::default() + .block(Block::default().title("Ratio").borders(Borders::ALL)) + .ratio(0.2113139343131) + .render(&mut f, chunks[1]); + }).unwrap(); + let expected = Buffer::with_lines(vec![ + " ", + " ", + " ┌Percentage────────────────────────┐ ", + " │ 43% │ ", + " └──────────────────────────────────┘ ", + " ┌Ratio─────────────────────────────┐ ", + " │ 21% │ ", + " └──────────────────────────────────┘ ", + " ", + " ", + ]); + assert_eq!(&expected, terminal.backend().buffer()); +}