diff options
Diffstat (limited to 'src/ui/views/tui_hsplit_view.rs')
-rw-r--r-- | src/ui/views/tui_hsplit_view.rs | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/ui/views/tui_hsplit_view.rs b/src/ui/views/tui_hsplit_view.rs new file mode 100644 index 0000000..015ca5a --- /dev/null +++ b/src/ui/views/tui_hsplit_view.rs @@ -0,0 +1,195 @@ +use tui::buffer::Buffer; +use tui::layout::{Constraint, Direction, Layout, Rect}; +use tui::style::{Color, Style}; +use tui::text::Span; +use tui::widgets::{Block, Borders, Paragraph, Widget, Wrap}; + +use crate::context::AppContext; +use crate::ui::widgets::{TuiDirListDetailed, TuiFooter, TuiTabBar, TuiTopBar}; + +const TAB_VIEW_WIDTH: u16 = 15; + +pub struct TuiHSplitView<'a> { + pub context: &'a AppContext, + pub show_bottom_status: bool, +} + +impl<'a> TuiHSplitView<'a> { + pub fn new(context: &'a AppContext) -> Self { + Self { + context, + show_bottom_status: true, + } + } +} + +impl<'a> Widget for TuiHSplitView<'a> { + fn render(self, area: Rect, buf: &mut Buffer) { + let tab_context = self.context.tab_context_ref(); + let tab_index = tab_context.index; + + let config = self.context.config_ref(); + let display_options = config.display_options_ref(); + let constraints = &[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]; + + let layout_rect = if display_options.show_borders() { + let area = Rect { + y: area.top() + 1, + height: area.height - 2, + ..area + }; + + let layout = calculate_layout_with_borders(area, constraints); + + let block = Block::default().borders(Borders::ALL); + let inner = block.inner(area); + block.render(area, buf); + + let layout_rect = Layout::default() + .direction(Direction::Horizontal) + .constraints(constraints.as_ref()) + .split(inner); + + let block = Block::default().borders(Borders::RIGHT); + block.render(layout_rect[0], buf); + + let block = Block::default().borders(Borders::LEFT); + block.render(layout_rect[1], buf); + + layout + } else { + let area = Rect { + y: area.top() + 1, + height: area.height - 2, + ..area + }; + calculate_layout(area, constraints) + }; + + if let Some(curr_tab) = tab_context.tab_ref(tab_index) { + let curr_list = curr_tab.curr_list_ref(); + + let layout_rect = if tab_index % 2 == 0 { + layout_rect[0] + } else { + layout_rect[1] + }; + + // render current view + if let Some(list) = curr_list.as_ref() { + TuiDirListDetailed::new(list, display_options, true).render(layout_rect, buf); + let rect = Rect { + x: 0, + y: area.height - 1, + width: area.width, + height: 1, + }; + + if self.show_bottom_status { + /* draw the bottom status bar */ + if let Some(msg) = self.context.worker_context_ref().get_msg() { + let message_style = Style::default().fg(Color::Yellow); + let text = Span::styled(msg, message_style); + Paragraph::new(text) + .wrap(Wrap { trim: true }) + .render(rect, buf); + } else if let Some(msg) = self.context.message_queue_ref().current_message() { + let text = Span::styled(msg.content.as_str(), msg.style); + Paragraph::new(text) + .wrap(Wrap { trim: true }) + .render(rect, buf); + } else { + TuiFooter::new(list).render(rect, buf); + } + } + } + + let topbar_width = area.width; + let rect = Rect { + x: 0, + y: 0, + width: topbar_width, + height: 1, + }; + TuiTopBar::new(self.context, curr_tab.cwd()).render(rect, buf); + + // render tabs + if self.context.tab_context_ref().len() > 1 { + let topbar_width = area.width.saturating_sub(TAB_VIEW_WIDTH); + + let rect = Rect { + x: topbar_width, + y: 0, + width: TAB_VIEW_WIDTH, + height: 1, + }; + let name = if let Some(ostr) = curr_tab.cwd().file_name() { + ostr.to_str().unwrap_or("") + } else { + "" + }; + TuiTabBar::new( + name, + self.context.tab_context_ref().index, + self.context.tab_context_ref().len(), + ) + .render(rect, buf); + } + } + + let other_tab_index = if tab_index % 2 == 0 { + tab_index + 1 + } else { + tab_index - 1 + }; + + if let Some(curr_tab) = tab_context.tab_ref(other_tab_index) { + let curr_list = curr_tab.curr_list_ref(); + + let layout_rect = if other_tab_index % 2 == 0 { + layout_rect[0] + } else { + layout_rect[1] + }; + + if let Some(list) = curr_list.as_ref() { + TuiDirListDetailed::new(list, display_options, false).render(layout_rect, buf); + } + } + } +} + +fn calculate_layout(area: Rect, constraints: &[Constraint; 2]) -> Vec<Rect> { + let mut layout_rect = Layout::default() + .direction(Direction::Horizontal) + .constraints(constraints.as_ref()) + .split(area); + + layout_rect[0] = Rect { + width: layout_rect[0].width - 1, + ..layout_rect[0] + }; + layout_rect[1] = Rect { + width: layout_rect[1].width - 1, + ..layout_rect[1] + }; + layout_rect +} + +fn calculate_layout_with_borders(area: Rect, constraints: &[Constraint; 2]) -> Vec<Rect> { + let block = Block::default().borders(Borders::ALL); + let inner = block.inner(area); + + let layout_rect = Layout::default() + .direction(Direction::Horizontal) + .constraints(constraints.as_ref()) + .split(inner); + + let block = Block::default().borders(Borders::RIGHT); + let inner1 = block.inner(layout_rect[0]); + + let block = Block::default().borders(Borders::LEFT); + let inner2 = block.inner(layout_rect[1]); + + vec![inner1, inner2] +} |