1#[derive(Debug, Clone, Default)]
14pub struct TableNav {
15 pub active_row: usize,
17 pub active_col: usize,
19}
20
21impl TableNav {
22 pub fn new() -> Self {
24 Self::default()
25 }
26
27 pub fn move_up(&mut self, total_rows: usize) -> bool {
31 if total_rows == 0 {
32 return false;
33 }
34 if self.active_row > 0 {
35 self.active_row -= 1;
36 true
37 } else {
38 false
39 }
40 }
41
42 pub fn move_down(&mut self, total_rows: usize) -> bool {
46 if total_rows == 0 {
47 return false;
48 }
49 if self.active_row + 1 < total_rows {
50 self.active_row += 1;
51 true
52 } else {
53 false
54 }
55 }
56
57 pub fn move_left(&mut self, total_cols: usize) -> bool {
61 if total_cols == 0 {
62 return false;
63 }
64 if self.active_col > 0 {
65 self.active_col -= 1;
66 true
67 } else {
68 false
69 }
70 }
71
72 pub fn move_right(&mut self, total_cols: usize) -> bool {
76 if total_cols == 0 {
77 return false;
78 }
79 if self.active_col + 1 < total_cols {
80 self.active_col += 1;
81 true
82 } else {
83 false
84 }
85 }
86
87 pub fn move_home_row(&mut self) -> bool {
89 if self.active_row != 0 {
90 self.active_row = 0;
91 true
92 } else {
93 false
94 }
95 }
96
97 pub fn move_end_row(&mut self, total_rows: usize) -> bool {
101 let last = total_rows.saturating_sub(1);
102 if self.active_row != last {
103 self.active_row = last;
104 true
105 } else {
106 false
107 }
108 }
109
110 pub fn page_up(&mut self, page_size: usize) -> bool {
114 let new_row = self.active_row.saturating_sub(page_size);
115 if new_row != self.active_row {
116 self.active_row = new_row;
117 true
118 } else {
119 false
120 }
121 }
122
123 pub fn page_down(&mut self, total_rows: usize, page_size: usize) -> bool {
128 if total_rows == 0 {
129 return false;
130 }
131 let new_row = (self.active_row + page_size).min(total_rows.saturating_sub(1));
132 if new_row != self.active_row {
133 self.active_row = new_row;
134 true
135 } else {
136 false
137 }
138 }
139
140 pub fn set_position(&mut self, row: usize, col: usize) {
142 self.active_row = row;
143 self.active_col = col;
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn default_is_top_left() {
153 let nav = TableNav::new();
154 assert_eq!(nav.active_row, 0);
155 assert_eq!(nav.active_col, 0);
156 }
157
158 #[test]
159 fn move_down_increments_row() {
160 let mut nav = TableNav::new();
161 assert!(nav.move_down(5));
162 assert_eq!(nav.active_row, 1);
163 }
164
165 #[test]
166 fn move_down_clamps_at_last_row() {
167 let mut nav = TableNav::new();
168 nav.active_row = 4;
169 assert!(!nav.move_down(5)); assert_eq!(nav.active_row, 4);
171 }
172
173 #[test]
174 fn move_up_clamps_at_zero() {
175 let mut nav = TableNav::new();
176 assert!(!nav.move_up(5));
177 assert_eq!(nav.active_row, 0);
178 }
179
180 #[test]
181 fn move_left_right() {
182 let mut nav = TableNav::new();
183 assert!(!nav.move_left(3));
184 assert!(nav.move_right(3));
185 assert_eq!(nav.active_col, 1);
186 nav.active_col = 2;
187 assert!(!nav.move_right(3));
188 assert_eq!(nav.active_col, 2);
189 }
190
191 #[test]
192 fn page_up_down() {
193 let mut nav = TableNav::new();
194 nav.active_row = 10;
195 assert!(nav.page_up(4));
196 assert_eq!(nav.active_row, 6);
197 assert!(nav.page_down(20, 4));
198 assert_eq!(nav.active_row, 10);
199 assert!(nav.page_down(12, 100));
201 assert_eq!(nav.active_row, 11);
202 }
203
204 #[test]
205 fn home_end() {
206 let mut nav = TableNav::new();
207 nav.active_row = 7;
208 assert!(nav.move_home_row());
209 assert_eq!(nav.active_row, 0);
210 assert!(!nav.move_home_row());
212
213 assert!(nav.move_end_row(10));
214 assert_eq!(nav.active_row, 9);
215 assert!(!nav.move_end_row(10));
217 }
218
219 #[test]
220 fn no_op_on_zero_rows() {
221 let mut nav = TableNav::new();
222 assert!(!nav.move_up(0));
223 assert!(!nav.move_down(0));
224 assert!(!nav.page_down(0, 5));
225 assert!(!nav.move_end_row(0));
226 assert_eq!(nav.active_row, 0);
227 }
228
229 #[test]
230 fn set_position_updates() {
231 let mut nav = TableNav::new();
232 nav.set_position(5, 3);
233 assert_eq!(nav.active_row, 5);
234 assert_eq!(nav.active_col, 3);
235 }
236}