summaryrefslogtreecommitdiffstats
path: root/src/term_manager.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/term_manager.rs')
-rw-r--r--src/term_manager.rs524
1 files changed, 315 insertions, 209 deletions
diff --git a/src/term_manager.rs b/src/term_manager.rs
index 918554f..25637e4 100644
--- a/src/term_manager.rs
+++ b/src/term_manager.rs
@@ -25,6 +25,21 @@ use crate::trash::TrashInfo;
/// At least 100 chars width to display 2 tabs.
pub const MIN_WIDTH_FOR_DUAL_PANE: usize = 100;
+const FIRST_LINE_COLORS: [Attr; 6] = [
+ color_to_attr(Color::Rgb(231, 162, 156)),
+ color_to_attr(Color::Rgb(144, 172, 186)),
+ color_to_attr(Color::Rgb(214, 125, 83)),
+ color_to_attr(Color::Rgb(91, 152, 119)),
+ color_to_attr(Color::Rgb(152, 87, 137)),
+ color_to_attr(Color::Rgb(230, 189, 87)),
+];
+
+const ATTR_YELLOW_BOLD: Attr = Attr {
+ fg: Color::YELLOW,
+ bg: Color::Default,
+ effect: Effect::BOLD,
+};
+
/// Simple struct to read the events.
pub struct EventReader {
term: Arc<Term>,
@@ -46,35 +61,23 @@ impl EventReader {
macro_rules! impl_preview {
($text:ident, $tab:ident, $length:ident, $canvas:ident, $line_number_width:ident) => {
for (i, line) in (*$text).window($tab.window.top, $tab.window.bottom, $length) {
- let row = Self::calc_line_row(i, $tab);
+ let row = calc_line_row(i, $tab);
$canvas.print(row, $line_number_width + 3, line)?;
}
};
}
-struct WinTab<'a> {
+struct WinMain<'a> {
status: &'a Status,
tab: &'a Tab,
disk_space: &'a str,
}
-impl<'a> Draw for WinTab<'a> {
+impl<'a> Draw for WinMain<'a> {
fn draw(&self, canvas: &mut dyn Canvas) -> DrawResult<()> {
+ canvas.clear()?;
match self.tab.mode {
- Mode::Navigate(Navigate::Jump) => self.destination(canvas, &self.status.flagged),
- Mode::Navigate(Navigate::History) => self.destination(canvas, &self.tab.history),
- Mode::Navigate(Navigate::Shortcut) => self.destination(canvas, &self.tab.shortcut),
- Mode::Navigate(Navigate::Trash) => self.trash(canvas, &self.status.trash),
- Mode::NeedConfirmation(confirmed_mode) => {
- self.confirmation(self.status, self.tab, confirmed_mode, canvas)
- }
- Mode::InputCompleted(_) => self.completion(self.tab, canvas),
Mode::Preview => self.preview(self.tab, canvas),
- Mode::InputSimple(InputSimple::Marks(_)) => self.marks(self.status, self.tab, canvas),
- Mode::InputSimple(InputSimple::Rename) => match self.tab.previous_mode {
- Mode::Tree => self.tree(self.status, self.tab, canvas),
- _ => self.files(self.status, self.tab, canvas),
- },
Mode::Tree => self.tree(self.status, self.tab, canvas),
Mode::Normal => self.files(self.status, self.tab, canvas),
_ => match self.tab.previous_mode {
@@ -82,39 +85,31 @@ impl<'a> Draw for WinTab<'a> {
_ => self.files(self.status, self.tab, canvas),
},
}?;
- self.cursor(self.tab, canvas)?;
self.first_line(self.tab, self.disk_space, canvas)?;
Ok(())
}
}
-impl<'a> Widget for WinTab<'a> {}
+impl<'a> Widget for WinMain<'a> {}
-impl<'a> WinTab<'a> {
- const EDIT_BOX_OFFSET: usize = 9;
- const SORT_CURSOR_OFFSET: usize = 37;
+impl<'a> WinMain<'a> {
const ATTR_LINE_NR: Attr = color_to_attr(Color::CYAN);
- const ATTR_YELLOW: Attr = color_to_attr(Color::YELLOW);
- const ATTR_YELLOW_BOLD: Attr = Attr {
- fg: Color::YELLOW,
- bg: Color::Default,
- effect: Effect::BOLD,
- };
- const FIRST_LINE_COLORS: [Attr; 6] = [
- color_to_attr(Color::Rgb(231, 162, 156)),
- color_to_attr(Color::Rgb(144, 172, 186)),
- color_to_attr(Color::Rgb(214, 125, 83)),
- color_to_attr(Color::Rgb(91, 152, 119)),
- color_to_attr(Color::Rgb(152, 87, 137)),
- color_to_attr(Color::Rgb(230, 189, 87)),
- ];
+
+ fn new(status: &'a Status, index: usize, disk_space: &'a str) -> Self {
+ Self {
+ status,
+ tab: &status.tabs[index],
+ disk_space,
+ }
+ }
+
/// Display the top line on terminal.
/// Its content depends on the mode.
/// In normal mode we display the path and number of files.
/// When a confirmation is needed we ask the user to input `'y'` or
/// something else.
fn first_line(&self, tab: &Tab, disk_space: &str, canvas: &mut dyn Canvas) -> FmResult<()> {
- self.draw_colored_strings(0, 0, self.create_first_row(tab, disk_space)?, canvas)
+ draw_colored_strings(0, 0, self.create_first_row(tab, disk_space)?, canvas)
}
fn second_line(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
@@ -134,7 +129,7 @@ impl<'a> WinTab<'a> {
}
}
Mode::InputSimple(InputSimple::Filter) => {
- canvas.print_with_attr(1, 0, FILTER_PRESENTATION, Self::ATTR_YELLOW_BOLD)?;
+ canvas.print_with_attr(1, 0, FILTER_PRESENTATION, ATTR_YELLOW_BOLD)?;
}
_ => (),
}
@@ -160,7 +155,7 @@ impl<'a> WinTab<'a> {
1,
0,
&format!("{}", &status.selected_non_mut().filter),
- Self::ATTR_YELLOW_BOLD,
+ ATTR_YELLOW_BOLD,
)?)
}
@@ -175,9 +170,6 @@ impl<'a> WinTab<'a> {
format!("{} ", &tab.path_content.git_string()?),
]
}
- Mode::NeedConfirmation(confirmed_action) => {
- vec![format!("{} (y/n)", confirmed_action)]
- }
Mode::Preview => match &tab.preview {
Preview::Text(text_content) => {
if matches!(text_content.kind, TextKind::HELP) {
@@ -191,18 +183,18 @@ impl<'a> WinTab<'a> {
}
_ => Self::default_preview_first_line(tab),
},
- Mode::InputSimple(InputSimple::Marks(MarkAction::Jump)) => {
- vec!["Jump to...".to_owned()]
- }
- Mode::InputSimple(InputSimple::Marks(MarkAction::New)) => {
- vec!["Save mark...".to_owned()]
- }
- _ => {
- vec![
- format!("{}", tab.mode.clone()),
- format!("{}", tab.input.string()),
- ]
- }
+ _ => match tab.previous_mode {
+ Mode::Normal | Mode::Tree => {
+ vec![
+ format!("{} ", tab.path_content.path.display()),
+ format!("{} files ", tab.path_content.true_len()),
+ format!("{} ", tab.path_content.used_space()),
+ format!("Avail: {} ", disk_space),
+ format!("{} ", &tab.path_content.git_string()?),
+ ]
+ }
+ _ => vec![],
+ },
};
Ok(first_row)
}
@@ -223,20 +215,6 @@ impl<'a> WinTab<'a> {
}
}
- fn draw_colored_strings(
- &self,
- row: usize,
- offset: usize,
- strings: Vec<String>,
- canvas: &mut dyn Canvas,
- ) -> FmResult<()> {
- let mut col = 0;
- for (text, attr) in std::iter::zip(strings.iter(), Self::FIRST_LINE_COLORS.iter().cycle()) {
- col += canvas.print_with_attr(row, offset + col, text, *attr)?;
- }
- Ok(())
- }
-
/// Displays the current directory content, one line per item like in
/// `ls -l`.
///
@@ -283,6 +261,174 @@ impl<'a> WinTab<'a> {
Ok(())
}
+ fn print_line_number(
+ row_position_in_canvas: usize,
+ line_number_to_print: usize,
+ canvas: &mut dyn Canvas,
+ ) -> FmResult<usize> {
+ Ok(canvas.print_with_attr(
+ row_position_in_canvas,
+ 0,
+ &line_number_to_print.to_string(),
+ Self::ATTR_LINE_NR,
+ )?)
+ }
+
+ /// Display a scrollable preview of a file.
+ /// Multiple modes are supported :
+ /// if the filename extension is recognized, the preview is highlighted,
+ /// if the file content is recognized as binary, an hex dump is previewed with 16 bytes lines,
+ /// else the content is supposed to be text and shown as such.
+ /// It may fail to recognize some usual extensions, notably `.toml`.
+ /// It may fail to recognize small files (< 1024 bytes).
+ fn preview(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ let length = tab.preview.len();
+ let line_number_width = length.to_string().len();
+ match &tab.preview {
+ Preview::Syntaxed(syntaxed) => {
+ for (i, vec_line) in (*syntaxed).window(tab.window.top, tab.window.bottom, length) {
+ let row_position = calc_line_row(i, tab);
+ Self::print_line_number(row_position, i + 1, canvas)?;
+ for token in vec_line.iter() {
+ token.print(canvas, row_position, line_number_width)?;
+ }
+ }
+ }
+ Preview::Binary(bin) => {
+ let line_number_width_hex = format!("{:x}", bin.len() * 16).len();
+
+ for (i, line) in (*bin).window(tab.window.top, tab.window.bottom, length) {
+ let row = calc_line_row(i, tab);
+
+ canvas.print_with_attr(
+ row,
+ 0,
+ &format_line_nr_hex(i + 1 + tab.window.top, line_number_width_hex),
+ Self::ATTR_LINE_NR,
+ )?;
+ line.print(canvas, row, line_number_width_hex + 1);
+ }
+ }
+ Preview::Thumbnail(image) => {
+ let (width, height) = canvas.size()?;
+
+ if let Ok(scaled_image) = (*image).resized_rgb8(width as u32 / 2, height as u32 - 3)
+ {
+ let (width, _) = scaled_image.dimensions();
+ for (i, pixel) in scaled_image.pixels().enumerate() {
+ let (r, g, b) = pixel_values(pixel);
+ let (row, col) = pixel_position(i, width);
+ print_pixel(canvas, row, col, r, g, b)?;
+ }
+ } else {
+ canvas.print(
+ 3,
+ 3,
+ &format!("Not a displayable image: {:?}", image.img_path),
+ )?;
+ }
+ }
+ Preview::Directory(directory) => {
+ for (i, (prefix, colored_string)) in
+ (directory).window(tab.window.top, tab.window.bottom, length)
+ {
+ let row = calc_line_row(i, tab);
+ let col = canvas.print(row, line_number_width, prefix)?;
+ canvas.print_with_attr(
+ row,
+ line_number_width + col + 1,
+ &colored_string.text,
+ colored_string.attr,
+ )?;
+ }
+ }
+ Preview::Archive(text) => impl_preview!(text, tab, length, canvas, line_number_width),
+ Preview::Exif(text) => impl_preview!(text, tab, length, canvas, line_number_width),
+ Preview::Media(text) => impl_preview!(text, tab, length, canvas, line_number_width),
+ Preview::Pdf(text) => impl_preview!(text, tab, length, canvas, line_number_width),
+ Preview::Text(text) => impl_preview!(text, tab, length, canvas, line_number_width),
+
+ Preview::Empty => (),
+ }
+ Ok(())
+ }
+}
+
+struct WinSecondary<'a> {
+ status: &'a Status,
+ tab: &'a Tab,
+}
+impl<'a> Draw for WinSecondary<'a> {
+ fn draw(&self, canvas: &mut dyn Canvas) -> DrawResult<()> {
+ canvas.clear()?;
+ match self.tab.mode {
+ Mode::Navigate(Navigate::Jump) => self.destination(canvas, &self.status.flagged),
+ Mode::Navigate(Navigate::History) => self.destination(canvas, &self.tab.history),
+ Mode::Navigate(Navigate::Shortcut) => self.destination(canvas, &self.tab.shortcut),
+ Mode::Navigate(Navigate::Trash) => self.trash(canvas, &self.status.trash),
+ Mode::NeedConfirmation(confirmed_mode) => {
+ self.confirmation(self.status, self.tab, confirmed_mode, canvas)
+ }
+ Mode::InputCompleted(_) => self.completion(self.tab, canvas),
+ Mode::InputSimple(InputSimple::Marks(_)) => self.marks(self.status, self.tab, canvas),
+ _ => Ok(()),
+ }?;
+ self.cursor(self.tab, canvas)?;
+ self.first_line(self.tab, canvas)?;
+ Ok(())
+ }
+}
+
+impl<'a> WinSecondary<'a> {
+ const EDIT_BOX_OFFSET: usize = 9;
+ const ATTR_YELLOW: Attr = color_to_attr(Color::YELLOW);
+ const SORT_CURSOR_OFFSET: usize = 37;
+
+ fn new(status: &'a Status, index: usize) -> Self {
+ Self {
+ status,
+ tab: &status.tabs[index],
+ }
+ }
+
+ fn first_line(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ draw_colored_strings(0, 0, self.create_first_row(tab)?, canvas)
+ }
+
+ fn create_first_row(&self, tab: &Tab) -> FmResult<Vec<String>> {
+ let first_row = match tab.mode {
+ Mode::NeedConfirmation(confirmed_action) => {
+ vec![format!("{} (y/n)", confirmed_action)]
+ }
+ Mode::InputSimple(InputSimple::Marks(MarkAction::Jump)) => {
+ vec!["Jump to...".to_owned()]
+ }
+ Mode::InputSimple(InputSimple::Marks(MarkAction::New)) => {
+ vec!["Save mark...".to_owned()]
+ }
+ _ => {
+ vec![
+ format!("{}", tab.mode.clone()),
+ format!("{}", tab.input.string()),
+ ]
+ }
+ };
+ Ok(first_row)
+ }
+
+ /// Display the possible completion items. The currently selected one is
+ /// reversed.
+ fn completion(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ canvas.set_cursor(0, tab.input.cursor_index + Self::EDIT_BOX_OFFSET)?;
+ for (row, candidate) in tab.completion.proposals.iter().enumerate() {
+ let mut attr = Attr::default();
+ if row == tab.completion.index {
+ attr.effect |= Effect::REVERSE;
+ }
+ canvas.print_with_attr(row + ContentWindow::WINDOW_MARGIN_TOP, 4, candidate, attr)?;
+ }
+ Ok(())
+ }
/// Display a cursor in the top row, at a correct column.
fn cursor(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
match tab.mode {
@@ -294,6 +440,7 @@ impl<'a> WinTab<'a> {
canvas.show_cursor(false)?;
}
Mode::InputSimple(InputSimple::Sort) => {
+ canvas.show_cursor(true)?;
canvas.set_cursor(0, Self::SORT_CURSOR_OFFSET)?;
}
Mode::InputSimple(_) | Mode::InputCompleted(_) => {
@@ -301,6 +448,7 @@ impl<'a> WinTab<'a> {
canvas.set_cursor(0, tab.input.cursor_index + Self::EDIT_BOX_OFFSET)?;
}
Mode::NeedConfirmation(confirmed_action) => {
+ canvas.show_cursor(true)?;
canvas.set_cursor(0, confirmed_action.cursor_offset())?;
}
}
@@ -352,16 +500,12 @@ impl<'a> WinTab<'a> {
Ok(())
}
- /// Display the possible completion items. The currently selected one is
- /// reversed.
- fn completion(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
- canvas.set_cursor(0, tab.input.cursor_index + Self::EDIT_BOX_OFFSET)?;
- for (row, candidate) in tab.completion.proposals.iter().enumerate() {
- let mut attr = Attr::default();
- if row == tab.completion.index {
- attr.effect |= Effect::REVERSE;
- }
- canvas.print_with_attr(row + ContentWindow::WINDOW_MARGIN_TOP, 4, candidate, attr)?;
+ fn marks(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ canvas.print_with_attr(2, 1, "mark path", Self::ATTR_YELLOW)?;
+
+ for (i, line) in status.marks.as_strings().iter().enumerate() {
+ let row = calc_line_row(i, tab) + 2;
+ canvas.print(row, 3, line)?;
}
Ok(())
}
@@ -411,118 +555,14 @@ impl<'a> WinTab<'a> {
}
NeedConfirmation::EmptyTrash => "Trash will be emptied".to_owned(),
};
- canvas.print_with_attr(2, 3, &confirmation_string, Self::ATTR_YELLOW_BOLD)?;
+ canvas.print_with_attr(2, 3, &confirmation_string, ATTR_YELLOW_BOLD)?;
Ok(())
}
-
- fn print_line_number(
- row_position_in_canvas: usize,
- line_number_to_print: usize,
- canvas: &mut dyn Canvas,
- ) -> FmResult<usize> {
- Ok(canvas.print_with_attr(
- row_position_in_canvas,
- 0,
- &line_number_to_print.to_string(),
- Self::ATTR_LINE_NR,
- )?)
- }
-
- /// Display a scrollable preview of a file.
- /// Multiple modes are supported :
- /// if the filename extension is recognized, the preview is highlighted,
- /// if the file content is recognized as binary, an hex dump is previewed with 16 bytes lines,
- /// else the content is supposed to be text and shown as such.
- /// It may fail to recognize some usual extensions, notably `.toml`.
- /// It may fail to recognize small files (< 1024 bytes).
- fn preview(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
- let length = tab.preview.len();
- let line_number_width = length.to_string().len();
- match &tab.preview {
- Preview::Syntaxed(syntaxed) => {
- for (i, vec_line) in (*syntaxed).window(tab.window.top, tab.window.bottom, length) {
- let row_position = Self::calc_line_row(i, tab);
- Self::print_line_number(row_position, i + 1, canvas)?;
- for token in vec_line.iter() {
- token.print(canvas, row_position, line_number_width)?;
- }
- }
- }
- Preview::Binary(bin) => {
- let line_number_width_hex = format!("{:x}", bin.len() * 16).len();
-
- for (i, line) in (*bin).window(tab.window.top, tab.window.bottom, length) {
- let row = Self::calc_line_row(i, tab);
-
- canvas.print_with_attr(
- row,
- 0,
- &format_line_nr_hex(i + 1 + tab.window.top, line_number_width_hex),
- Self::ATTR_LINE_NR,
- )?;
- line.print(canvas, row, line_number_width_hex + 1);
- }
- }
- Preview::Thumbnail(image) => {
- let (width, height) = canvas.size()?;
-
- if let Ok(scaled_image) = (*image).resized_rgb8(width as u32 / 2, height as u32 - 3)
- {
- let (width, _) = scaled_image.dimensions();
- for (i, pixel) in scaled_image.pixels().enumerate() {
- let (r, g, b) = pixel_values(pixel);
- let (row, col) = pixel_position(i, width);
- print_pixel(canvas, row, col, r, g, b)?;
- }
- } else {
- canvas.print(
- 3,
- 3,
- &format!("Not a displayable image: {:?}", image.img_path),
- )?;
- }
- }
- Preview::Directory(directory) => {
- for (i, (prefix, colored_string)) in
- (directory).window(tab.window.top, tab.window.bottom, length)
- {
- let row = Self::calc_line_row(i, tab);
- let col = canvas.print(row, line_number_width, prefix)?;
- canvas.print_with_attr(
- row,
- line_number_width + col + 1,
- &colored_string.text,
- colored_string.attr,
- )?;
- }
- }
- Preview::Archive(text) => impl_preview!(text, tab, length, canvas, line_number_width),
- Preview::Exif(text) => impl_preview!(text, tab, length, canvas, line_number_width),
- Preview::Media(text) => impl_preview!(text, tab, length, canvas, line_number_width),
- Preview::Pdf(text) => impl_preview!(text, tab, length, canvas, line_number_width),
- Preview::Text(text) => impl_preview!(text, tab, length, canvas, line_number_width),
-
- Preview::Empty => (),
- }
- Ok(())
- }
-
- fn marks(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
- canvas.print_with_attr(2, 1, "mark path", Self::ATTR_YELLOW)?;
-
- for (i, line) in status.marks.as_strings().iter().enumerate() {
- let row = Self::calc_line_row(i, tab) + 2;
- canvas.print(row, 3, line)?;
- }
- Ok(())
- }
-
- fn calc_line_row(i: usize, tab: &Tab) -> usize {
- i + ContentWindow::WINDOW_MARGIN_TOP - tab.window.top
- }
}
+impl<'a> Widget for WinSecondary<'a> {}
+
/// Is responsible for displaying content in the terminal.
/// It uses an already created terminal.
pub struct Display {
@@ -547,6 +587,11 @@ impl Display {
Ok(self.term.show_cursor(true)?)
}
+ fn hide_cursor(&self) -> FmResult<()> {
+ self.term.set_cursor(0, 0)?;
+ Ok(self.term.show_cursor(false)?)
+ }
+
/// Display every possible content in the terminal.
///
/// The top line
@@ -565,6 +610,7 @@ impl Display {
/// Displays one pane or two panes, depending of the width and current
/// status of the application.
pub fn display_all(&mut self, status: &Status) -> FmResult<()> {
+ self.hide_cursor()?;
self.term.clear()?;
let (width, _) = self.term.term_size()?;
@@ -578,42 +624,85 @@ impl Display {
Ok(self.term.present()?)
}
+ fn size_for_second_window(&self, tab: &Tab) -> FmResult<usize> {
+ if tab.need_second_window() {
+ Ok(self.height()? / 2)
+ } else {
+ Ok(0)
+ }
+ }
+
+ fn vertical_split<'a>(
+ &self,
+ win_main: &'a WinMain,
+ win_secondary: &'a WinSecondary,
+ border: Attr,
+ size: usize,
+ ) -> FmResult<VSplit<'a>> {
+ Ok(VSplit::default()
+ .split(
+ Win::new(win_main)
+ .basis(self.height()? - size)
+ .shrink(4)
+ .border(true)
+ .border_attr(border),
+ )
+ .split(
+ Win::new(win_secondary)
+ .basis(size)
+ .shrink(0)
+ .border(true)
+ .border_attr(border),
+ ))
+ }
+
+ fn borders(&self, status: &Status) -> (Attr, Attr) {
+ if status.index == 0 {
+ (Self::SELECTED_BORDER, Self::INERT_BORDER)
+ } else {
+ (Self::INERT_BORDER, Self::SELECTED_BORDER)
+ }
+ }
+
fn draw_dual_pane(
&mut self,
status: &Status,
disk_space_tab_0: &str,
disk_space_tab_1: &str,
) -> FmResult<()> {
- let win_left = WinTab {
- status,
- tab: &status.tabs[0],
- disk_space: disk_space_tab_0,
- };
- let win_right = WinTab {
- status,
- tab: &status.tabs[1],
- disk_space: disk_space_tab_1,
- };
- let (left_border, right_border) = if status.index == 0 {
- (Self::SELECTED_BORDER, Self::INERT_BORDER)
- } else {
- (Self::INERT_BORDER, Self::SELECTED_BORDER)
- };
+ let win_main_left = WinMain::new(status, 0, disk_space_tab_0);
+ let win_main_right = WinMain::new(status, 1, disk_space_tab_1);
+ let win_second_left = WinSecondary::new(status, 0);
+ let win_second_right = WinSecondary::new(status, 1);
+ let (border_left, border_right) = self.borders(status);
+ let percent_left = self.size_for_second_window(&status.tabs[0])?;
+ let percent_right = self.size_for_second_window(&status.tabs[1])?;
let hsplit = HSplit::default()
- .split(Win::new(&win_left).border(true).border_attr(left_border))
- .split(Win::new(&win_right).border(true).border_attr(right_border));
+ .split(self.vertical_split(
+ &win_main_left,
+ &win_second_left,
+ border_left,
+ percent_left,
+ )?)
+ .split(self.vertical_split(
+ &win_main_right,
+ &win_second_right,
+ border_right,
+ percent_right,
+ )?);
Ok(self.term.draw(&hsplit)?)
}
fn draw_single_pane(&mut self, status: &Status, disk_space_tab_0: &str) -> FmResult<()> {
- let win_left = WinTab {
- status,
- tab: &status.tabs[0],
- disk_space: disk_space_tab_0,
- };
- let win = Win::new(&win_left)
- .border(true)
- .border_attr(Self::SELECTED_BORDER);
+ let win_main_left = WinMain::new(status, 0, disk_space_tab_0);
+ let win_second_left = WinSecondary::new(status, 0);
+ let percent_left = self.size_for_second_window(&status.tabs[0])?;
+ let win = self.vertical_split(
+ &win_main_left,
+ &win_second_left,
+ Self::SELECTED_BORDER,
+ percent_left,
+ )?;
Ok(self.term.draw(&win)?)
}
@@ -647,6 +736,23 @@ const fn pixel_position(i: usize, width: u32) -> (usize, usize) {
(row, col)
}
+fn draw_colored_strings(
+ row: usize,
+ offset: usize,
+ strings: Vec<String>,
+ canvas: &mut dyn Canvas,
+) -> FmResult<()> {
+ let mut col = 0;
+ for (text, attr) in std::iter::zip(strings.iter(), FIRST_LINE_COLORS.iter().cycle()) {
+ col += canvas.print_with_attr(row, offset + col, text, *attr)?;
+ }
+ Ok(())
+}
+
+fn calc_line_row(i: usize, tab: &Tab) -> usize {
+ i + ContentWindow::WINDOW_MARGIN_TOP - tab.window.top
+}
+
fn print_pixel(
canvas: &mut dyn Canvas,
row: usize,