From d52b16993285f6fd98d7241689e1bd950739bb88 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Wed, 9 Oct 2024 22:22:10 +0200 Subject: simple scrollbar for entry list --- src/frontend/entries.rs | 34 +++++++++++++++++++++++++--------- src/frontend/ui.rs | 19 +++++++++++++++++-- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs index 1f79bf4..b0bb0b7 100644 --- a/src/frontend/entries.rs +++ b/src/frontend/entries.rs @@ -22,12 +22,20 @@ use color_eyre::eyre::{Context, Ok, Result}; use core::panic; use editor_command::EditorBuilder; use itertools::Itertools; -use ratatui::widgets::TableState; +use ratatui::widgets::{ScrollbarState, TableState}; use std::process::{Command, Stdio}; +// Define list containing entries as table +#[derive(Debug)] +pub struct EntryTable { + pub entry_table_items: Vec, + pub entry_table_state: TableState, + pub entry_scroll_state: ScrollbarState, +} + impl FromIterator> for EntryTable { fn from_iter>>(iter: T) -> Self { - let entry_table_items = iter + let entry_table_items: Vec = iter .into_iter() .sorted() // 0: authors, 1: title, 2: date, 3: pubtype, 4: keywords, 5: citekey @@ -40,20 +48,15 @@ impl FromIterator> for EntryTable { }) .collect(); let entry_table_state = TableState::default().with_selected(0); + let entry_scroll_state = ScrollbarState::new(entry_table_items.len()); Self { entry_table_items, entry_table_state, + entry_scroll_state, } } } -// Define list containing entries as table -#[derive(Debug)] -pub struct EntryTable { - pub entry_table_items: Vec, - pub entry_table_state: TableState, -} - // Define contents of each entry table row #[derive(Debug)] pub struct EntryTableItem { @@ -127,21 +130,34 @@ impl App { pub fn select_next_entry(&mut self) { self.scroll_info = 0; self.entry_table.entry_table_state.select_next(); + self.entry_table.entry_scroll_state = self + .entry_table + .entry_scroll_state + .position(self.entry_table.entry_table_state.selected().unwrap()); } pub fn select_previous_entry(&mut self) { self.scroll_info = 0; self.entry_table.entry_table_state.select_previous(); + self.entry_table.entry_scroll_state = self + .entry_table + .entry_scroll_state + .position(self.entry_table.entry_table_state.selected().unwrap()); } pub fn select_first_entry(&mut self) { self.scroll_info = 0; self.entry_table.entry_table_state.select_first(); + self.entry_table.entry_scroll_state = self.entry_table.entry_scroll_state.position(0); } pub fn select_last_entry(&mut self) { self.scroll_info = 0; self.entry_table.entry_table_state.select_last(); + self.entry_table.entry_scroll_state = self + .entry_table + .entry_scroll_state + .position(self.entry_table.entry_table_items.len()); } // Get the citekey of the selected entry diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index 6a292d7..32a8296 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -22,8 +22,8 @@ use ratatui::{ symbols, text::{Line, Span, Text}, widgets::{ - Block, Cell, HighlightSpacing, List, ListItem, Padding, Paragraph, Row, StatefulWidget, - Table, Widget, Wrap, + Block, Cell, HighlightSpacing, List, ListItem, Padding, Paragraph, Row, Scrollbar, + ScrollbarOrientation, StatefulWidget, Table, Widget, Wrap, }, }; @@ -82,6 +82,7 @@ impl Widget for &mut App { self.render_footer(footer_area, buf); // Render list area where entry gets selected self.render_entrytable(list_area, buf); + self.render_entry_table_scrollbar(list_area, buf); // Render infos related to selected entry // TODO: only placeholder at the moment, has to be impl. self.render_taglist(tag_area, buf); @@ -230,6 +231,20 @@ impl App { ); } + pub fn render_entry_table_scrollbar(&mut self, area: Rect, buf: &mut Buffer) { + StatefulWidget::render( + Scrollbar::default() + .orientation(ScrollbarOrientation::VerticalRight) + .track_symbol(None) + .thumb_style(Style::new().fg(Color::DarkGray)) + .begin_symbol(None) + .end_symbol(None), + area, + buf, + &mut self.entry_table.entry_scroll_state, + ); + } + pub fn render_selected_item(&mut self, area: Rect, buf: &mut Buffer) { // We get the info depending on the item's state. let style_value = Style::new().bold().fg(TEXT_FG_COLOR); -- cgit v1.2.3 From 1ad9a97e9a25622a9946cb9c55705922c42d9149 Mon Sep 17 00:00:00 2001 From: lukeflo-work Date: Thu, 10 Oct 2024 15:12:31 +0200 Subject: scrollbar for keyword and entry area --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/errorsetup.rs | 51 +++++++++++++++++++++++++++++++ src/frontend/app.rs | 14 +++++++-- src/frontend/handler.rs | 1 + src/frontend/keywords.rs | 20 +++++++++++-- src/frontend/tui.rs | 2 +- src/frontend/ui.rs | 78 ++++++++++++++++++++++++++++++++++++++---------- src/main.rs | 7 +++-- test.bib | 1 + 10 files changed, 154 insertions(+), 24 deletions(-) create mode 100644 src/errorsetup.rs diff --git a/Cargo.lock b/Cargo.lock index 70e5ee8..c8ef416 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ dependencies = [ [[package]] name = "bibiman" -version = "0.2.1" +version = "0.2.2" dependencies = [ "arboard", "biblatex", diff --git a/Cargo.toml b/Cargo.toml index 26debff..01ac69f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bibiman" -version = "0.2.1" +version = "0.2.2" authors = ["lukeflo "] license = "GPL-3.0-or-later" edition = "2021" diff --git a/src/errorsetup.rs b/src/errorsetup.rs new file mode 100644 index 0000000..eaaba0f --- /dev/null +++ b/src/errorsetup.rs @@ -0,0 +1,51 @@ +// bibiman - a TUI for managing BibLaTeX databases +// Copyright (C) 2024 lukeflo +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +///// + +use color_eyre::config::HookBuilder; +use color_eyre::eyre::Result; +use crossterm::cursor; +use crossterm::event::DisableMouseCapture; +use crossterm::terminal::LeaveAlternateScreen; +use std::io::stdout; + +// Define error hooks to restore the terminal after panic +pub fn init_error_hooks() -> Result<()> { + let (panic, error) = HookBuilder::default().into_hooks(); + let panic = panic.into_panic_hook(); + let error = error.into_eyre_hook(); + color_eyre::eyre::set_hook(Box::new(move |e| { + let _ = crossterm::execute!( + stdout(), + DisableMouseCapture, + LeaveAlternateScreen, + cursor::Show + ); + let _ = crossterm::terminal::disable_raw_mode(); + error(e) + }))?; + std::panic::set_hook(Box::new(move |info| { + let _ = crossterm::execute!( + stdout(), + DisableMouseCapture, + LeaveAlternateScreen, + cursor::Show + ); + let _ = crossterm::terminal::disable_raw_mode(); + panic(info) + })); + Ok(()) +} diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 0751da1..26b9a13 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -33,6 +33,7 @@ pub enum CurrentArea { TagArea, SearchArea, HelpArea, + InfoArea, } // Check which area was active when popup set active @@ -137,11 +138,20 @@ impl App { // Toggle moveable list between entries and tags pub fn toggle_area(&mut self) { if let CurrentArea::EntryArea = self.current_area { + self.entry_table.entry_scroll_state = self.entry_table.entry_scroll_state.position(0); self.current_area = CurrentArea::TagArea; - self.tag_list.tag_list_state.select(Some(0)) + self.tag_list.tag_list_state.select(Some(0)); + self.tag_list.tag_scroll_state = self + .tag_list + .tag_scroll_state + .position(self.tag_list.tag_list_state.selected().unwrap()); } else if let CurrentArea::TagArea = self.current_area { self.current_area = CurrentArea::EntryArea; - self.tag_list.tag_list_state.select(None) + self.tag_list.tag_list_state.select(None); + self.entry_table.entry_scroll_state = self + .entry_table + .entry_scroll_state + .position(self.entry_table.entry_table_state.selected().unwrap()); } } diff --git a/src/frontend/handler.rs b/src/frontend/handler.rs index 9a27b3a..ac5b94f 100644 --- a/src/frontend/handler.rs +++ b/src/frontend/handler.rs @@ -148,6 +148,7 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R } _ => {} }, + CurrentArea::InfoArea => {} } Ok(()) } diff --git a/src/frontend/keywords.rs b/src/frontend/keywords.rs index 4beec14..6aa4068 100644 --- a/src/frontend/keywords.rs +++ b/src/frontend/keywords.rs @@ -18,12 +18,13 @@ use super::app::{App, FormerArea}; use super::entries::EntryTable; use crate::backend::search::BibiSearch; -use ratatui::widgets::ListState; +use ratatui::widgets::{ListState, ScrollbarState}; #[derive(Debug)] pub struct TagList { pub tag_list_items: Vec, pub tag_list_state: ListState, + pub tag_scroll_state: ScrollbarState, } // Structure of the list items. @@ -43,14 +44,16 @@ impl TagListItem { impl FromIterator for TagList { fn from_iter>(iter: I) -> Self { - let tag_list_items = iter + let tag_list_items: Vec = iter .into_iter() .map(|info| TagListItem::new(&info)) .collect(); let tag_list_state = ListState::default(); // for preselection: .with_selected(Some(0)); + let tag_scroll_state = ScrollbarState::new(tag_list_items.len()); Self { tag_list_items, tag_list_state, + tag_scroll_state, } } } @@ -61,18 +64,31 @@ impl App { // Movement pub fn select_next_tag(&mut self) { self.tag_list.tag_list_state.select_next(); + self.tag_list.tag_scroll_state = self + .tag_list + .tag_scroll_state + .position(self.tag_list.tag_list_state.selected().unwrap()); } pub fn select_previous_tag(&mut self) { self.tag_list.tag_list_state.select_previous(); + self.tag_list.tag_scroll_state = self + .tag_list + .tag_scroll_state + .position(self.tag_list.tag_list_state.selected().unwrap()); } pub fn select_first_tag(&mut self) { self.tag_list.tag_list_state.select_first(); + self.tag_list.tag_scroll_state = self.tag_list.tag_scroll_state.position(0); } pub fn select_last_tag(&mut self) { self.tag_list.tag_list_state.select_last(); + self.tag_list.tag_scroll_state = self + .tag_list + .tag_scroll_state + .position(self.tag_list.tag_list_items.len()); } pub fn get_selected_tag(&self) -> &str { diff --git a/src/frontend/tui.rs b/src/frontend/tui.rs index a4560c1..698407d 100644 --- a/src/frontend/tui.rs +++ b/src/frontend/tui.rs @@ -179,7 +179,7 @@ impl Tui { // if self.paste { // crossterm::execute!(stdout(), EnableBracketedPaste)?; // } - Self::init_error_hooks()?; + // Self::init_error_hooks()?; self.start(); Ok(()) } diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index 32a8296..3b79f7a 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -47,6 +47,9 @@ const SELECTED_STYLE: Style = Style::new() const TEXT_FG_COLOR: Color = Color::Indexed(252); const TEXT_UNSELECTED_FG_COLOR: Color = Color::Indexed(245); +const SCROLLBAR_UPPER_CORNER: Option<&str> = Some("┓"); +const SCROLLBAR_LOWER_CORNER: Option<&str> = Some("┛"); + pub const fn alternate_colors(i: usize) -> Color { if i % 2 == 0 { NORMAL_ROW_BG @@ -82,9 +85,7 @@ impl Widget for &mut App { self.render_footer(footer_area, buf); // Render list area where entry gets selected self.render_entrytable(list_area, buf); - self.render_entry_table_scrollbar(list_area, buf); // Render infos related to selected entry - // TODO: only placeholder at the moment, has to be impl. self.render_taglist(tag_area, buf); self.render_selected_item(info_area, buf); } @@ -229,20 +230,24 @@ impl App { buf, &mut self.entry_table.entry_table_state, ); - } - pub fn render_entry_table_scrollbar(&mut self, area: Rect, buf: &mut Buffer) { - StatefulWidget::render( - Scrollbar::default() - .orientation(ScrollbarOrientation::VerticalRight) - .track_symbol(None) - .thumb_style(Style::new().fg(Color::DarkGray)) - .begin_symbol(None) - .end_symbol(None), - area, - buf, - &mut self.entry_table.entry_scroll_state, - ); + // Scrollbar for entry table + let scrollbar = Scrollbar::default() + .orientation(ScrollbarOrientation::VerticalRight) + .track_symbol(None) + .begin_symbol(SCROLLBAR_UPPER_CORNER) + .end_symbol(SCROLLBAR_LOWER_CORNER) + .thumb_style(Style::new().fg(Color::DarkGray)); + + if let CurrentArea::EntryArea = self.current_area { + // render the scrollbar + StatefulWidget::render( + scrollbar, + area, + buf, + &mut self.entry_table.entry_scroll_state, + ); + } } pub fn render_selected_item(&mut self, area: Rect, buf: &mut Buffer) { @@ -358,6 +363,25 @@ impl App { .wrap(Wrap { trim: false }) .scroll((scroll_height, 0)) .render(area, buf); + + let scrollbar = Scrollbar::default() + .orientation(ScrollbarOrientation::VerticalRight) + .track_symbol(None) + .begin_symbol(SCROLLBAR_UPPER_CORNER) + .end_symbol(SCROLLBAR_LOWER_CORNER) + .thumb_style(Style::new().fg(Color::DarkGray)); + + if box_height > area.height.into() { + if let CurrentArea::EntryArea = self.current_area { + // render the scrollbar + StatefulWidget::render( + scrollbar, + area, + buf, + &mut self.entry_table.entry_scroll_state, + ); + } + } } pub fn render_taglist(&mut self, area: Rect, buf: &mut Buffer) { @@ -404,8 +428,32 @@ impl App { // .highlight_symbol("> ") .highlight_spacing(HighlightSpacing::Always); + // Save list length for calculating scrollbar need + // Add 2 to compmensate lines of the block border + let list_length = list.len() + 2; + // We need to disambiguate this trait method as both `Widget` and `StatefulWidget` share the // same method name `render`. StatefulWidget::render(list, area, buf, &mut self.tag_list.tag_list_state); + + // Scrollbar for keyword list + let scrollbar = Scrollbar::default() + .orientation(ScrollbarOrientation::VerticalRight) + .track_symbol(None) + .begin_symbol(SCROLLBAR_UPPER_CORNER) + .end_symbol(SCROLLBAR_LOWER_CORNER) + .thumb_style(Style::new().fg(Color::DarkGray)); + + if list_length > area.height.into() { + if let CurrentArea::TagArea = self.current_area { + // render the scrollbar + StatefulWidget::render( + scrollbar, + area, + buf, + &mut self.entry_table.entry_scroll_state, + ); + } + } } } diff --git a/src/main.rs b/src/main.rs index 74e1252..6ef7ee1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,13 +15,14 @@ // along with this program. If not, see . ///// -use core::panic; - use backend::cliargs::{self, CLIArgs}; use color_eyre::eyre::Result; +use core::panic; +use errorsetup::init_error_hooks; use frontend::app::App; pub mod backend; +pub mod errorsetup; pub mod frontend; #[tokio::main] @@ -45,6 +46,8 @@ async fn main() -> Result<()> { panic!("No \'.bib\' file passed, aborting") } + init_error_hooks()?; + // Create an application. let mut app = App::new(parsed_args)?; diff --git a/test.bib b/test.bib index b902220..50ea05f 100644 --- a/test.bib +++ b/test.bib @@ -117,6 +117,7 @@ langid = {english}, langidopts = {variant=american}, annotation = {A plain \texttt{book} entry}, + keywords = {chemistry}, } @book{averroes/bland, -- cgit v1.2.3 From d7bc5105f0fb572beb2ae4e5b033a343ae12f2dc Mon Sep 17 00:00:00 2001 From: lukeflo Date: Fri, 11 Oct 2024 14:05:34 +0200 Subject: scrollbar for entries and keywords. scroll symbols for abstract first steps --- src/frontend/app.rs | 22 ++++++++++++----- src/frontend/entries.rs | 21 ++++++++++++---- src/frontend/handler.rs | 36 ++++++++++++++++++++++++---- src/frontend/ui.rs | 64 +++++++++++++++++++++++++++---------------------- 4 files changed, 101 insertions(+), 42 deletions(-) diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 26b9a13..ee2ab05 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -175,15 +175,25 @@ impl App { } pub fn scroll_info_down(&mut self) { - self.scroll_info = self.scroll_info + 1; + // self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll + 1; + self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll.saturating_add(1); + self.entry_table.entry_info_scroll_state = self + .entry_table + .entry_info_scroll_state + .position(self.entry_table.entry_info_scroll.into()); } pub fn scroll_info_up(&mut self) { - if self.scroll_info == 0 { - {} - } else { - self.scroll_info = self.scroll_info - 1; - } + // if self.entry_table.entry_info_scroll == 0 { + // {} + // } else { + // self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll - 1; + // } + self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll.saturating_sub(1); + self.entry_table.entry_info_scroll_state = self + .entry_table + .entry_info_scroll_state + .position(self.entry_table.entry_info_scroll.into()); } // Search Area diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs index b0bb0b7..081de4c 100644 --- a/src/frontend/entries.rs +++ b/src/frontend/entries.rs @@ -31,6 +31,8 @@ pub struct EntryTable { pub entry_table_items: Vec, pub entry_table_state: TableState, pub entry_scroll_state: ScrollbarState, + pub entry_info_scroll: u16, + pub entry_info_scroll_state: ScrollbarState, } impl FromIterator> for EntryTable { @@ -49,10 +51,13 @@ impl FromIterator> for EntryTable { .collect(); let entry_table_state = TableState::default().with_selected(0); let entry_scroll_state = ScrollbarState::new(entry_table_items.len()); + let entry_info_scroll_state = ScrollbarState::default(); Self { entry_table_items, entry_table_state, entry_scroll_state, + entry_info_scroll: 0, + entry_info_scroll_state, } } } @@ -128,7 +133,9 @@ impl App { // Movement pub fn select_next_entry(&mut self) { - self.scroll_info = 0; + self.entry_table.entry_info_scroll = 0; + self.entry_table.entry_info_scroll_state = + self.entry_table.entry_info_scroll_state.position(0); self.entry_table.entry_table_state.select_next(); self.entry_table.entry_scroll_state = self .entry_table @@ -137,7 +144,9 @@ impl App { } pub fn select_previous_entry(&mut self) { - self.scroll_info = 0; + self.entry_table.entry_info_scroll = 0; + self.entry_table.entry_info_scroll_state = + self.entry_table.entry_info_scroll_state.position(0); self.entry_table.entry_table_state.select_previous(); self.entry_table.entry_scroll_state = self .entry_table @@ -146,13 +155,17 @@ impl App { } pub fn select_first_entry(&mut self) { - self.scroll_info = 0; + self.entry_table.entry_info_scroll = 0; + self.entry_table.entry_info_scroll_state = + self.entry_table.entry_info_scroll_state.position(0); self.entry_table.entry_table_state.select_first(); self.entry_table.entry_scroll_state = self.entry_table.entry_scroll_state.position(0); } pub fn select_last_entry(&mut self) { - self.scroll_info = 0; + self.entry_table.entry_info_scroll = 0; + self.entry_table.entry_info_scroll_state = + self.entry_table.entry_info_scroll_state.position(0); self.entry_table.entry_table_state.select_last(); self.entry_table.entry_scroll_state = self .entry_table diff --git a/src/frontend/handler.rs b/src/frontend/handler.rs index ac5b94f..c2cacf5 100644 --- a/src/frontend/handler.rs +++ b/src/frontend/handler.rs @@ -48,12 +48,26 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R match app.current_area { // Keycodes for the tag area CurrentArea::TagArea => match key_event.code { - KeyCode::Char('j') | KeyCode::Down => { + KeyCode::Down => { app.select_next_tag(); } - KeyCode::Char('k') | KeyCode::Up => { + KeyCode::Up => { app.select_previous_tag(); } + KeyCode::Char('j') => { + if key_event.modifiers == KeyModifiers::ALT { + app.scroll_info_down(); + } else { + app.select_next_tag(); + } + } + KeyCode::Char('k') => { + if key_event.modifiers == KeyModifiers::ALT { + app.scroll_info_up(); + } else { + app.select_previous_tag(); + } + } KeyCode::Char('g') | KeyCode::Home => { app.select_first_tag(); } @@ -81,12 +95,26 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R }, // Keycodes for the entry area CurrentArea::EntryArea => match key_event.code { - KeyCode::Char('j') | KeyCode::Down => { + KeyCode::Down => { app.select_next_entry(); } - KeyCode::Char('k') | KeyCode::Up => { + KeyCode::Up => { app.select_previous_entry(); } + KeyCode::Char('j') => { + if key_event.modifiers == KeyModifiers::ALT { + app.scroll_info_down(); + } else { + app.select_next_entry(); + } + } + KeyCode::Char('k') => { + if key_event.modifiers == KeyModifiers::ALT { + app.scroll_info_up(); + } else { + app.select_previous_entry(); + } + } KeyCode::Char('g') | KeyCode::Home => { app.select_first_entry(); } diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index 3b79f7a..dfb9017 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -17,13 +17,14 @@ use ratatui::{ buffer::Buffer, - layout::{Constraint, Layout, Rect}, + layout::{Alignment, Constraint, Layout, Rect}, style::{Color, Modifier, Style, Stylize}, symbols, text::{Line, Span, Text}, widgets::{ + block::{Position, Title}, Block, Cell, HighlightSpacing, List, ListItem, Padding, Paragraph, Row, Scrollbar, - ScrollbarOrientation, StatefulWidget, Table, Widget, Wrap, + ScrollbarOrientation, ScrollbarState, StatefulWidget, Table, Widget, Wrap, }, }; @@ -343,22 +344,32 @@ impl App { .line_count(area.width); // Make sure to allow scroll only if text is larger than the rendered area and stop scrolling when last line is reached let scroll_height = { - if self.scroll_info == 0 { - self.scroll_info + if self.entry_table.entry_info_scroll == 0 { + self.entry_table.entry_info_scroll } else if area.height > box_height as u16 { - self.scroll_info = 0; - self.scroll_info - } else if self.scroll_info > (box_height as u16 + 1 - area.height) { - self.scroll_info = box_height as u16 + 1 - area.height; - self.scroll_info + self.entry_table.entry_info_scroll = 0; + self.entry_table.entry_info_scroll + } else if self.entry_table.entry_info_scroll > (box_height as u16 + 2 - area.height) { + self.entry_table.entry_info_scroll = box_height as u16 + 2 - area.height; + self.entry_table.entry_info_scroll } else { - self.scroll_info + self.entry_table.entry_info_scroll } }; // We can now render the item info Paragraph::new(info) - .block(block) + .block( + block.title( + Title::from(if box_height > area.height.into() { + " ▼ " + } else { + "" + }) + .position(Position::Bottom) + .alignment(Alignment::Right), + ), + ) // .fg(TEXT_FG_COLOR) .wrap(Wrap { trim: false }) .scroll((scroll_height, 0)) @@ -371,17 +382,19 @@ impl App { .end_symbol(SCROLLBAR_LOWER_CORNER) .thumb_style(Style::new().fg(Color::DarkGray)); - if box_height > area.height.into() { - if let CurrentArea::EntryArea = self.current_area { - // render the scrollbar - StatefulWidget::render( - scrollbar, - area, - buf, - &mut self.entry_table.entry_scroll_state, - ); - } - } + // if box_height > area.height.into() { + // // self.entry_table.entry_info_scroll_state = ScrollbarState::new(area.height.into()); + // self.entry_table.entry_info_scroll_state = self + // .entry_table + // .entry_info_scroll_state + // .content_length(area.height.into()); + // StatefulWidget::render( + // scrollbar, + // area, + // buf, + // &mut self.entry_table.entry_info_scroll_state, + // ); + // } } pub fn render_taglist(&mut self, area: Rect, buf: &mut Buffer) { @@ -447,12 +460,7 @@ impl App { if list_length > area.height.into() { if let CurrentArea::TagArea = self.current_area { // render the scrollbar - StatefulWidget::render( - scrollbar, - area, - buf, - &mut self.entry_table.entry_scroll_state, - ); + StatefulWidget::render(scrollbar, area, buf, &mut self.tag_list.tag_scroll_state); } } } -- cgit v1.2.3 From d9ed8fc8eaab1aa04aac031cc629d7018d513ab7 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Fri, 11 Oct 2024 14:26:32 +0200 Subject: info box scrollable arrows --- src/frontend/ui.rs | 53 ++++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index dfb9017..7edcf43 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -24,7 +24,7 @@ use ratatui::{ widgets::{ block::{Position, Title}, Block, Cell, HighlightSpacing, List, ListItem, Padding, Paragraph, Row, Scrollbar, - ScrollbarOrientation, ScrollbarState, StatefulWidget, Table, Widget, Wrap, + ScrollbarOrientation, StatefulWidget, Table, Widget, Wrap, }, }; @@ -360,41 +360,32 @@ impl App { // We can now render the item info Paragraph::new(info) .block( - block.title( - Title::from(if box_height > area.height.into() { - " ▼ " - } else { - "" - }) - .position(Position::Bottom) - .alignment(Alignment::Right), - ), + block + // Render arrows to show that info box has content outside the block + .title( + Title::from( + if box_height > area.height.into() + && self.entry_table.entry_info_scroll + < box_height as u16 + 2 - area.height + { + " ▼ " + } else { + "" + }, + ) + .position(Position::Bottom) + .alignment(Alignment::Right), + ) + .title( + Title::from(if scroll_height > 0 { " ▲ " } else { "" }) + .position(Position::Top) + .alignment(Alignment::Right), + ), ) // .fg(TEXT_FG_COLOR) .wrap(Wrap { trim: false }) .scroll((scroll_height, 0)) .render(area, buf); - - let scrollbar = Scrollbar::default() - .orientation(ScrollbarOrientation::VerticalRight) - .track_symbol(None) - .begin_symbol(SCROLLBAR_UPPER_CORNER) - .end_symbol(SCROLLBAR_LOWER_CORNER) - .thumb_style(Style::new().fg(Color::DarkGray)); - - // if box_height > area.height.into() { - // // self.entry_table.entry_info_scroll_state = ScrollbarState::new(area.height.into()); - // self.entry_table.entry_info_scroll_state = self - // .entry_table - // .entry_info_scroll_state - // .content_length(area.height.into()); - // StatefulWidget::render( - // scrollbar, - // area, - // buf, - // &mut self.entry_table.entry_info_scroll_state, - // ); - // } } pub fn render_taglist(&mut self, area: Rect, buf: &mut Buffer) { -- cgit v1.2.3