From b3a52c171b405b8358af2b1b8b7300e4f9155a9a Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 3 Mar 2025 18:39:21 +0200 Subject: [PATCH] more highlights, prevent overscroll --- src/keys.rs | 28 ++++++++++++++++++--------- src/main.rs | 9 +++++++++ src/view.rs | 55 ++++++++++++++++++++++++++++++++--------------------- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/keys.rs b/src/keys.rs index c98393b..ab1ee69 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,8 +1,12 @@ use crate::*; +const PAGE_SIZE: usize = 10; + impl Handle for Taggart { fn handle (&mut self, input: &TuiIn) -> Perhaps { - Ok(match &*input.event() { + let x_min = self.offset; + let x_max = self.offset + self.size.h().saturating_sub(1); + match &*input.event() { Event::Key(KeyEvent { code: KeyCode::Up, kind: KeyEventKind::Press, @@ -10,7 +14,6 @@ impl Handle for Taggart { state: KeyEventState::NONE }) => { self.cursor = self.cursor.saturating_sub(1); - None }, Event::Key(KeyEvent { code: KeyCode::Down, @@ -19,7 +22,6 @@ impl Handle for Taggart { state: KeyEventState::NONE }) => { self.cursor = self.cursor + 1; - None }, Event::Key(KeyEvent { code: KeyCode::PageUp, @@ -27,8 +29,7 @@ impl Handle for Taggart { modifiers: KeyModifiers::NONE, state: KeyEventState::NONE }) => { - self.offset = self.offset.saturating_sub(5); - None + self.cursor = self.cursor.saturating_sub(PAGE_SIZE); }, Event::Key(KeyEvent { code: KeyCode::PageDown, @@ -36,11 +37,20 @@ impl Handle for Taggart { modifiers: KeyModifiers::NONE, state: KeyEventState::NONE }) => { - self.offset += 5; - None + self.cursor += PAGE_SIZE; }, - _ => None - }) + _ => {} + } + if self.cursor < x_min { + self.offset = self.cursor; + } + if self.cursor > x_max { + self.offset += self.cursor - x_max; + } + if self.cursor >= self.paths.len() { + self.cursor = self.paths.len().saturating_sub(1) + } + Ok(None) } } diff --git a/src/main.rs b/src/main.rs index 4762d21..153b1d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,8 @@ struct Taggart { paths: Vec, cursor: usize, offset: usize, + column: usize, + size: Measure, } #[derive(Ord, Eq, PartialEq, PartialOrd, Default)] struct Entry { @@ -64,6 +66,11 @@ impl Taggart { } let depth = entry.depth(); let path = entry.into_path(); + let (is_dir, is_mus, is_img) = if path.is_dir() { + (true, false, false) + } else { + (false, false, false) + }; paths.push(Entry { path: path.strip_prefix(&root)?.into(), is_dir: path.is_dir(), @@ -78,6 +85,8 @@ impl Taggart { paths, cursor: 0, offset: 0, + column: 0, + size: Measure::new(), }) } } diff --git a/src/view.rs b/src/view.rs index fc3a93d..d388cab 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,25 +1,44 @@ use crate::*; +use tek_tui::ratatui::{style::{Color, Style}, prelude::Stylize}; use pad::PadStr; +fn table_row (label: &str, artist: &str, album: &str, title: &str) -> String { + format!("{label:60} {artist:20} {album:20} {title:20}") +} + impl Content for Taggart { - fn layout (&self, area: [u16;4]) -> [u16;4] { - [area.x(), area.y(), 20, area.h()] + fn content (&self) -> impl Render { + let sizer = Fill::xy(&self.size); + let size = format!("{}x{}", self.size.w(), self.size.h()); + let size_bar = Fill::x(Align::e(Tui::bold(true, Tui::fg_bg(Color::Rgb(0,0,0), Color::Rgb(255,255,255), size)))); + let titlebar = Fill::x(Align::w(Tui::bold(true, Tui::fg_bg(Color::Rgb(0,0,0), Color::Rgb(255,255,255), table_row("FILE", "ARTIST", "ALBUM", "TITLE"))))); + let table = Fill::xy(TreeTable(self)); + Bsp::n(size_bar, Bsp::s(titlebar, Bsp::b(sizer, table))) } +} + +struct TreeTable<'a>(&'a Taggart); + +impl<'a> Content for TreeTable<'a> { fn render (&self, to: &mut TuiOut) { let area = to.area(); + let Taggart { offset, paths, cursor, .. } = self.0; for (i, y) in area.iter_y().enumerate() { - let i_offset = i + self.offset; - if let Some(entry) = self.paths.get(i_offset) { - if entry.depth > 0 { - for (index, fragment) in entry.path.iter().enumerate() { - if index == entry.depth - 1 { - let cursor = if self.cursor == i_offset { ">" } else { " " }; - let icon = if entry.is_dir {"+"} else {" "}; - let name = fragment.display(); - let indent = "".pad_to_width((entry.depth - 1) * 2); - let label = format!("{cursor} {indent}{icon} {name}"); - let label = format!("{label:80} ARTIST ALBUM TITLE"); - to.blit(&label, area.x(), y, None); + let i_offset = i + offset; + let selected = *cursor == i_offset; + if let Some(entry) = paths.get(i_offset) { + for (index, fragment) in entry.path.iter().enumerate() { + if index == entry.depth - 1 { + let cursor = if selected { ">" } else { " " }; + let icon = if entry.is_dir {"+"} else {" "}; + let name = fragment.display(); + let indent = "".pad_to_width((entry.depth - 1) * 2); + let label = table_row(&format!("{cursor} {indent}{icon} {name}"), "", "", ""); + to.blit(&label, area.x(), y, if entry.is_dir { None } else { + Some(Style::default().bold()) + }); + if selected { + to.fill_bg([area.x(), y, area.w(), 1], Color::Rgb(0, 0, 0)); } } } @@ -29,11 +48,3 @@ impl Content for Taggart { } } } - -fn depth_of (path: &PathBuf) -> usize { - let mut depth = 0; - for _ in path.iter() { - depth += 1; - } - depth -}