use crate::tui::component::{Action, Component, ComponentState}; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{KeyCode, KeyEvent}; use ratatui::layout::Rect; use ratatui::style::{Color, Style}; use ratatui::text::Line; use ratatui::widgets::{Block, Borders, Tabs, Widget}; use strum::{EnumIter, FromRepr, IntoEnumIterator}; #[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr, EnumIter)] enum TitleBarItem { File, Edit, View, Help, } impl TitleBarItem { pub fn next(mut self) -> Self { let cur = self as usize; let next = cur.saturating_add(1); Self::from_repr(next).unwrap_or(self) } pub fn prev(self) -> Self { let cur = self as usize; let prev = cur.saturating_sub(1); Self::from_repr(prev).unwrap_or(self) } pub fn id(&self) -> &str { match self { TitleBarItem::File => "File", TitleBarItem::Edit => "Edit", TitleBarItem::View => "View", TitleBarItem::Help => "Help", } } } pub struct TitleBar { selected: TitleBarItem, opened: Option, pub(crate) component_state: ComponentState, } impl TitleBar { pub fn new() -> Self { Self { selected: TitleBarItem::File, opened: None, component_state: ComponentState::default() .with_help_text(concat!("TODO: Title bar help text.").as_ref()), } } fn render_title_bar(&self, area: Rect, buf: &mut Buffer) { let titles: Vec = TitleBarItem::iter() .map(|item| Line::from(item.id().to_owned())) .collect(); let tabs_style = Style::default(); let highlight_style = if self.opened.is_some() { Style::default().bg(Color::Blue).fg(Color::White) } else { Style::default().bg(Color::Cyan).fg(Color::Black) }; Tabs::new(titles) .style(tabs_style) .block(Block::default().borders(Borders::ALL)) .highlight_style(highlight_style) .select(self.selected as usize) .render(area, buf); } } impl Widget for &TitleBar { fn render(self, area: Rect, buf: &mut Buffer) where Self: Sized, { let title_bar_area = Rect { x: area.x, y: area.y, width: area.width, height: 3, }; self.render_title_bar(title_bar_area, buf); } } impl Component for TitleBar { fn handle_key_events(&mut self, key: KeyEvent) -> anyhow::Result { match key.code { // KeyCode::Up | KeyCode::Char('k') => self.selected.key_up(), // KeyCode::Down | KeyCode::Char('j') => self.selected.key_down(), KeyCode::Left | KeyCode::Char('h') => { self.selected = self.selected.prev(); Ok(Action::Handled) } KeyCode::Right | KeyCode::Char('l') => { self.selected = self.selected.next(); Ok(Action::Handled) } KeyCode::Enter => { self.opened = Some(self.selected); Ok(Action::Handled) } _ => Ok(Action::Noop), } } }