1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::emit;
use std::ops::Range;
pub struct Paginate<T> {
    list: Vec<T>,
    nth_window: usize,
    cursor_range: Range<usize>,
    cursor: usize,
    hovered: Option<T>,
}

impl<T> Paginate<T>
where
    T: Clone,
{
    pub fn new(list: Vec<T>) -> Self {
        let hovered = list.first().cloned();
        Self {
            list,
            nth_window: Default::default(),
            cursor_range: Default::default(),
            cursor: Default::default(),
            hovered,
        }
    }

    pub fn update_list(&mut self, list: Vec<T>) {
        *self = Self::new(list)
    }
}

impl<T> Paginate<T>
where
    T: Clone,
{
    pub fn next_elem(&mut self, wid_height: usize) -> bool {
        if self.list.is_empty() {
            emit!(Popup(vec!["List is empty".into()]));
            return true;
        }
        self.set_cursor_range(wid_height);
        let old_cursor = self.cursor;
        let old_window = self.nth_window;

        if self.cursor >= self.cursor_range.end {
            self.nth_window = self.nth_window.saturating_add(1).min(
                self.list
                    .windows(self.cursor_upper_bound(wid_height))
                    .count()
                    - 1,
            );
        } else {
            self.cursor = (self.cursor + 1).min(self.cursor_upper_bound(wid_height) - 1);
        }
        self.hovered = self.window(wid_height).get(self.cursor).cloned();
        self.cursor != old_cursor || self.nth_window != old_window
    }

    pub fn prev_elem(&mut self, wid_height: usize) -> bool {
        if self.list.is_empty() {
            emit!(Popup(vec!["List is empty".into()]));
            return true;
        }
        self.set_cursor_range(wid_height);
        let old_cursor = self.cursor;
        let old_window = self.nth_window;

        if self.cursor < self.cursor_range.start {
            self.nth_window = self.nth_window.saturating_sub(1);
        } else {
            self.cursor = self.cursor.saturating_sub(1);
        }

        self.hovered = self.window(wid_height).get(self.cursor).cloned();
        self.cursor != old_cursor || self.nth_window != old_window
    }

    fn set_cursor_range(&mut self, wid_height: usize) {
        let mut b = self.cursor_upper_bound(wid_height);
        if self.cursor_upper_bound(wid_height) >= wid_height {
            b = self.cursor_upper_bound(wid_height).saturating_sub(3)
        }
        if self.nth_window == 0 {
            //first window
            self.cursor_range = 0..b;
        } else if self.nth_window
            == (self
                .list
                .windows(self.cursor_upper_bound(wid_height))
                .count()
                - 1)
        {
            // last_window
            self.cursor_range = 3..self.cursor_upper_bound(wid_height);
        } else {
            self.cursor_range = 3..self.cursor_upper_bound(wid_height) - 3;
        }
    }

    fn cursor_upper_bound(&self, wid_height: usize) -> usize {
        wid_height.min(self.list.len())
    }

    pub fn window(&self, wid_height: usize) -> &[T] {
        self.list
            .windows(self.cursor_upper_bound(wid_height))
            .nth(self.nth_window)
            .unwrap_or(&[])
    }
    pub fn hovered(&self) -> Option<&T> {
        self.hovered.as_ref()
    }
}