Skip to main content

gm_lib/tui/app/widgets/
scroll_bar.rs

1use ratatui::{layout::Offset, widgets::Widget};
2
3pub struct CustomScrollBar {
4    pub cursor: usize,
5    pub total: usize,
6}
7
8impl Widget for CustomScrollBar {
9    fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
10    where
11        Self: Sized,
12    {
13        let capacity = area.height as usize;
14        let num_pages = self.total.div_ceil(capacity);
15        let current_page = self.cursor / capacity;
16
17        let top = (0..current_page)
18            .map(|i| get_page_height(i, capacity, num_pages))
19            .sum::<usize>();
20        let middle = get_page_height(current_page, capacity, num_pages);
21        let bottom = ((current_page + 1)..num_pages)
22            .map(|i| get_page_height(i, capacity, num_pages))
23            .sum::<usize>();
24        assert_eq!(
25            top + middle + bottom,
26            capacity,
27            "self.total = {}, capacity = {}, current_page = {current_page}, num_pages = {num_pages}, top = {top}, middle = {middle}, bottom = {bottom}",
28            self.total, capacity
29        );
30
31        let mut i = 0;
32        for _ in 0..top {
33            "║".render(area.offset(Offset { x: 0, y: i }), buf);
34            i += 1;
35        }
36        for _ in 0..middle {
37            "█".render(area.offset(Offset { x: 0, y: i }), buf);
38            i += 1;
39        }
40        for _ in 0..bottom {
41            "║".render(area.offset(Offset { x: 0, y: i }), buf);
42            i += 1;
43        }
44    }
45}
46
47fn get_page_height(i: usize, capacity: usize, num_pages: usize) -> usize {
48    let base = capacity / num_pages;
49    if i < capacity % num_pages {
50        base + 1
51    } else {
52        base
53    }
54}
55
56#[cfg(test)]
57mod test {
58    use super::*;
59
60    #[test]
61    fn test_get_page_height() {
62        for capacity in 10..100 {
63            for num_pages in 1..15 {
64                let mut sum = 0;
65                for i in 0..num_pages {
66                    sum += get_page_height(i, capacity, num_pages);
67                }
68
69                if sum != capacity {
70                    println!("capacity: {capacity}, num_pages: {num_pages}");
71                    for i in 0..num_pages {
72                        let h = get_page_height(i, capacity, num_pages);
73                        println!("page {i}: {h}");
74                    }
75                }
76
77                assert_eq!(
78                    sum, capacity,
79                    "capacity: {capacity}, num_pages: {num_pages}"
80                );
81            }
82        }
83    }
84}