use sauron_vdom::{Attribute, Event};
use unicode_width::UnicodeWidthStr;
use crate::{
buffer::Buffer,
layout::Rect,
style::Style,
symbols::line,
widgets::{Block, Widget},
};
pub struct Tabs<'a, T, MSG>
where
T: AsRef<str> + 'a,
{
block: Option<Block<'a, MSG>>,
titles: &'a [T],
selected: usize,
style: Style,
highlight_style: Style,
divider: &'a str,
area: Rect,
events: Vec<Attribute<Event, MSG>>,
}
impl<'a, T, MSG> Default for Tabs<'a, T, MSG>
where
T: AsRef<str>,
{
fn default() -> Tabs<'a, T, MSG> {
Tabs {
block: None,
titles: &[],
selected: 0,
style: Default::default(),
highlight_style: Default::default(),
divider: line::VERTICAL,
area: Default::default(),
events: vec![],
}
}
}
impl<'a, T, MSG> Tabs<'a, T, MSG>
where
T: AsRef<str>,
{
pub fn block(mut self, block: Block<'a, MSG>) -> Self {
self.block = Some(block);
self
}
pub fn titles(mut self, titles: &'a [T]) -> Self {
self.titles = titles;
self
}
pub fn select(mut self, selected: usize) -> Self {
self.selected = selected;
self
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn highlight_style(mut self, style: Style) -> Self {
self.highlight_style = style;
self
}
pub fn divider(mut self, divider: &'a str) -> Self {
self.divider = divider;
self
}
pub fn area(mut self, area: Rect) -> Self {
self.area = area;
self
}
}
impl<'a, T, MSG> Widget for Tabs<'a, T, MSG>
where
T: AsRef<str>,
MSG: 'static,
{
fn get_area(&self) -> Rect {
self.area
}
fn draw(&mut self, buf: &mut Buffer) {
let tabs_area = match self.block {
Some(ref mut b) => {
b.draw(buf);
b.inner()
}
None => self.area,
};
if tabs_area.height < 1 {
return;
}
self.background(buf, self.style.bg);
let mut x = tabs_area.left();
let titles_length = self.titles.len();
let divider_width = self.divider.width() as u16;
for (title, style, last_title) in self.titles.iter().enumerate().map(|(i, t)| {
let lt = i + 1 == titles_length;
if i == self.selected {
(t, self.highlight_style, lt)
} else {
(t, self.style, lt)
}
}) {
x += 1;
if x > tabs_area.right() {
break;
} else {
buf.set_string(x, tabs_area.top(), title.as_ref(), style);
x += title.as_ref().width() as u16 + 1;
if x >= tabs_area.right() || last_title {
break;
} else {
buf.set_string(x, tabs_area.top(), self.divider, self.style);
x += divider_width;
}
}
}
}
}