screen_buffer_ui/
scrollable.rs

1pub trait Scrollable {
2    fn selected(&self) -> usize;
3    fn len(&self) -> usize;
4    fn set_selected(&mut self, selected: usize) -> bool;
5    fn element_height(&self, index: usize) -> u16;
6    fn visible_range(&self, height: u16) -> Box<dyn Iterator<Item = usize>>;
7    fn visible_start_end(&self, height: u16) -> (usize, usize);
8    fn up(&mut self, how_much: usize);
9    fn down(&mut self, how_much: usize);
10}
11
12#[macro_export]
13macro_rules! scrollable {
14    ($x:ty, $($y:item),*) => {
15        impl Scrollable for $x {
16            fn up(&mut self, how_much: usize) {
17                let how_much = how_much % self.len();
18
19                self.set_selected((self.len() + self.selected() - how_much) % self.len());
20            }
21            fn down(&mut self, how_much: usize) {
22                let how_much = how_much % self.len();
23
24                self.set_selected((how_much + self.selected()) % self.len());
25            }
26            fn visible_range(&self, height: u16) -> Box<dyn Iterator<Item = usize>> {
27                let (a, b) = self.visible_start_end(height);
28
29                Box::new((a..b).into_iter())
30            }
31            fn visible_start_end(&self, height: u16) -> (usize, usize) {
32                let mut last_first = 0;
33                let mut current_height = 0;
34                let mut i = 0;
35                while i < self.len() {
36                    let eh =  self.element_height(i);
37                    if current_height + eh > height {
38                        if i > self.selected() {
39                            break;
40                        }
41                        current_height = eh;
42                        last_first = i;
43                    } else {
44                        current_height += eh;
45                    }
46
47                    i += 1;
48                }
49
50                (last_first, i)
51            }
52            $($y)*
53        }
54    }
55}