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}