diff options
| author | 2026-03-09 00:43:26 -0400 | |
|---|---|---|
| committer | 2026-03-09 00:43:26 -0400 | |
| commit | 744c5cc2960cbc29802739bbb5851cfa429316b6 (patch) | |
| tree | 7deec9c01a85ac674f5712bf5428fa437a654eac | |
| parent | fixing text wrap miscalculation on long words (diff) | |
add scroll and scroll bar indicator to members list
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/tui/app.rs | 27 | ||||
| -rw-r--r-- | src/tui/ui.rs | 24 |
3 files changed, 44 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs index b87ee8d..b81eff8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -105,6 +105,8 @@ async fn run( (KeyModifiers::NONE | KeyModifiers::SHIFT, KeyCode::Char(c)) => { app.input_insert(c); } + (KeyModifiers::SHIFT, KeyCode::Up) => app.members_scroll_up(), + (KeyModifiers::SHIFT, KeyCode::Down) => app.members_scroll_down(), (_, KeyCode::Backspace) => app.input_backspace(), (_, KeyCode::Left) => app.cursor_left(), (_, KeyCode::Right) => app.cursor_right(), diff --git a/src/tui/app.rs b/src/tui/app.rs index 879d762..52fc85a 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -1,3 +1,5 @@ +use ratatui::widgets::{ListState, ScrollbarState}; + /// A single chat message in the log #[derive(Clone)] pub struct ChatLine { @@ -15,7 +17,9 @@ pub struct AppState { pub members: Vec<String>, pub input: String, pub cursor: usize, - pub scroll_offset: usize, + pub chat_scroll: usize, + pub members_scroll: ScrollbarState, + pub members_list_state: ListState, pub status: String, pub connected: bool, } @@ -29,7 +33,9 @@ impl AppState { members: Vec::new(), input: String::new(), cursor: 0, - scroll_offset: 0, + chat_scroll: 0, + members_scroll: ScrollbarState::new(0), + members_list_state: ListState::default(), status: "Set nick with /nick to connect.".into(), connected: false, } @@ -88,11 +94,24 @@ impl AppState { } pub fn scroll_up(&mut self) { - self.scroll_offset += 1; + self.chat_scroll = self.chat_scroll.saturating_add(1); } pub fn scroll_down(&mut self) { - self.scroll_offset = self.scroll_offset.saturating_sub(1); + self.chat_scroll = self.chat_scroll.saturating_sub(1); + } + + pub fn members_scroll_up(&mut self) { + let pos = self.members_scroll.get_position().saturating_sub(5); + self.members_scroll = self.members_scroll.position(pos); + *self.members_list_state.offset_mut() = pos; + } + + pub fn members_scroll_down(&mut self) { + let max = self.members.len().saturating_sub(1); + let pos = (self.members_scroll.get_position().saturating_add(5)).min(max); + self.members_scroll = self.members_scroll.position(pos); + *self.members_list_state.offset_mut() = pos; } pub fn take_input(&mut self) -> String { diff --git a/src/tui/ui.rs b/src/tui/ui.rs index b026c34..05b3c9f 100644 --- a/src/tui/ui.rs +++ b/src/tui/ui.rs @@ -4,7 +4,10 @@ use ratatui::{ layout::{Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, text::{Line, Span, Text}, - widgets::{Block, BorderType, Borders, List, ListItem, Paragraph, Wrap}, + widgets::{ + Block, BorderType, Borders, List, ListItem, Paragraph, Scrollbar, ScrollbarOrientation, + Wrap, + }, }; use unicode_width::UnicodeWidthStr; @@ -113,8 +116,8 @@ fn draw_chat_log(f: &mut Frame, area: Rect, state: &mut AppState) { let max_offset = base_scroll as usize; // Clamp the offset and write it back so app.rs stays in sync - state.scroll_offset = state.scroll_offset.clamp(0, max_offset); - let final_scroll = (base_scroll as i32 - state.scroll_offset as i32) as u16; + state.chat_scroll = state.chat_scroll.clamp(0, max_offset); + let final_scroll = (base_scroll as i32 - state.chat_scroll as i32) as u16; f.render_widget( Paragraph::new(Text::from(padded_lines)) @@ -246,7 +249,7 @@ fn draw_input(f: &mut Frame, area: Rect, state: &AppState) { ); } -fn draw_members_panel(f: &mut Frame, area: Rect, state: &AppState) { +fn draw_members_panel(f: &mut Frame, area: Rect, state: &mut AppState) { let items: Vec<ListItem> = state .members .iter() @@ -281,7 +284,18 @@ fn draw_members_panel(f: &mut Frame, area: Rect, state: &AppState) { let title = format!(" users ({}) ", state.members.len()); let block = panel_block(&title); - f.render_widget(List::new(items).block(block), area); + state.members_scroll = state.members_scroll.content_length(state.members.len()); + + f.render_stateful_widget( + List::new(items).block(block), + area, + &mut state.members_list_state, + ); + f.render_stateful_widget( + Scrollbar::new(ScrollbarOrientation::VerticalRight), + area, + &mut state.members_scroll, + ); } fn draw_statusbar(f: &mut Frame, area: Rect, state: &AppState) { |
