scrin 0.1.78

A terminal UI toolkit with panes, widgets, overlays, animations, and Aisling-powered effects/loaders.
Documentation
use crate::core::buffer::Buffer;
use crate::core::color::Color;
use crate::core::rect::Rect;
use crate::style::Style;
use crate::widgets::Widget;

#[derive(Debug, Clone)]
pub struct Gauge<'a> {
    pub ratio: f64,
    pub label: &'a str,
    pub style: Style,
    pub gauge_style: Style,
    pub use_unicode: bool,
}

impl<'a> Gauge<'a> {
    pub fn new() -> Self {
        Self {
            ratio: 0.0,
            label: "",
            style: Style::new(),
            gauge_style: Style::new().fg(Color::rgb(88, 166, 255)),
            use_unicode: true,
        }
    }

    pub fn with_ratio(mut self, ratio: f64) -> Self {
        self.ratio = ratio.clamp(0.0, 1.0);
        self
    }

    pub fn with_label(mut self, label: &'a str) -> Self {
        self.label = label;
        self
    }

    pub fn with_style(mut self, style: Style) -> Self {
        self.style = style;
        self
    }

    pub fn with_gauge_style(mut self, style: Style) -> Self {
        self.gauge_style = style;
        self
    }
}

impl<'a> Widget for Gauge<'a> {
    fn render(&self, buffer: &mut Buffer, area: Rect) {
        if area.width < 2 || area.height < 1 {
            return;
        }
        let w = area.width as usize;
        let fill = (w as f64 * self.ratio) as usize;
        let fg = self.gauge_style.fg_or_default();
        let bg = self.style.bg;
        let empty_bg = self.style.bg;

        let (full, half, empty) = if self.use_unicode {
            ('', '', '')
        } else {
            ('=', '-', ' ')
        };

        for i in 0..w {
            let x = (area.x as usize) + i;
            let y = area.y as usize;
            if i < fill {
                buffer.set(
                    x,
                    y,
                    crate::core::buffer::Cell {
                        ch: full,
                        fg,
                        bg,
                        bold: false,
                        italic: false,
                        underlined: false,
                    },
                );
            } else if i == fill && self.ratio > 0.0 {
                buffer.set(
                    x,
                    y,
                    crate::core::buffer::Cell {
                        ch: half,
                        fg: fg.dim(0.5),
                        bg: empty_bg,
                        bold: false,
                        italic: false,
                        underlined: false,
                    },
                );
            } else {
                buffer.set(
                    x,
                    y,
                    crate::core::buffer::Cell {
                        ch: empty,
                        fg: fg.dim(0.3),
                        bg: empty_bg,
                        bold: false,
                        italic: false,
                        underlined: false,
                    },
                );
            }
        }

        if !self.label.is_empty() {
            let pct = (self.ratio * 100.0) as u32;
            let label = format!(" {} {}%", self.label, pct);
            let display: String = label.chars().take(w).collect();
            let lx = area.x as usize + (w.saturating_sub(display.len())) / 2;
            buffer.set_str(lx, area.y as usize, &display, Color::WHITE, bg);
        }
    }
}

impl<'a> Default for Gauge<'a> {
    fn default() -> Self {
        Self::new()
    }
}