tui_meter/
lib.rs

1use ratatui::prelude::{Widget, Rect, Buffer, Style, symbols, Color};
2
3// A version of ratatui's `Gauge` with no label (TODO: more styling options)
4
5#[derive(Debug, Clone, Copy, Default)]
6pub struct Meter {
7	meter_style: Style,
8	use_ascii: bool,
9	ratio: f64,
10}
11
12impl Meter {
13	pub fn ratio(self, ratio: f64) -> Self {
14		Self { ratio, ..self }
15	}
16
17	pub fn style(self, meter_style: Style) -> Self {
18		Self { meter_style, ..self }
19	}
20
21	pub fn use_ascii(self, use_ascii: bool) -> Self {
22		Self { use_ascii, ..self }
23	}
24}
25
26impl Widget for Meter {
27	fn render(self, area: Rect, buf: &mut Buffer) {
28		if area.is_empty() {
29			return;
30		}
31
32		buf.set_style(area, self.meter_style);
33
34		// the gauge will be filled proportionally to the ratio
35		let filled_width = f64::from(area.width) * self.ratio;
36		let end = if self.use_ascii {
37			area.left() + filled_width.round() as u16
38		} else {
39			area.left() + filled_width.floor() as u16
40		};
41		for y in area.top()..area.bottom() {
42			// render the filled area (left to end)
43			for x in area.left()..end {
44				// Use full block for the filled part of the gauge and spaces for the part that is
45				// covered by the label. Note that the background and foreground colors are swapped
46				// for the label part, otherwise the gauge will be inverted
47				buf[(x, y)]
48					.set_symbol(symbols::block::FULL)
49					.set_fg(self.meter_style.fg.unwrap_or(Color::Reset))
50					.set_bg(self.meter_style.bg.unwrap_or(Color::Reset));
51			}
52			if !self.use_ascii && self.ratio < 1.0 {
53				let symbol = match ((filled_width % 1.0) * 8.0).round() as u16 {
54					1 => symbols::block::ONE_EIGHTH,
55					2 => symbols::block::ONE_QUARTER,
56					3 => symbols::block::THREE_EIGHTHS,
57					4 => symbols::block::HALF,
58					5 => symbols::block::FIVE_EIGHTHS,
59					6 => symbols::block::THREE_QUARTERS,
60					7 => symbols::block::SEVEN_EIGHTHS,
61					8 => symbols::block::FULL,
62					_ => " ",
63				};
64				buf[(end, y)].set_symbol(symbol);
65			}
66		}
67	}
68}