1#![deny(missing_docs)]
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 constants::{LAST_COLUMN, LAST_ROW},
7 expressions::utils::{is_valid_column_number, is_valid_row},
8 worksheet::NavigationDirection,
9};
10
11use super::common::UserModel;
12
13#[derive(Serialize, Deserialize)]
14#[cfg_attr(test, derive(PartialEq, Debug))]
15pub struct SelectedView {
16 pub sheet: u32,
17 pub row: i32,
18 pub column: i32,
19 pub range: [i32; 4],
20 pub top_row: i32,
21 pub left_column: i32,
22}
23
24impl<'a> UserModel<'a> {
25 pub fn get_selected_sheet(&self) -> u32 {
27 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
28 view.sheet
29 } else {
30 0
31 }
32 }
33
34 pub fn get_selected_cell(&self) -> (u32, i32, i32) {
36 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
37 view.sheet
38 } else {
39 0
40 };
41 if let Ok(worksheet) = self.model.workbook.worksheet(sheet) {
42 if let Some(view) = worksheet.views.get(&self.model.view_id) {
43 return (sheet, view.row, view.column);
44 }
45 }
46 (0, 1, 1)
48 }
49
50 pub fn get_selected_view(&self) -> SelectedView {
52 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
53 view.sheet
54 } else {
55 0
56 };
57 if let Ok(worksheet) = self.model.workbook.worksheet(sheet) {
58 if let Some(view) = worksheet.views.get(&self.model.view_id) {
59 return SelectedView {
60 sheet,
61 row: view.row,
62 column: view.column,
63 range: view.range,
64 top_row: view.top_row,
65 left_column: view.left_column,
66 };
67 }
68 }
69 SelectedView {
71 sheet: 0,
72 row: 1,
73 column: 1,
74 range: [1, 1, 1, 1],
75 top_row: 1,
76 left_column: 1,
77 }
78 }
79
80 pub fn set_selected_sheet(&mut self, sheet: u32) -> Result<(), String> {
82 if self.model.workbook.worksheet(sheet).is_err() {
83 return Err(format!("Invalid worksheet index {sheet}"));
84 }
85 if let Some(view) = self.model.workbook.views.get_mut(&0) {
86 view.sheet = sheet;
87 }
88 Ok(())
89 }
90
91 pub fn set_selected_cell(&mut self, row: i32, column: i32) -> Result<(), String> {
93 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
94 view.sheet
95 } else {
96 0
97 };
98 if !is_valid_column_number(column) {
99 return Err(format!("Invalid column: '{column}'"));
100 }
101 if !is_valid_row(row) {
102 return Err(format!("Invalid row: '{row}'"));
103 }
104 if self.model.workbook.worksheet(sheet).is_err() {
105 return Err(format!("Invalid worksheet index {sheet}"));
106 }
107 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
108 if let Some(view) = worksheet.views.get_mut(&0) {
109 view.row = row;
110 view.column = column;
111 view.range = [row, column, row, column];
112 }
113 }
114 Ok(())
115 }
116
117 pub fn set_selected_range(
119 &mut self,
120 start_row: i32,
121 start_column: i32,
122 end_row: i32,
123 end_column: i32,
124 ) -> Result<(), String> {
125 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
126 view.sheet
127 } else {
128 0
129 };
130
131 if !is_valid_column_number(start_column) {
132 return Err(format!("Invalid column: '{start_column}'"));
133 }
134 if !is_valid_row(start_row) {
135 return Err(format!("Invalid row: '{start_row}'"));
136 }
137
138 if !is_valid_column_number(end_column) {
139 return Err(format!("Invalid column: '{end_column}'"));
140 }
141 if !is_valid_row(end_row) {
142 return Err(format!("Invalid row: '{end_row}'"));
143 }
144 if self.model.workbook.worksheet(sheet).is_err() {
145 return Err(format!("Invalid worksheet index {sheet}"));
146 }
147 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
148 if let Some(view) = worksheet.views.get_mut(&0) {
149 let selected_row = view.row;
150 let selected_column = view.column;
151 if start_row == 1 && end_row == LAST_ROW {
152 if selected_column != start_column && selected_column != end_column {
154 return Err(format!(
155 "The selected cell is not the column edge. Column '{selected_column}' and column range '({start_column}, {end_column})'"
156 ));
157 }
158 } else if start_column == 1 && end_column == LAST_COLUMN {
159 if selected_row != start_row && selected_row != end_row {
161 return Err(format!(
162 "The selected cell is not in the row edge. Row: '{selected_row}' and row range '({start_row}, {end_row})'"
163 ));
164 }
165 } else {
166 if selected_row != start_row && selected_row != end_row {
168 return Err(format!(
169 "The selected cell is not in one of the corners. Row: '{selected_row}' and row range '({start_row}, {end_row})'"
170 ));
171 }
172 if selected_column != start_column && selected_column != end_column {
173 return Err(format!(
174 "The selected cell is not in one of the corners. Column '{selected_column}' and column range '({start_column}, {end_column})'"
175 ));
176 }
177 }
178 view.range = [start_row, start_column, end_row, end_column];
179 }
180 }
181 Ok(())
182 }
183
184 pub fn on_expand_selected_range(&mut self, key: &str) -> Result<(), String> {
186 let (sheet, window_width, window_height) =
187 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
188 (
189 view.sheet,
190 view.window_width as f64,
191 view.window_height as f64,
192 )
193 } else {
194 return Ok(());
195 };
196 let (selected_row, selected_column, range, top_row, left_column) =
197 if let Ok(worksheet) = self.model.workbook.worksheet(sheet) {
198 if let Some(view) = worksheet.views.get(&self.model.view_id) {
199 (
200 view.row,
201 view.column,
202 view.range,
203 view.top_row,
204 view.left_column,
205 )
206 } else {
207 return Ok(());
208 }
209 } else {
210 return Ok(());
211 };
212 let [row_start, column_start, row_end, column_end] = range;
213 if ["ArrowUp", "ArrowDown"].contains(&key) && row_start == 1 && row_end == LAST_ROW {
214 return Ok(());
216 }
217 if ["ArrowRight", "ArrowLeft"].contains(&key)
218 && column_start == 1
219 && column_end == LAST_COLUMN
220 {
221 return Ok(());
223 }
224 let worksheet = self.model.workbook.worksheet(sheet)?;
225
226 match key {
227 "ArrowRight" => {
228 if selected_column > column_start {
229 let mut new_column = column_start + 1;
230 while new_column < LAST_COLUMN && worksheet.is_column_hidden(new_column)? {
231 new_column += 1;
232 }
233 if !(is_valid_column_number(new_column)) {
234 return Ok(());
235 }
236 self.set_selected_range(row_start, new_column, row_end, column_end)?;
237 } else {
238 let mut new_column = column_end + 1;
239 while new_column < LAST_COLUMN && worksheet.is_column_hidden(new_column)? {
240 new_column += 1;
241 }
242 if !is_valid_column_number(new_column) {
243 return Ok(());
244 }
245 let mut width = 0.0;
247 let mut c = left_column;
248 while c <= new_column {
249 width += self.model.get_column_width(sheet, c)?;
250 c += 1;
251 }
252 if width > window_width {
253 self.set_top_left_visible_cell(top_row, left_column + 1)?;
254 }
255 self.set_selected_range(row_start, column_start, row_end, new_column)?;
256 }
257 }
258 "ArrowLeft" => {
259 if selected_column < column_end {
260 let mut new_column = column_end - 1;
261 while new_column > 1 && worksheet.is_column_hidden(new_column)? {
262 new_column -= 1;
263 }
264 if !is_valid_column_number(new_column) {
265 return Ok(());
266 }
267 if new_column < left_column {
268 self.set_top_left_visible_cell(top_row, new_column)?;
269 }
270 self.set_selected_range(row_start, column_start, row_end, new_column)?;
271 } else {
272 let mut new_column = column_start - 1;
273 while new_column > 1 && worksheet.is_column_hidden(new_column)? {
274 new_column -= 1;
275 }
276 if !is_valid_column_number(new_column) {
277 return Ok(());
278 }
279 if new_column < left_column {
280 self.set_top_left_visible_cell(top_row, new_column)?;
281 }
282 self.set_selected_range(row_start, new_column, row_end, column_end)?;
283 }
284 }
285 "ArrowUp" => {
286 if selected_row < row_end {
287 let mut new_row = row_end - 1;
288 while new_row > 1 && worksheet.is_row_hidden(new_row)? {
289 new_row -= 1;
290 }
291 if !is_valid_row(new_row) {
292 return Ok(());
293 }
294 self.set_selected_range(row_start, column_start, new_row, column_end)?;
295 } else {
296 let mut new_row = row_start - 1;
297 while new_row > 1 && worksheet.is_row_hidden(new_row)? {
298 new_row -= 1;
299 }
300 if !is_valid_row(new_row) {
301 return Ok(());
302 }
303 if new_row < top_row {
304 self.set_top_left_visible_cell(new_row, left_column)?;
305 }
306 self.set_selected_range(new_row, column_start, row_end, column_end)?;
307 }
308 }
309 "ArrowDown" => {
310 if selected_row > row_start {
311 let mut new_row = row_start + 1;
312 while new_row < LAST_ROW && worksheet.is_row_hidden(new_row)? {
313 new_row += 1;
314 }
315 if !is_valid_row(new_row) {
316 return Ok(());
317 }
318 self.set_selected_range(new_row, column_start, row_end, column_end)?;
319 } else {
320 let mut new_row = row_end + 1;
321 while new_row < LAST_ROW && worksheet.is_row_hidden(new_row)? {
322 new_row += 1;
323 }
324 if !is_valid_row(new_row) {
325 return Ok(());
326 }
327 let mut height = 0.0;
328 let mut r = top_row;
329 while r <= new_row + 1 {
330 height += self.model.get_row_height(sheet, r)?;
331 r += 1;
332 }
333 if height >= window_height {
334 self.set_top_left_visible_cell(top_row + 1, left_column)?;
335 }
336 self.set_selected_range(row_start, column_start, new_row, column_end)?;
337 }
338 }
339 _ => {}
340 }
341
342 Ok(())
343 }
344
345 pub fn set_top_left_visible_cell(
347 &mut self,
348 top_row: i32,
349 left_column: i32,
350 ) -> Result<(), String> {
351 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
352 view.sheet
353 } else {
354 0
355 };
356
357 if !is_valid_column_number(left_column) {
358 return Err(format!("Invalid column: '{left_column}'"));
359 }
360 if !is_valid_row(top_row) {
361 return Err(format!("Invalid row: '{top_row}'"));
362 }
363 if self.model.workbook.worksheet(sheet).is_err() {
364 return Err(format!("Invalid worksheet index {sheet}"));
365 }
366 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
367 if let Some(view) = worksheet.views.get_mut(&0) {
368 view.top_row = top_row;
369 view.left_column = left_column;
370 }
371 }
372 Ok(())
373 }
374
375 pub fn set_window_width(&mut self, window_width: f64) {
377 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
378 view.window_width = window_width as i64;
379 };
380 }
381
382 pub fn get_window_width(&mut self) -> Result<i64, String> {
384 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
385 return Ok(view.window_width);
386 };
387 Err("View not found".to_string())
388 }
389
390 pub fn set_window_height(&mut self, window_height: f64) {
392 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
393 view.window_height = window_height as i64;
394 };
395 }
396
397 pub fn get_window_height(&mut self) -> Result<i64, String> {
399 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
400 return Ok(view.window_height);
401 };
402 Err("View not found".to_string())
403 }
404
405 pub fn on_arrow_right(&mut self) -> Result<(), String> {
407 let (sheet, window_width) =
408 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
409 (view.sheet, view.window_width)
410 } else {
411 return Err("View not found".to_string());
412 };
413 let worksheet = match self.model.workbook.worksheet(sheet) {
414 Ok(s) => s,
415 Err(_) => return Err("Worksheet not found".to_string()),
416 };
417 let view = match worksheet.views.get(&self.model.view_id) {
418 Some(s) => s,
419 None => return Err("View not found".to_string()),
420 };
421 let mut new_column = view.column + 1;
422 while new_column <= LAST_COLUMN
423 && self
424 .model
425 .workbook
426 .worksheet(sheet)?
427 .is_column_hidden(new_column)?
428 {
429 new_column += 1;
430 }
431 if !is_valid_column_number(new_column) {
432 return Ok(());
433 }
434 let mut width = 0.0;
436 let mut column = view.left_column;
437 while column <= new_column {
438 width += self.model.get_column_width(sheet, column)?;
439 column += 1;
440 }
441 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
442 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
443 view.column = new_column;
444 view.range = [view.row, new_column, view.row, new_column];
445 if width > window_width as f64 {
446 view.left_column += 1;
447 }
448 }
449 }
450 Ok(())
451 }
452
453 pub fn on_arrow_left(&mut self) -> Result<(), String> {
455 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
456 view.sheet
457 } else {
458 return Err("View not found".to_string());
459 };
460 let worksheet = match self.model.workbook.worksheet(sheet) {
461 Ok(s) => s,
462 Err(_) => return Err("Worksheet not found".to_string()),
463 };
464 let view = match worksheet.views.get(&self.model.view_id) {
465 Some(s) => s,
466 None => return Err("View not found".to_string()),
467 };
468 let mut new_column = view.column - 1;
469 while new_column >= 1
470 && self
471 .model
472 .workbook
473 .worksheet(sheet)?
474 .is_column_hidden(new_column)?
475 {
476 new_column -= 1;
477 }
478 if !is_valid_column_number(new_column) {
479 return Ok(());
480 }
481 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
483 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
484 view.column = new_column;
485 view.range = [view.row, new_column, view.row, new_column];
486 if new_column < view.left_column {
487 view.left_column = new_column;
488 }
489 }
490 }
491 Ok(())
492 }
493
494 pub fn on_arrow_up(&mut self) -> Result<(), String> {
496 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
497 view.sheet
498 } else {
499 return Err("View not found".to_string());
500 };
501 let worksheet = match self.model.workbook.worksheet(sheet) {
502 Ok(s) => s,
503 Err(_) => return Err("Worksheet not found".to_string()),
504 };
505 let view = match worksheet.views.get(&self.model.view_id) {
506 Some(s) => s,
507 None => return Err("View not found".to_string()),
508 };
509 let mut new_row = view.row - 1;
510 while new_row >= 1
511 && self
512 .model
513 .workbook
514 .worksheet(sheet)?
515 .is_row_hidden(new_row)?
516 {
517 new_row -= 1;
518 }
519 if !is_valid_row(new_row) {
520 return Ok(());
521 }
522 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
524 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
525 view.row = new_row;
526 view.range = [new_row, view.column, new_row, view.column];
527 if new_row < view.top_row {
528 view.top_row = new_row;
529 }
530 }
531 }
532 Ok(())
533 }
534
535 pub fn on_arrow_down(&mut self) -> Result<(), String> {
537 let (sheet, window_height) =
538 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
539 (view.sheet, view.window_height)
540 } else {
541 return Err("View not found".to_string());
542 };
543 let worksheet = match self.model.workbook.worksheet(sheet) {
544 Ok(s) => s,
545 Err(_) => return Err("Worksheet not found".to_string()),
546 };
547 let view = match worksheet.views.get(&self.model.view_id) {
548 Some(s) => s,
549 None => return Err("View not found".to_string()),
550 };
551 let mut new_row = view.row + 1;
552 while new_row <= LAST_ROW
553 && self
554 .model
555 .workbook
556 .worksheet(sheet)?
557 .is_row_hidden(new_row)?
558 {
559 new_row += 1;
560 }
561 if !is_valid_row(new_row) {
562 return Ok(());
563 }
564 let mut height = 0.0;
566 let mut row = view.top_row;
567 while row <= new_row + 1 && row <= LAST_ROW {
568 height += self.model.get_row_height(sheet, row)?;
569 row += 1;
570 }
571 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
572 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
573 view.row = new_row;
574 view.range = [new_row, view.column, new_row, view.column];
575 if height > window_height as f64 {
576 view.top_row += 1;
577 }
578 }
579 }
580 Ok(())
581 }
582
583 pub fn get_scroll_x(&self) -> Result<f64, String> {
586 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
587 view.sheet
588 } else {
589 return Err("View not found".to_string());
590 };
591 let worksheet = match self.model.workbook.worksheet(sheet) {
592 Ok(s) => s,
593 Err(_) => return Err("Worksheet not found".to_string()),
594 };
595 let view = match worksheet.views.get(&self.model.view_id) {
596 Some(s) => s,
597 None => return Err("View not found".to_string()),
598 };
599 let mut scroll_x = 0.0;
600 for column in 1..view.left_column {
601 scroll_x += self.model.get_column_width(sheet, column)?;
602 }
603 Ok(scroll_x)
604 }
605
606 pub fn get_scroll_y(&self) -> Result<f64, String> {
609 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
610 view.sheet
611 } else {
612 return Err("View not found".to_string());
613 };
614 let worksheet = match self.model.workbook.worksheet(sheet) {
615 Ok(s) => s,
616 Err(_) => return Err("Worksheet not found".to_string()),
617 };
618 let view = match worksheet.views.get(&self.model.view_id) {
619 Some(s) => s,
620 None => return Err("View not found".to_string()),
621 };
622 let mut scroll_y = 0.0;
623 for row in 1..view.top_row {
624 scroll_y += self.model.get_row_height(sheet, row)?;
625 }
626 Ok(scroll_y)
627 }
628
629 pub fn on_page_down(&mut self) -> Result<(), String> {
632 let (sheet, window_height) =
633 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
634 (view.sheet, view.window_height)
635 } else {
636 return Err("View not found".to_string());
637 };
638 let worksheet = match self.model.workbook.worksheet(sheet) {
639 Ok(s) => s,
640 Err(_) => return Err("Worksheet not found".to_string()),
641 };
642 let view = match worksheet.views.get(&self.model.view_id) {
643 Some(s) => s,
644 None => return Err("View not found".to_string()),
645 };
646 let mut last_row = view.top_row;
647 let mut height = self.model.get_row_height(sheet, last_row)?;
648 while height <= window_height as f64 {
649 last_row += 1;
650 height += self.model.get_row_height(sheet, last_row)?;
651 }
652 if !is_valid_row(last_row) {
653 return Ok(());
654 }
655 let row_delta = view.row - view.top_row;
656 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
657 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
658 view.top_row = last_row;
659 view.row = view.top_row + row_delta;
660 view.range = [view.row, view.column, view.row, view.column];
661 }
662 }
663 Ok(())
664 }
665
666 pub fn on_page_up(&mut self) -> Result<(), String> {
668 let (sheet, window_height) =
669 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
670 (view.sheet, view.window_height as f64)
671 } else {
672 return Err("View not found".to_string());
673 };
674 let worksheet = match self.model.workbook.worksheet(sheet) {
675 Ok(s) => s,
676 Err(_) => return Err("Worksheet not found".to_string()),
677 };
678 let view = match worksheet.views.get(&self.model.view_id) {
679 Some(s) => s,
680 None => return Err("View not found".to_string()),
681 };
682
683 let mut first_row = view.top_row;
684 let mut height = self.model.get_row_height(sheet, first_row)?;
685 while height <= window_height && first_row > 1 {
686 first_row -= 1;
687 height += self.model.get_row_height(sheet, first_row)?;
688 }
689
690 let row_delta = view.row - view.top_row;
691 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
692 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
693 view.top_row = first_row;
694 view.row = view.top_row + row_delta;
695 view.range = [view.row, view.column, view.row, view.column];
696 }
697 }
698 Ok(())
699 }
700
701 pub fn on_area_selecting(&mut self, target_row: i32, target_column: i32) -> Result<(), String> {
703 let (sheet, window_width, window_height) =
704 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
705 (
706 view.sheet,
707 view.window_width as f64,
708 view.window_height as f64,
709 )
710 } else {
711 return Ok(());
712 };
713 let (selected_row, selected_column, range, top_row, left_column) =
714 if let Ok(worksheet) = self.model.workbook.worksheet(sheet) {
715 if let Some(view) = worksheet.views.get(&self.model.view_id) {
716 (
717 view.row,
718 view.column,
719 view.range,
720 view.top_row,
721 view.left_column,
722 )
723 } else {
724 return Ok(());
725 }
726 } else {
727 return Ok(());
728 };
729 let [row_start, column_start, _row_end, _column_end] = range;
730
731 let mut new_left_column = left_column;
732 if target_column >= selected_column {
733 let mut width = 0.0;
734 let mut column = left_column;
735 while column <= target_column {
736 width += self.model.get_column_width(sheet, column)?;
737 column += 1;
738 }
739
740 while width > window_width {
741 width -= self.model.get_column_width(sheet, new_left_column)?;
742 new_left_column += 1;
743 }
744 } else if target_column < new_left_column {
745 new_left_column = target_column;
746 }
747 let mut new_top_row = top_row;
748 if target_row >= selected_row {
749 let mut height = 0.0;
750 let mut row = top_row;
751 while row <= target_row {
752 height += self.model.get_row_height(sheet, row)?;
753 row += 1;
754 }
755 while height > window_height {
756 height -= self.model.get_row_height(sheet, new_top_row)?;
757 new_top_row += 1;
758 }
759 } else if target_row < new_top_row {
760 new_top_row = target_row;
761 }
762
763 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
764 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
765 view.range = [row_start, column_start, target_row, target_column];
766 if new_top_row != top_row {
767 view.top_row = new_top_row;
768 }
769 if new_left_column != left_column {
770 view.left_column = new_left_column;
771 }
772 }
773 }
774
775 Ok(())
776 }
777
778 pub fn on_navigate_to_edge_in_direction(
780 &mut self,
781 direction: NavigationDirection,
782 ) -> Result<(), String> {
783 let (sheet, window_height, window_width) =
784 if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
785 (view.sheet, view.window_height, view.window_width)
786 } else {
787 return Err("View not found".to_string());
788 };
789 let worksheet = match self.model.workbook.worksheet(sheet) {
790 Ok(s) => s,
791 Err(_) => return Err("Worksheet not found".to_string()),
792 };
793 let view = match worksheet.views.get(&self.model.view_id) {
794 Some(s) => s,
795 None => return Err("View not found".to_string()),
796 };
797 let row = view.row;
798 let column = view.column;
799 if !is_valid_row(row) || !is_valid_column_number(column) {
800 return Err("Invalid row or column".to_string());
801 }
802 let (new_row, new_column) =
803 worksheet.navigate_to_edge_in_direction(row, column, direction)?;
804 if !is_valid_row(new_row) || !is_valid_column_number(new_column) {
805 return Err("Invalid row or column after navigation".to_string());
806 }
807 if new_row == row && new_column == column {
808 return Ok(()); }
810
811 let mut top_row = view.top_row;
812 let mut left_column = view.left_column;
813
814 match direction {
815 NavigationDirection::Left | NavigationDirection::Right => {
816 if new_column < view.left_column {
821 left_column = new_column;
822 } else {
823 let mut c = new_column;
824 let mut width = self.model.get_column_width(sheet, c)?;
825 while c > 1 && width <= window_width as f64 {
826 c -= 1;
827 width += self.model.get_column_width(sheet, c)?;
828 }
829 if c > view.left_column {
830 left_column = c;
831 }
832 }
833 }
834 NavigationDirection::Up | NavigationDirection::Down => {
835 if new_row < view.top_row {
840 top_row = new_row;
841 } else {
842 let mut r = new_row;
843 let mut height = self.model.get_row_height(sheet, r)?;
844 while r > 1 && height <= window_height as f64 {
845 r -= 1;
846 height += self.model.get_row_height(sheet, r)?;
847 }
848 if r > view.top_row {
849 top_row = r;
850 }
851 }
852 }
853 }
854
855 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
856 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
857 view.row = new_row;
858 view.column = new_column;
859 view.range = [new_row, new_column, new_row, new_column];
860
861 view.top_row = top_row;
862 view.left_column = left_column;
863 }
864 }
865 Ok(())
866 }
867}