fm/modes/utils/
content_window.rs1use std::cmp::{max, min};
2
3#[derive(Debug, Clone)]
9pub struct ContentWindow {
10 pub top: usize,
12 pub bottom: usize,
14 pub len: usize,
16 pub height: usize,
18}
19
20impl Default for ContentWindow {
21 fn default() -> Self {
22 Self::new(0, 80)
23 }
24}
25
26impl ContentWindow {
27 pub const WINDOW_PADDING: usize = 4;
29 pub const WINDOW_PADDING_FUZZY: u32 = 3;
30 pub const WINDOW_MARGIN_TOP_U16: u16 = 2;
32 pub const WINDOW_MARGIN_BOTTOM: usize = 1;
34 pub const HEADER_ROWS: usize = 3;
36 const FOOTER_ROWS: usize = 2;
38
39 fn nb_displayed_rows(rect_height: usize) -> usize {
43 rect_height.saturating_sub(Self::HEADER_ROWS + Self::FOOTER_ROWS)
44 }
45
46 fn default_bottom(len: usize, used_height: usize) -> usize {
49 min(len, used_height)
50 }
51
52 pub fn new(len: usize, rect_height: usize) -> Self {
55 let height = Self::nb_displayed_rows(rect_height);
56 let top = 0;
57 let bottom = Self::default_bottom(len, height);
58 ContentWindow {
59 top,
60 bottom,
61 len,
62 height,
63 }
64 }
65
66 pub fn set_height(&mut self, terminal_height: usize) {
68 self.height = Self::nb_displayed_rows(terminal_height);
69 self.bottom = Self::default_bottom(self.len, self.height);
70 }
71
72 pub fn set_len(&mut self, len: usize) {
73 self.len = len;
74 self.bottom = Self::default_bottom(len, self.height);
75 }
76
77 pub fn scroll_up_one(&mut self, index: usize) {
80 if (index < self.top + Self::WINDOW_PADDING || index > self.bottom) && self.top > 0 {
81 self.top -= 1;
82 self.bottom -= 1;
83 }
84 self.scroll_to(index)
85 }
86
87 pub fn scroll_down_one(&mut self, index: usize) {
90 if self.len < self.height {
91 return;
92 }
93 if index < self.top || index + Self::WINDOW_PADDING > self.bottom {
94 self.top += 1;
95 self.bottom += 1;
96 }
97 self.scroll_to(index)
98 }
99
100 pub fn scroll_to(&mut self, index: usize) {
103 if self.len < self.height {
104 return;
105 }
106 if self.is_index_outside_window(index) {
107 let height = max(self.bottom.saturating_sub(self.top), self.height);
108 self.top = index.saturating_sub(Self::WINDOW_PADDING);
109 self.bottom = self.top + height;
110 }
111 }
112
113 pub fn reset(&mut self, len: usize) {
115 self.len = len;
116 self.top = 0;
117 self.bottom = Self::default_bottom(self.len, self.height);
118 }
119
120 fn is_index_outside_window(&self, index: usize) -> bool {
124 index < self.top || index >= self.bottom
125 }
126
127 pub fn is_row_in_header(row: u16) -> bool {
128 row < Self::HEADER_ROWS as u16
129 }
130
131 pub fn preview_page_up(&mut self, skip: usize) {
132 if self.top == 0 {
133 return;
134 }
135 let skip = min(self.top, skip);
136 self.bottom -= skip;
137 self.top -= skip;
138 }
139
140 pub fn preview_page_down(&mut self, skip: usize, preview_len: usize) {
141 if self.bottom < preview_len {
142 let skip = min(preview_len - self.bottom, skip);
143 self.bottom += skip;
144 self.top += skip;
145 }
146 }
147}