use crate::interactive::CursorDirection; use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use termion::event::Key; use termion::event::Key::*; use tui::{ buffer::Buffer, layout::Rect, style::Color, style::{Modifier, Style}, widgets::{Block, Borders, Paragraph, Text, Widget}, }; #[derive(Default, Clone)] pub struct HelpPane { pub scroll: u16, } pub struct HelpPaneProps { pub border_style: Style, } impl HelpPane { pub fn key(&mut self, key: Key) { match key { Ctrl('u') | PageUp => self.scroll_help(CursorDirection::PageUp), Char('k') | Up => self.scroll_help(CursorDirection::Up), Char('j') | Down => self.scroll_help(CursorDirection::Down), Ctrl('d') | PageDown => self.scroll_help(CursorDirection::PageDown), _ => {} }; } fn scroll_help(&mut self, direction: CursorDirection) { self.scroll = direction.move_cursor(self.scroll as usize) as u16; } pub fn render(&mut self, props: impl Borrow, area: Rect, buf: &mut Buffer) { let (texts, num_lines) = { let num_lines = Cell::new(0u16); let count = |n| num_lines.set(num_lines.get() + n); let lines = RefCell::new(Vec::with_capacity(30)); let spacer = || { count(2); lines.borrow_mut().push(Text::Raw("\n\n".into())); }; let title = |name| { count(2); lines.borrow_mut().push(Text::Styled( format!("{}\n\n", name).into(), Style { modifier: Modifier::BOLD | Modifier::UNDERLINED, ..Default::default() }, )); }; let hotkey = |keys, description, other_line: Option<&str>| { let separator_size = 3; let column_size = 11 + separator_size; count(1 + other_line.iter().count() as u16); lines.borrow_mut().push(Text::Styled( format!( "{:>column_size$}", keys, column_size = column_size - separator_size ) .into(), Style { fg: Color::Green, ..Default::default() }, )); lines.borrow_mut().push(Text::Styled( format!(" => {}\n", description).into(), Style::default(), )); if let Some(second_line) = other_line { lines.borrow_mut().push(Text::Styled( format!( "{:>column_size$}{}\n", "", second_line, column_size = column_size + 1 ) .into(), Style::default(), )); } }; title("Keys for pane control"); { hotkey( "q/", "Close the current pane. Closes the program if no", Some("pane is open"), ); hotkey("", "Cycle between all open panes", None); hotkey("?", "Show or hide the help pane", None); spacer(); } title("Keys for Navigation"); { hotkey("j/", "move down an entry", None); hotkey("k/", "move up an entry", None); hotkey("o/", "descent into the selected directory", None); hotkey("", "^", None); hotkey( "u/", "ascent one level into the parent directory", None, ); hotkey("", "^", None); hotkey("Ctrl + d", "move down 10 entries at once", None); hotkey("", "^", None); hotkey("Ctrl + u", "move up 10 entries at once", None); hotkey("", "^", None); spacer(); } title("Keys for display"); { hotkey("s", "toggle sort by size ascending/descending", None); hotkey( "g", "cycle through percentage display and bar options", None, ); spacer(); } title("Keys for entry operations"); { hotkey( "Shift + o", "Open the entry with the associated program", None, ); hotkey( "d", "Toggle the currently selected entry and move down", None, ); hotkey("", "Toggle the currently selected entry", None); spacer(); } title("Keys in the Mark pane"); { hotkey("d/", "remove the selected entry from the list", None); hotkey( "Ctrl + r", "Permanently delete all marked entries without prompt!", Some("This operation cannot be undone!"), ); spacer(); } title("Keys for application control"); { hotkey( "Ctrl + c", "close the application. No questions asked!", None, ); spacer(); } (lines.into_inner(), num_lines.get()) }; let HelpPaneProps { border_style } = props.borrow(); let mut block = Block::default() .title("Help") .border_style(*border_style) .borders(Borders::ALL); block.draw(area, buf); let area = block.inner(area).inner(1); self.scroll = self.scroll.min(num_lines.saturating_sub(area.height)); Paragraph::new(texts.iter()) .scroll(self.scroll) .draw(area, buf); } }