1use crate::core::buffer::Buffer;
2use crate::core::color::Color;
3use crate::core::rect::Rect;
4use crate::style::Style;
5use crate::widgets::Widget;
6
7#[derive(Debug, Clone)]
8pub struct Gauge<'a> {
9 pub ratio: f64,
10 pub label: &'a str,
11 pub style: Style,
12 pub gauge_style: Style,
13 pub use_unicode: bool,
14}
15
16impl<'a> Gauge<'a> {
17 pub fn new() -> Self {
18 Self {
19 ratio: 0.0,
20 label: "",
21 style: Style::new(),
22 gauge_style: Style::new().fg(Color::rgb(88, 166, 255)),
23 use_unicode: true,
24 }
25 }
26
27 pub fn with_ratio(mut self, ratio: f64) -> Self {
28 self.ratio = ratio.clamp(0.0, 1.0);
29 self
30 }
31
32 pub fn with_label(mut self, label: &'a str) -> Self {
33 self.label = label;
34 self
35 }
36
37 pub fn with_style(mut self, style: Style) -> Self {
38 self.style = style;
39 self
40 }
41
42 pub fn with_gauge_style(mut self, style: Style) -> Self {
43 self.gauge_style = style;
44 self
45 }
46}
47
48impl<'a> Widget for Gauge<'a> {
49 fn render(&self, buffer: &mut Buffer, area: Rect) {
50 if area.width < 2 || area.height < 1 {
51 return;
52 }
53 let w = area.width as usize;
54 let fill = (w as f64 * self.ratio) as usize;
55 let fg = self.gauge_style.fg_or_default();
56 let bg = self.style.bg;
57 let empty_bg = self.style.bg;
58
59 let (full, half, empty) = if self.use_unicode {
60 ('━', '╌', '─')
61 } else {
62 ('=', '-', ' ')
63 };
64
65 for i in 0..w {
66 let x = (area.x as usize) + i;
67 let y = area.y as usize;
68 if i < fill {
69 buffer.set(
70 x,
71 y,
72 crate::core::buffer::Cell {
73 ch: full,
74 fg,
75 bg,
76 bold: false,
77 italic: false,
78 underlined: false,
79 },
80 );
81 } else if i == fill && self.ratio > 0.0 {
82 buffer.set(
83 x,
84 y,
85 crate::core::buffer::Cell {
86 ch: half,
87 fg: fg.dim(0.5),
88 bg: empty_bg,
89 bold: false,
90 italic: false,
91 underlined: false,
92 },
93 );
94 } else {
95 buffer.set(
96 x,
97 y,
98 crate::core::buffer::Cell {
99 ch: empty,
100 fg: fg.dim(0.3),
101 bg: empty_bg,
102 bold: false,
103 italic: false,
104 underlined: false,
105 },
106 );
107 }
108 }
109
110 if !self.label.is_empty() {
111 let pct = (self.ratio * 100.0) as u32;
112 let label = format!(" {} {}%", self.label, pct);
113 let display: String = label.chars().take(w).collect();
114 let lx = area.x as usize + (w.saturating_sub(display.len())) / 2;
115 buffer.set_str(lx, area.y as usize, &display, Color::WHITE, bg);
116 }
117 }
118}
119
120impl<'a> Default for Gauge<'a> {
121 fn default() -> Self {
122 Self::new()
123 }
124}