diff options
author | Jeff Zhao <jeff.no.zhao@gmail.com> | 2021-12-20 21:40:14 -0500 |
---|---|---|
committer | Jeff Zhao <jeff.no.zhao@gmail.com> | 2021-12-20 21:41:32 -0500 |
commit | ee3650945abccd28063a237ef4d7ec21a3a6ddbb (patch) | |
tree | 266c1b60b876d0dbe3dd1c44cfbafc1da6a74028 /src/ui | |
parent | 1d9986a2b3d3f849ac0288fb7135d3e938d72cf5 (diff) |
refactor image preview via ueberzug
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/mod.rs | 11 | ||||
-rw-r--r-- | src/ui/tui_backend.rs | 4 | ||||
-rw-r--r-- | src/ui/views/mod.rs | 2 | ||||
-rw-r--r-- | src/ui/views/tui_command_menu.rs | 4 | ||||
-rw-r--r-- | src/ui/views/tui_folder_view.rs | 202 | ||||
-rw-r--r-- | src/ui/views/tui_textfield.rs | 4 | ||||
-rw-r--r-- | src/ui/views/tui_view.rs | 7 | ||||
-rw-r--r-- | src/ui/widgets/tui_file_preview.rs | 6 | ||||
-rw-r--r-- | src/ui/widgets/tui_prompt.rs | 4 |
9 files changed, 152 insertions, 92 deletions
diff --git a/src/ui/mod.rs b/src/ui/mod.rs index b782b1f..4580c0b 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -14,16 +14,17 @@ pub struct Rect { pub height: u16, } +#[derive(Debug, Clone)] pub struct RenderResult { - pub file_preview_path: Option<path::PathBuf>, - pub preview_area: Option<Rect>, + pub file_preview_path: path::PathBuf, + pub preview_area: Rect, } impl RenderResult { - pub fn new() -> RenderResult { + pub fn new(file_preview_path: path::PathBuf, preview_area: Rect) -> RenderResult { RenderResult { - file_preview_path: None, - preview_area: None, + file_preview_path, + preview_area, } } } diff --git a/src/ui/tui_backend.rs b/src/ui/tui_backend.rs index dc15f03..52afba4 100644 --- a/src/ui/tui_backend.rs +++ b/src/ui/tui_backend.rs @@ -69,6 +69,10 @@ impl TuiBackend { }); } + pub fn terminal_ref(&self) -> &JoshutoTerminal { + self.terminal.as_ref().unwrap() + } + pub fn terminal_mut(&mut self) -> &mut JoshutoTerminal { self.terminal.as_mut().unwrap() } diff --git a/src/ui/views/mod.rs b/src/ui/views/mod.rs index 70517cf..6af230c 100644 --- a/src/ui/views/mod.rs +++ b/src/ui/views/mod.rs @@ -5,7 +5,7 @@ mod tui_view; mod tui_worker_view; pub use self::tui_command_menu::TuiCommandMenu; -pub use self::tui_folder_view::TuiFolderView; +pub use self::tui_folder_view::*; pub use self::tui_textfield::TuiTextField; pub use self::tui_view::TuiView; pub use self::tui_worker_view::TuiWorkerView; diff --git a/src/ui/views/tui_command_menu.rs b/src/ui/views/tui_command_menu.rs index d62fa09..bc94752 100644 --- a/src/ui/views/tui_command_menu.rs +++ b/src/ui/views/tui_command_menu.rs @@ -8,7 +8,6 @@ use crate::config::AppKeyMapping; use crate::context::AppContext; use crate::ui::views::TuiView; use crate::ui::widgets::TuiMenu; -use crate::ui::RenderResult; use crate::util::to_string::ToString; const BORDER_HEIGHT: usize = 1; @@ -27,8 +26,7 @@ impl<'a> TuiCommandMenu<'a> { impl<'a> Widget for TuiCommandMenu<'a> { fn render(self, area: Rect, buf: &mut Buffer) { - let mut render_result = RenderResult::new(); - TuiView::new(self.context, &mut render_result).render(area, buf); + TuiView::new(self.context).render(area, buf); // draw menu let mut display_vec: Vec<String> = self diff --git a/src/ui/views/tui_folder_view.rs b/src/ui/views/tui_folder_view.rs index 1a07ce0..d019327 100644 --- a/src/ui/views/tui_folder_view.rs +++ b/src/ui/views/tui_folder_view.rs @@ -1,5 +1,3 @@ -use std::path; - use tui::buffer::Buffer; use tui::layout::{Constraint, Direction, Layout, Rect}; use tui::style::{Color, Style}; @@ -19,15 +17,13 @@ const TAB_VIEW_WIDTH: u16 = 15; pub struct TuiFolderView<'a> { pub context: &'a AppContext, pub show_bottom_status: bool, - pub render_result: &'a mut RenderResult, } impl<'a> TuiFolderView<'a> { - pub fn new(context: &'a AppContext, render_result: &'a mut RenderResult) -> Self { + pub fn new(context: &'a AppContext) -> Self { Self { context, show_bottom_status: true, - render_result, } } } @@ -45,25 +41,11 @@ impl<'a> Widget for TuiFolderView<'a> { let config = self.context.config_ref(); let display_options = config.display_options_ref(); - let (default_layout, constraints): (bool, &[Constraint; 3]) = - if !display_options.collapse_preview() { - (true, &display_options.default_layout) - } else { - match child_list { - Some(_) => (true, &display_options.default_layout), - None => match curr_entry { - None => (false, &display_options.no_preview_layout), - Some(e) => match preview_context.get_preview_ref(e.file_path()) { - Some(Some(p)) if p.status.code() != Some(1) => { - (true, &display_options.default_layout) - } - _ => (false, &display_options.no_preview_layout), - }, - }, - } - }; + let constraints = get_constraints(self.context); + let is_default_layout = constraints == &display_options.default_layout; - let layout_rect = if config.display_options_ref().show_borders() { + let layout_rect = if display_options.show_borders() { + let layout = calculate_layout_with_borders(area, constraints); let area = Rect { y: area.top() + 1, height: area.height - 2, @@ -79,6 +61,12 @@ impl<'a> Widget for TuiFolderView<'a> { .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[2], buf); + // Render inner borders properly. { let top = area.top(); @@ -97,36 +85,18 @@ impl<'a> Widget for TuiFolderView<'a> { Constraint::Ratio(0, _) => (), _ => intersections.render_left(buf), } - if default_layout { + if is_default_layout { intersections.render_right(buf); } } - - let block = Block::default().borders(Borders::RIGHT); - let inner1 = block.inner(layout_rect[0]); - block.render(layout_rect[0], buf); - - let block = Block::default().borders(Borders::LEFT); - let inner3 = block.inner(layout_rect[2]); - block.render(layout_rect[2], buf); - - vec![inner1, layout_rect[1], inner3] + layout } else { - let mut layout_rect = Layout::default() - .direction(Direction::Horizontal) - .vertical_margin(1) - .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] + let area = Rect { + y: area.top() + 1, + height: area.height - 2, + ..area }; - layout_rect + calculate_layout(area, constraints) }; // render parent view @@ -168,31 +138,24 @@ impl<'a> Widget for TuiFolderView<'a> { } } - // render preview - let mut file_preview_path: Option<path::PathBuf> = None; - let mut preview_area: Option<ui::Rect> = None; if let Some(list) = child_list.as_ref() { TuiDirList::new(list).render(layout_rect[2], buf); - } else if let Some(entry) = curr_entry { - if let Some(Some(preview)) = preview_context.get_preview_ref(entry.file_path()) { - match preview.status.code() { - Some(1) | None => {} - _ => { - let rect = layout_rect[2]; - TuiFilePreview::new(entry, preview).render(rect, buf); - file_preview_path = Some(entry.file_path_buf()); - preview_area = Some(ui::Rect { - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height, - }) - } + } else if curr_entry.is_some() { + let render_result = calculate_preview(self.context, layout_rect[2]); + if let Some(render_result) = render_result { + let area = Rect { + x: render_result.preview_area.x, + y: render_result.preview_area.y, + width: render_result.preview_area.width, + height: render_result.preview_area.height, + }; + if let Some(Some(preview)) = + preview_context.get_preview_ref(&render_result.file_preview_path) + { + TuiFilePreview::new(preview).render(area, buf); } } } - self.render_result.file_preview_path = file_preview_path; - self.render_result.preview_area = preview_area; let topbar_width = area.width; let rect = Rect { @@ -252,3 +215,106 @@ impl Intersections { .set_symbol(HORIZONTAL_UP); } } + +pub fn get_constraints(context: &AppContext) -> &[Constraint; 3] { + let preview_context = context.preview_context_ref(); + let curr_tab = context.tab_context_ref().curr_tab_ref(); + + let curr_list = curr_tab.curr_list_ref(); + let curr_entry = curr_list.and_then(|c| c.curr_entry_ref()); + + let child_list = curr_tab.child_list_ref(); + + let config = context.config_ref(); + let display_options = config.display_options_ref(); + + if !display_options.collapse_preview() { + &display_options.default_layout + } else { + match child_list { + Some(_) => &display_options.default_layout, + None => match curr_entry { + None => &display_options.no_preview_layout, + Some(e) => match preview_context.get_preview_ref(e.file_path()) { + Some(Some(p)) if p.status.code() != Some(1) => &display_options.default_layout, + _ => &display_options.no_preview_layout, + }, + }, + } + } +} + +pub fn calculate_layout(area: Rect, constraints: &[Constraint; 3]) -> 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 +} + +pub fn calculate_layout_with_borders(area: Rect, constraints: &[Constraint; 3]) -> Vec<Rect> { + let area = Rect { + y: area.top() + 1, + height: area.height - 2, + ..area + }; + + 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 inner3 = block.inner(layout_rect[2]); + + vec![inner1, layout_rect[1], inner3] +} + +pub fn calculate_preview(context: &AppContext, rect: Rect) -> Option<RenderResult> { + let preview_context = context.preview_context_ref(); + let curr_tab = context.tab_context_ref().curr_tab_ref(); + + let child_list = curr_tab.child_list_ref(); + + let curr_list = curr_tab.curr_list_ref(); + let curr_entry = curr_list.and_then(|c| c.curr_entry_ref()); + + if child_list.as_ref().is_some() { + None + } else if let Some(entry) = curr_entry { + if let Some(Some(preview)) = preview_context.get_preview_ref(entry.file_path()) { + match preview.status.code() { + Some(1) | None => None, + _ => { + let file_preview_path = entry.file_path_buf(); + let preview_area = ui::Rect { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + }; + Some(RenderResult::new(file_preview_path, preview_area)) + } + } + } else { + None + } + } else { + None + } +} diff --git a/src/ui/views/tui_textfield.rs b/src/ui/views/tui_textfield.rs index b9426db..d829852 100644 --- a/src/ui/views/tui_textfield.rs +++ b/src/ui/views/tui_textfield.rs @@ -10,7 +10,6 @@ use crate::context::AppContext; use crate::event::AppEvent; use crate::ui::views::TuiView; use crate::ui::widgets::{TuiMenu, TuiMultilineText}; -use crate::ui::RenderResult; use crate::ui::TuiBackend; use crate::util::input; @@ -97,8 +96,7 @@ impl<'a> TuiTextField<'a> { return; } { - let mut render_result = RenderResult::new(); - let mut view = TuiView::new(context, &mut render_result); + let mut view = TuiView::new(context); view.show_bottom_status = false; frame.render_widget(view, area); } diff --git a/src/ui/views/tui_view.rs b/src/ui/views/tui_view.rs index a5f093c..2178475 100644 --- a/src/ui/views/tui_view.rs +++ b/src/ui/views/tui_view.rs @@ -4,26 +4,23 @@ use tui::widgets::Widget; use super::TuiFolderView; use crate::context::AppContext; -use crate::ui::RenderResult; pub struct TuiView<'a> { pub context: &'a AppContext, pub show_bottom_status: bool, - pub render_result: &'a mut RenderResult, } impl<'a> TuiView<'a> { - pub fn new(context: &'a AppContext, render_result: &'a mut RenderResult) -> Self { + pub fn new(context: &'a AppContext) -> Self { Self { context, show_bottom_status: true, - render_result, } } } impl<'a> Widget for TuiView<'a> { fn render(self, area: Rect, buf: &mut Buffer) { - TuiFolderView::new(self.context, self.render_result).render(area, buf); + TuiFolderView::new(self.context).render(area, buf); } } diff --git a/src/ui/widgets/tui_file_preview.rs b/src/ui/widgets/tui_file_preview.rs index cfd6812..de0d3ec 100644 --- a/src/ui/widgets/tui_file_preview.rs +++ b/src/ui/widgets/tui_file_preview.rs @@ -4,17 +4,15 @@ use tui::layout::Rect; use tui::text::Text; use tui::widgets::Widget; -use crate::fs::JoshutoDirEntry; use crate::preview::preview_file::FilePreview; pub struct TuiFilePreview<'a> { - _entry: &'a JoshutoDirEntry, preview: &'a FilePreview, } impl<'a> TuiFilePreview<'a> { - pub fn new(_entry: &'a JoshutoDirEntry, preview: &'a FilePreview) -> Self { - Self { _entry, preview } + pub fn new(preview: &'a FilePreview) -> Self { + Self { preview } } } diff --git a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs index f1bd0d4..bc1b210 100644 --- a/src/ui/widgets/tui_prompt.rs +++ b/src/ui/widgets/tui_prompt.rs @@ -7,7 +7,6 @@ use tui::widgets::{Clear, Paragraph, Wrap}; use crate::context::AppContext; use crate::event::AppEvent; use crate::ui::views::TuiView; -use crate::ui::RenderResult; use crate::ui::TuiBackend; use crate::util::input; @@ -32,8 +31,7 @@ impl<'a> TuiPrompt<'a> { } { - let mut render_result = RenderResult::new(); - let mut view = TuiView::new(context, &mut render_result); + let mut view = TuiView::new(context); view.show_bottom_status = false; frame.render_widget(view, f_size); } |