bee_tui/components/
scroll.rs1use ratatui::{
10 Frame,
11 layout::Rect,
12 style::Style,
13 widgets::{Scrollbar, ScrollbarOrientation, ScrollbarState},
14};
15
16use crate::theme;
17
18pub fn clamp_scroll(
27 selected: usize,
28 scroll_offset: usize,
29 visible_rows: usize,
30 total_rows: usize,
31) -> usize {
32 let visible_rows = visible_rows.max(1);
33 let max_offset = total_rows.saturating_sub(visible_rows);
34 let mut offset = scroll_offset;
35 if selected < offset {
36 offset = selected;
37 } else if selected >= offset + visible_rows {
38 offset = selected + 1 - visible_rows;
39 }
40 offset.min(max_offset)
41}
42
43pub fn render_scrollbar(
47 frame: &mut Frame,
48 area: Rect,
49 scroll_offset: usize,
50 visible_rows: usize,
51 total_rows: usize,
52) {
53 if total_rows <= visible_rows {
54 return;
55 }
56 let t = theme::active();
57 let mut state = ScrollbarState::new(total_rows.saturating_sub(visible_rows))
58 .position(scroll_offset)
59 .viewport_content_length(visible_rows);
60 let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
61 .style(Style::default().fg(t.dim))
62 .thumb_style(Style::default().fg(t.accent))
63 .begin_symbol(None)
64 .end_symbol(None);
65 frame.render_stateful_widget(scrollbar, area, &mut state);
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn clamp_keeps_selection_in_window_when_already_visible() {
74 assert_eq!(clamp_scroll(3, 0, 10, 50), 0);
76 }
77
78 #[test]
79 fn clamp_advances_window_when_selection_moves_below() {
80 assert_eq!(clamp_scroll(12, 0, 10, 50), 3);
82 }
83
84 #[test]
85 fn clamp_snaps_window_up_when_selection_moves_above() {
86 assert_eq!(clamp_scroll(2, 10, 10, 50), 2);
88 }
89
90 #[test]
91 fn clamp_holds_offset_within_max_when_list_shrinks() {
92 assert_eq!(clamp_scroll(14, 15, 10, 20), 10);
96 }
97
98 #[test]
99 fn clamp_yields_zero_when_list_fits() {
100 assert_eq!(clamp_scroll(4, 0, 10, 5), 0);
102 assert_eq!(clamp_scroll(4, 7, 10, 5), 0); }
104
105 #[test]
106 fn clamp_handles_zero_visible_rows_without_panic() {
107 let _ = clamp_scroll(3, 0, 0, 50);
110 }
111}