scrin 0.1.73

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 Tabs<'a> {
    pub titles: &'a [&'a str],
    pub selected: usize,
    pub style: Style,
    pub highlight_style: Style,
    pub divider: &'a str,
}

impl<'a> Tabs<'a> {
    pub fn new(titles: &'a [&'a str]) -> Self {
        Self {
            titles,
            selected: 0,
            style: Style::new().fg(Color::rgb(139, 148, 158)),
            highlight_style: Style::new().fg(Color::rgb(88, 166, 255)).bold(),
            divider: "",
        }
    }

    pub fn with_selected(mut self, selected: usize) -> Self {
        self.selected = selected;
        self
    }

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

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

    pub fn select_next(&mut self) {
        self.selected = (self.selected + 1) % self.titles.len();
    }

    pub fn select_prev(&mut self) {
        self.selected = if self.selected == 0 {
            self.titles.len() - 1
        } else {
            self.selected - 1
        };
    }
}

impl<'a> Widget for Tabs<'a> {
    fn render(&self, buffer: &mut Buffer, area: Rect) {
        let mut x = area.x as usize;
        for (i, title) in self.titles.iter().enumerate() {
            if x >= area.right() as usize {
                break;
            }
            let is_selected = i == self.selected;
            let (fg, bg, _bold) = if is_selected {
                (
                    self.highlight_style.fg_or_default(),
                    self.highlight_style.bg,
                    self.highlight_style.bold,
                )
            } else {
                (self.style.fg_or_default(), self.style.bg, self.style.bold)
            };
            let display: String = title
                .chars()
                .take(area.width as usize - x + area.x as usize)
                .collect();
            buffer.set_str_bold(x, area.y as usize, &display, fg, bg);
            x += display.len();
            if i < self.titles.len() - 1 && x < area.right() as usize {
                let div: String = self
                    .divider
                    .chars()
                    .take(area.width as usize - x + area.x as usize)
                    .collect();
                buffer.set_str(x, area.y as usize, &div, self.style.fg_or_default(), bg);
                x += div.len();
            }
        }
    }
}