use tui::{
buffer::Buffer,
layout::Rect,
style::{Color, Style},
text::Span,
widgets::{Block, Widget},
};
#[derive(Debug, Clone)]
pub struct Gauge2<'a> {
block: Option<Block<'a>>,
ratio: f64,
label: Option<Span<'a>>,
style: Style,
gauge_style: Style,
}
impl<'a> Default for Gauge2<'a> {
fn default() -> Gauge2<'a> {
Gauge2 {
block: None,
ratio: 0.0,
label: None,
style: Style::default(),
gauge_style: Style::default(),
}
}
}
impl<'a> Gauge2<'a> {
pub fn block(mut self, block: Block<'a>) -> Gauge2<'a> {
self.block = Some(block);
self
}
pub fn percent(mut self, percent: u16) -> Gauge2<'a> {
assert!(
percent <= 100,
"Percentage should be between 0 and 100 inclusively."
);
self.ratio = f64::from(percent) / 100.0;
self
}
pub fn ratio(mut self, ratio: f64) -> Gauge2<'a> {
assert!(
ratio <= 1.0 && ratio >= 0.0,
"{}", format!("Ratio ({}) should be between 0 and 1 inclusively.", ratio).to_string()
);
self.ratio = ratio;
self
}
pub fn label<T>(mut self, label: T) -> Gauge2<'a>
where
T: Into<Span<'a>>,
{
self.label = Some(label.into());
self
}
pub fn style(mut self, style: Style) -> Gauge2<'a> {
self.style = style;
self
}
pub fn gauge_style(mut self, style: Style) -> Gauge2<'a> {
self.gauge_style = style;
self
}
}
impl<'a> Widget for Gauge2<'a> {
fn render(mut self, area: Rect, buf: &mut Buffer) {
buf.set_style(area, self.style);
let gauge_area = match self.block.take() {
Some(b) => {
let mut inner_area = b.inner(area);
if area.height == 1 {
inner_area = area;
}
b.render(area, buf);
inner_area
}
None => area,
};
buf.set_style(gauge_area, self.gauge_style);
if gauge_area.height < 1 {
return;
}
let mut center = gauge_area.height / 2 + gauge_area.top();
if gauge_area.height < 1 {
center = gauge_area.height + gauge_area.top();
};
let width = (f64::from(gauge_area.width) * self.ratio).round() as u16;
let end = gauge_area.left() + width;
let ratio = self.ratio;
let label = self
.label
.unwrap_or_else(|| Span::from(format!("{}%", (ratio * 100.0).round())));
for y in gauge_area.top()..gauge_area.bottom() {
for x in gauge_area.left()..end {
buf.get_mut(x, y).set_symbol(" ");
}
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);
}
for x in gauge_area.left()..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));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn gauge_invalid_percentage() {
Gauge2::default().percent(110);
}
#[test]
#[should_panic]
fn gauge_invalid_ratio_upper_bound() {
Gauge2::default().ratio(1.1);
}
#[test]
#[should_panic]
fn gauge_invalid_ratio_lower_bound() {
Gauge2::default().ratio(-0.5);
}
}