scrin 0.1.80

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 aisling::color::{Color as AislingColor, Gradient as AislingGradient, GradientDirection};
use aisling::loaders::{Loader, LoaderConfig, LoaderKind, LoaderProgress};

pub struct LoaderPlayer {
    kind: LoaderKind,
    config: LoaderConfig,
    accent: Color,
}

impl LoaderPlayer {
    pub fn new(kind: LoaderKind) -> Self {
        Self {
            kind,
            config: LoaderConfig::default(),
            accent: Color::rgb(88, 166, 255),
        }
    }

    pub fn with_config(kind: LoaderKind, config: LoaderConfig) -> Self {
        Self {
            kind,
            config,
            accent: Color::rgb(88, 166, 255),
        }
    }

    pub fn with_accent(mut self, accent: Color) -> Self {
        self.accent = accent;
        self
    }

    pub fn with_size(mut self, width: usize, height: usize) -> Self {
        self.config = self.config.with_size(width, height);
        self
    }

    pub fn with_label(mut self, label: String) -> Self {
        self.config = self.config.with_label(label);
        self
    }

    pub fn with_unit(mut self, unit: &str) -> Self {
        self.config = self.config.with_unit(unit);
        self
    }

    pub fn with_fraction(mut self, fraction: bool) -> Self {
        self.config = self.config.with_fraction(fraction);
        self
    }

    pub fn with_gradient_colors(mut self, colors: Vec<Color>, angle: f32) -> Self {
        let a_colors: Vec<AislingColor> = colors
            .into_iter()
            .map(|c| AislingColor::rgb(c.r, c.g, c.b))
            .collect();
        let grad = AislingGradient::new(a_colors, 32);
        let dir = match angle as u32 {
            0 => GradientDirection::Horizontal,
            90 => GradientDirection::Vertical,
            _ => GradientDirection::Diagonal,
        };
        self.config = self.config.with_gradient(grad, dir);
        self
    }

    pub fn render(&self, tick: usize, progress: LoaderProgress, buffer: &mut Buffer, area: Rect) {
        let loader = Loader::with_config(self.kind, self.config.clone());
        let frame = loader.frame(tick, progress);
        let fw = frame.width();
        let fh = frame.height();
        for fy in 0..fh.min(area.height as usize) {
            for fx in 0..fw.min(area.width as usize) {
                if let Some(cell) = frame.cell(fx, fy) {
                    let x = area.x as usize + fx;
                    let y = area.y as usize + fy;
                    if x < buffer.width && y < buffer.height {
                        let fg = if let Some(c) = cell.colors.fg {
                            Color::rgb(c.r, c.g, c.b)
                        } else {
                            self.accent
                        };
                        let bg = cell.colors.bg.map(|c| Color::rgb(c.r, c.g, c.b));
                        buffer.set(
                            x,
                            y,
                            crate::core::buffer::Cell {
                                ch: cell.ch,
                                fg,
                                bg,
                                bold: cell.bold,
                                italic: false,
                                underlined: false,
                            },
                        );
                    }
                }
            }
        }
    }

    pub fn get_ansi_string(&self, tick: usize, progress: LoaderProgress) -> String {
        let loader = Loader::with_config(self.kind, self.config.clone());
        loader.frame(tick, progress).to_ansi_string()
    }

    pub fn kind(&self) -> LoaderKind {
        self.kind
    }

    pub fn name(&self) -> &'static str {
        self.kind.name()
    }

    pub fn all_kinds() -> &'static [LoaderKind] {
        LoaderKind::all()
    }

    pub fn progress_from_counts(current: u64, total: u64) -> LoaderProgress {
        LoaderProgress::from_counts(current, total)
    }

    pub fn progress_from_fraction(fraction: f32) -> LoaderProgress {
        LoaderProgress::new(fraction)
    }
}