From 0fd9f1522ef9fb5d46863e5e170d04dc6b0d1d5e Mon Sep 17 00:00:00 2001 From: Rushmore75 Date: Tue, 11 Nov 2025 14:30:30 -0700 Subject: [PATCH] fix scrolling --- src/app/app.rs | 10 +++--- src/app/screen.rs | 85 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/app/app.rs b/src/app/app.rs index 76d6229..8d54ccc 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -63,7 +63,7 @@ impl Widget for &App { x_idx = x as usize - 1 + self.screen.scroll_x(); } if y != 0 { - y_idx = y as usize - 1 + self.screen.y(); + y_idx = y as usize - 1 + self.screen.scroll_y(); } if is_selected(x.into(), y.into()) { @@ -216,7 +216,7 @@ impl App { frame.render_widget(Paragraph::new(format!("x/w y/h: cursor{:?} scroll({}, {}) cell({}, {}) screen({}, {})", self.grid.selected_cell, self.screen.scroll_x(), - self.screen.y(), + self.screen.scroll_y(), self.screen.get_cell_width(&self.vars), self.screen.get_cell_height(&self.vars), body.width, @@ -225,9 +225,6 @@ impl App { } fn handle_events(&mut self) -> io::Result<()> { - // make sure cursor is inside window - self.screen.scroll_based_on_cursor_location(self.grid.selected_cell, &self.vars); - match &mut self.mode { Mode::Chord(chord) => match event::read()? { event::Event::Key(key) => match key.code { @@ -312,6 +309,9 @@ impl App { }, } + // make sure cursor is inside window + self.screen.scroll_based_on_cursor_location(self.grid.selected_cell, &self.vars); + Ok(()) } } diff --git a/src/app/screen.rs b/src/app/screen.rs index d096eb8..046bf2f 100644 --- a/src/app/screen.rs +++ b/src/app/screen.rs @@ -25,27 +25,45 @@ impl ScreenSpace { pub fn scroll_based_on_cursor_location(&mut self, (cursor_x, cursor_y): (usize, usize), vars: &HashMap) { if let Ok(screen_size) = self.last_seen_screen_size.read() { - - // screen seems to be 2 cells smaller than it should be - let x_cells = (screen_size.0 / self.get_cell_width(vars) as usize)-2; + // ======= X ======= + let x_cells = (screen_size.0) / self.get_cell_width(vars) as usize ; let lower_x = self.scroll_x(); - let upper_x = self.scroll_x() + x_cells; + // screen seems to be 2 cells smaller than it should be + let upper_x = self.scroll_x() + x_cells -2; - if cursor_x<=lower_x { - self.scroll.0 = self.scroll.0.saturating_sub(1); + if cursor_x < lower_x { + let delta = lower_x - cursor_x; + self.scroll.0 = self.scroll.0.saturating_sub(delta); } if cursor_x > upper_x { - self.scroll.0 = self.scroll.0.saturating_add(1); + let delta = cursor_x - upper_x; + self.scroll.0 = self.scroll.0.saturating_add(delta); } + // ======= Y ======= + let y_cells = screen_size.1 / self.get_cell_height(vars) as usize; + + let lower_y = self.scroll_y(); + // screen seems to be 2 cells smaller than it should be + let upper_y = self.scroll_y() + y_cells -2; + + if cursor_y < lower_y { + let delta = lower_y - cursor_y; + self.scroll.1 = self.scroll.1.saturating_sub(delta); + } + + if cursor_y > upper_y { + let delta = cursor_y - upper_y; + self.scroll.1 = self.scroll.1.saturating_add(delta); + } } } pub fn scroll_x(&self) -> usize { self.scroll.0 } - pub fn y(&self) -> usize{ + pub fn scroll_y(&self) -> usize{ self.scroll.1 } pub fn get_cell_height(&self, vars: &HashMap) -> usize { @@ -78,3 +96,54 @@ impl ScreenSpace { } } +#[test] +fn fit_cells() { + use crate::App; + let mut app = App::new(); + app.vars.insert("length".to_string(), 10.to_string()); + app.vars.insert("height".to_string(), 1.to_string()); + + let (x,y) = app.screen.how_many_cells_fit_in(&Rect::new(0, 0, 181, 14), &app.vars); + assert_eq!(x, 18); + assert_eq!(y, 14); +} + +#[test] +fn scroll() { + use crate::App; + let mut app = App::new(); + app.vars.insert("length".to_string(), 10.to_string()); + app.vars.insert("height".to_string(), 1.to_string()); + + // We have to check how many cells fit, because screen learns the width + // of the area by rumour here. + let (x,y) = app.screen.how_many_cells_fit_in(&Rect::new(0, 0, 181, 14), &app.vars); + assert_eq!(x, 18); + assert_eq!(y, 14); + + // we aren't scrolled at all yet + app.screen.scroll_based_on_cursor_location((0,0), &app.vars); + assert_eq!(app.screen.scroll.0, 0); + assert_eq!(app.screen.scroll.1, 0); + + // at the edge of visible, but shouldn't scroll yet + app.screen.scroll_based_on_cursor_location((18,0), &app.vars); + assert_eq!(app.screen.scroll.0, 0); + assert_eq!(app.screen.scroll.1, 0); + + // scroll 1 right + app.screen.scroll_based_on_cursor_location((19,0), &app.vars); + assert_eq!(app.screen.scroll.0, 1); + assert_eq!(app.screen.scroll.1, 0); + + // cursor comes back, scroll should stay + app.screen.scroll_based_on_cursor_location((18,0), &app.vars); + assert_eq!(app.screen.scroll.0, 1); + assert_eq!(app.screen.scroll.1, 0); + + // scroll left + app.screen.scroll_based_on_cursor_location((0,0), &app.vars); + assert_eq!(app.screen.scroll.0, 0); + assert_eq!(app.screen.scroll.1, 0); + +}