Skip to main content

scrin/widgets/
tabs.rs

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 Tabs<'a> {
9    pub titles: &'a [&'a str],
10    pub selected: usize,
11    pub style: Style,
12    pub highlight_style: Style,
13    pub divider: &'a str,
14}
15
16impl<'a> Tabs<'a> {
17    pub fn new(titles: &'a [&'a str]) -> Self {
18        Self {
19            titles,
20            selected: 0,
21            style: Style::new().fg(Color::rgb(139, 148, 158)),
22            highlight_style: Style::new().fg(Color::rgb(88, 166, 255)).bold(),
23            divider: " │ ",
24        }
25    }
26
27    pub fn with_selected(mut self, selected: usize) -> Self {
28        self.selected = selected;
29        self
30    }
31
32    pub fn with_style(mut self, style: Style) -> Self {
33        self.style = style;
34        self
35    }
36
37    pub fn with_highlight_style(mut self, style: Style) -> Self {
38        self.highlight_style = style;
39        self
40    }
41
42    pub fn select_next(&mut self) {
43        self.selected = (self.selected + 1) % self.titles.len();
44    }
45
46    pub fn select_prev(&mut self) {
47        self.selected = if self.selected == 0 {
48            self.titles.len() - 1
49        } else {
50            self.selected - 1
51        };
52    }
53}
54
55impl<'a> Widget for Tabs<'a> {
56    fn render(&self, buffer: &mut Buffer, area: Rect) {
57        let mut x = area.x as usize;
58        for (i, title) in self.titles.iter().enumerate() {
59            if x >= area.right() as usize {
60                break;
61            }
62            let is_selected = i == self.selected;
63            let (fg, bg, _bold) = if is_selected {
64                (
65                    self.highlight_style.fg_or_default(),
66                    self.highlight_style.bg,
67                    self.highlight_style.bold,
68                )
69            } else {
70                (self.style.fg_or_default(), self.style.bg, self.style.bold)
71            };
72            let display: String = title
73                .chars()
74                .take(area.width as usize - x + area.x as usize)
75                .collect();
76            buffer.set_str_bold(x, area.y as usize, &display, fg, bg);
77            x += display.len();
78            if i < self.titles.len() - 1 && x < area.right() as usize {
79                let div: String = self
80                    .divider
81                    .chars()
82                    .take(area.width as usize - x + area.x as usize)
83                    .collect();
84                buffer.set_str(x, area.y as usize, &div, self.style.fg_or_default(), bg);
85                x += div.len();
86            }
87        }
88    }
89}