i3status_rs/formatting/formatter/
bar.rs

1use super::*;
2
3const DEFAULT_BAR_VERTICAL: bool = false;
4const DEFAULT_BAR_WIDTH_HORIZONTAL: usize = 5;
5const DEFAULT_BAR_WIDTH_VERTICAL: usize = 1;
6const DEFAULT_BAR_MAX_VAL: f64 = 100.0;
7
8#[derive(Debug)]
9pub struct BarFormatter {
10    width: usize,
11    max_value: f64,
12    vertical: bool,
13}
14
15impl BarFormatter {
16    pub(super) fn from_args(args: &[Arg]) -> Result<Self> {
17        let mut vertical = DEFAULT_BAR_VERTICAL;
18        let mut width = None;
19        let mut max_value = DEFAULT_BAR_MAX_VAL;
20        for arg in args {
21            match arg.key {
22                "width" | "w" => {
23                    width = Some(arg.parse_value()?);
24                }
25                "max_value" => {
26                    max_value = arg.parse_value()?;
27                }
28                "vertical" | "v" => {
29                    vertical = arg.parse_value()?;
30                }
31                other => {
32                    return Err(Error::new(format!("Unknown argument for 'bar': '{other}'")));
33                }
34            }
35        }
36        Ok(Self {
37            width: width.unwrap_or(match vertical {
38                false => DEFAULT_BAR_WIDTH_HORIZONTAL,
39                true => DEFAULT_BAR_WIDTH_VERTICAL,
40            }),
41            max_value,
42            vertical,
43        })
44    }
45}
46
47const HORIZONTAL_BAR_CHARS: [char; 9] = [
48    ' ', '\u{258f}', '\u{258e}', '\u{258d}', '\u{258c}', '\u{258b}', '\u{258a}', '\u{2589}',
49    '\u{2588}',
50];
51
52const VERTICAL_BAR_CHARS: [char; 9] = [
53    ' ', '\u{2581}', '\u{2582}', '\u{2583}', '\u{2584}', '\u{2585}', '\u{2586}', '\u{2587}',
54    '\u{2588}',
55];
56
57impl Formatter for BarFormatter {
58    fn format(&self, val: &Value, _config: &SharedConfig) -> Result<String, FormatError> {
59        match val {
60            &Value::Number { mut val, .. } => {
61                val = (val / self.max_value).clamp(0., 1.);
62                if self.vertical {
63                    let vert_char = VERTICAL_BAR_CHARS[(val * 8.) as usize];
64                    Ok((0..self.width).map(|_| vert_char).collect())
65                } else {
66                    let chars_to_fill = val * self.width as f64;
67                    Ok((0..self.width)
68                        .map(|i| {
69                            HORIZONTAL_BAR_CHARS
70                                [((chars_to_fill - i as f64).clamp(0., 1.) * 8.) as usize]
71                        })
72                        .collect())
73                }
74            }
75            other => Err(FormatError::IncompatibleFormatter {
76                ty: other.type_name(),
77                fmt: "bar",
78            }),
79        }
80    }
81}