use crate::interactive::{ widgets::{ Entries, EntriesProps, Footer, FooterProps, Header, HelpPane, HelpPaneProps, MarkPane, MarkPaneProps, COLOR_MARKED, }, AppState, DisplayOptions, FocussedPane, }; use dua::traverse::Traversal; use std::borrow::Borrow; use tui::{ buffer::Buffer, layout::{Constraint, Direction, Layout, Rect}, style::Modifier, style::{Color, Style}, }; use Constraint::*; use FocussedPane::*; pub struct MainWindowProps<'a> { pub traversal: &'a Traversal, pub display: DisplayOptions, pub state: &'a AppState, } #[derive(Default)] pub struct MainWindow { pub help_pane: Option, pub entries_pane: Entries, pub mark_pane: Option, } impl MainWindow { pub fn render<'a>( &mut self, props: impl Borrow>, area: Rect, buf: &mut Buffer, ) { let MainWindowProps { traversal: Traversal { tree, entries_traversed, total_bytes, .. }, display, state, } = props.borrow(); let (entries_style, help_style, mark_style) = { let grey = Style { fg: Color::DarkGray.into(), bg: Color::Reset.into(), add_modifier: Modifier::empty(), ..Style::default() }; let bold = Style { fg: Color::Rgb(230, 230, 230).into(), add_modifier: Modifier::BOLD, ..grey }; match state.focussed { Main => (bold, grey, grey), Help => (grey, bold, grey), Mark => (grey, grey, bold), } }; let (header_area, entries_area, footer_area) = { let regions = Layout::default() .direction(Direction::Vertical) .constraints([Length(1), Max(256), Length(1)].as_ref()) .split(area); (regions[0], regions[1], regions[2]) }; { let marked = self.mark_pane.as_ref().map(|p| p.marked()); let bg_color = match (marked.map_or(true, |m| m.is_empty()), state.focussed) { (false, FocussedPane::Mark) => Color::LightRed, (false, _) => COLOR_MARKED, (_, _) => Color::White, }; Header.render(bg_color, header_area, buf); } let (entries_area, help_pane, mark_pane) = { let regions = Layout::default() .direction(Direction::Horizontal) .constraints([Percentage(50), Percentage(50)].as_ref()) .split(entries_area); let (left_pane, right_pane) = (regions[0], regions[1]); match (&mut self.help_pane, &mut self.mark_pane) { (Some(ref mut pane), None) => (left_pane, Some((right_pane, pane)), None), (None, Some(ref mut pane)) => (left_pane, None, Some((right_pane, pane))), (Some(ref mut help), Some(ref mut mark)) => { let regions = Layout::default() .direction(Direction::Vertical) .constraints([Percentage(50), Percentage(50)].as_ref()) .split(right_pane); ( left_pane, Some((regions[0], help)), Some((regions[1], mark)), ) } (None, None) => (entries_area, None, None), } }; if let Some((mark_area, pane)) = mark_pane { let props = MarkPaneProps { border_style: mark_style, format: display.byte_format, }; pane.render(props, mark_area, buf); } if let Some((help_area, pane)) = help_pane { let props = HelpPaneProps { border_style: help_style, has_focus: matches!(state.focussed, Help), }; pane.render(props, help_area, buf); } let marked = self.mark_pane.as_ref().map(|p| p.marked()); let props = EntriesProps { tree: &tree, root: state.root, display: *display, entries: &state.entries, marked, selected: state.selected, border_style: entries_style, is_focussed: matches!(state.focussed, Main), }; self.entries_pane.render(props, entries_area, buf); Footer.render( FooterProps { total_bytes: *total_bytes, format: display.byte_format, entries_traversed: *entries_traversed, message: state.message.clone(), }, footer_area, buf, ); } }