use anyhow::bail;
use anyhow::Result;
use cursive::theme::Effect;
use cursive::vec::Vec2;
use cursive::Printer;
use cursive::View;
pub struct TabView {
pub tabs: Vec<String>,
pub current_selected: usize,
pub current_offset_idx: usize,
separator: String,
pub cur_length: usize,
pub cur_offset: usize,
pub total_length: usize,
pub fixed_tabs: usize,
}
impl View for TabView {
fn draw(&self, printer: &Printer) {
let mut current_offset = 0;
let mut current_offset_idx = self.current_offset_idx;
for idx in 0..self.tabs.len() {
if idx >= self.fixed_tabs && current_offset_idx > 0 {
current_offset_idx -= 1;
continue;
}
let content = self.tabs[idx].to_string();
if idx == self.current_selected {
let trimed = &content.trim_end();
printer.with_effects(Effect::Bold | Effect::Underline, |printer| {
printer.print((current_offset, 0), trimed);
});
printer.print_hline(
(current_offset + trimed.len(), 0),
content.len() - trimed.len(),
" ",
);
} else {
printer.print((current_offset, 0), &content);
}
current_offset += content.len();
printer.print((current_offset, 0), &self.separator);
current_offset += self.separator.len();
}
printer.print_hline((0, 1), printer.size.x, "─");
}
fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
Vec2::new(1, 2)
}
}
impl TabView {
pub fn new(tabs: Vec<String>, sep: &str, fixed_tabs: usize) -> Result<Self> {
if tabs.is_empty() {
bail!("Fail to construct TabView with empty tabs");
}
let total_length = tabs.iter().fold(0, |acc, x| acc + x.len() + 1);
let cur_length = tabs[0].len();
Ok(Self {
tabs,
current_selected: 0,
current_offset_idx: 0,
separator: sep.into(),
cur_length,
cur_offset: 0,
total_length,
fixed_tabs,
})
}
pub fn get_cur_selected(&self) -> &String {
&self.tabs[self.current_selected]
}
pub fn on_tab(&mut self) -> usize {
self.current_selected += 1;
self.current_selected %= self.tabs.len();
if self.current_selected == 0 {
self.cur_length = self.tabs[0].len();
} else {
self.cur_length += self.get_cur_selected().len() + 1;
}
self.cur_length
}
pub fn on_shift_tab(&mut self) -> usize {
if self.current_selected == 0 {
self.current_selected = self.tabs.len() - 1;
self.cur_length = self.total_length;
} else {
self.cur_length -= self.get_cur_selected().len() + 1;
self.current_selected -= 1;
}
self.cur_length
}
pub fn on_right(&mut self, screen_size: usize) -> usize {
if self.total_length - self.cur_offset <= screen_size {
return self.cur_offset;
}
self.current_offset_idx += 1;
self.cur_offset += self.tabs[self.current_offset_idx].len() + 1;
self.cur_offset
}
pub fn on_left(&mut self) -> usize {
if self.current_offset_idx == 0 {
return 0;
}
self.cur_offset -= self.tabs[self.current_offset_idx].len() + 1;
self.current_offset_idx -= 1;
self.cur_offset
}
pub fn scroll_to_offset(&mut self, offset: usize, screen_size: usize) -> usize {
self.cur_offset = 0;
self.current_offset_idx = 0;
if offset == 0 {
return 0;
}
while self.total_length - self.cur_offset > screen_size && self.cur_offset < offset {
self.on_right(screen_size);
}
self.cur_offset
}
}