mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 15:14:27 +00:00
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
This commit is contained in:
parent
0030eb4a13
commit
0a05579a1c
3 changed files with 113 additions and 5 deletions
|
@ -106,7 +106,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.add_modifier(Modifier::ITALIC),
|
||||
)
|
||||
.percent(app.progress4)
|
||||
.label(label);
|
||||
.label(label)
|
||||
.use_unicode(false);
|
||||
f.render_widget(gauge, chunks[3]);
|
||||
})?;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ pub struct Gauge<'a> {
|
|||
block: Option<Block<'a>>,
|
||||
ratio: f64,
|
||||
label: Option<Span<'a>>,
|
||||
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:
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue