tui_meter/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use ratatui::prelude::{Widget, Rect, Buffer, Style, symbols, Color};

// A version of ratatui's `Gauge` with no label (TODO: more styling options)

#[derive(Debug, Clone, Copy, Default)]
pub struct Meter {
	meter_style: Style,
	use_ascii: bool,
	ratio: f64,
}

impl Meter {
	pub fn ratio(self, ratio: f64) -> Self {
		Self { ratio, ..self }
	}

	pub fn style(self, meter_style: Style) -> Self {
		Self { meter_style, ..self }
	}

	pub fn use_ascii(self, use_ascii: bool) -> Self {
		Self { use_ascii, ..self }
	}
}

impl Widget for Meter {
	fn render(self, area: Rect, buf: &mut Buffer) {
		if area.is_empty() {
			return;
		}

		buf.set_style(area, self.meter_style);

		// the gauge will be filled proportionally to the ratio
		let filled_width = f64::from(area.width) * self.ratio;
		let end = if self.use_ascii {
			area.left() + filled_width.round() as u16
		} else {
			area.left() + filled_width.floor() as u16
		};
		for y in area.top()..area.bottom() {
			// render the filled area (left to end)
			for x in area.left()..end {
				// Use full block for the filled part of the gauge and spaces for the part that is
				// covered by the label. Note that the background and foreground colors are swapped
				// for the label part, otherwise the gauge will be inverted
				buf.get_mut(x, y)
					.set_symbol(symbols::block::FULL)
					.set_fg(self.meter_style.fg.unwrap_or(Color::Reset))
					.set_bg(self.meter_style.bg.unwrap_or(Color::Reset));
			}
			if !self.use_ascii && self.ratio < 1.0 {
				let symbol = match ((filled_width % 1.0) * 8.0).round() as u16 {
					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,
					_ => " ",
				};
				buf.get_mut(end, y).set_symbol(symbol);
			}
		}
	}
}