diff --git a/src/main.rs b/src/main.rs index b46a71e..017c6a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,7 +73,10 @@ fn main() -> Result<()> { // Load or create model let mut model = if let Some(ref path) = file_path { if path.exists() { - persistence::load(path).with_context(|| format!("Failed to load {}", path.display()))? + let mut m = persistence::load(path) + .with_context(|| format!("Failed to load {}", path.display()))?; + m.normalize_view_state(); + m } else { let name = path.file_stem() .and_then(|s| s.to_str()) diff --git a/src/ui/app.rs b/src/ui/app.rs index 63f48a3..004b17d 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -594,6 +594,11 @@ impl App { // ── Panel key handlers ─────────────────────────────────────────────────── fn handle_formula_panel_key(&mut self, key: KeyEvent) -> Result<()> { + // Clamp cursor in case the formula list shrank since it was last set. + let flen = self.model.formulas.len(); + if flen == 0 { self.formula_cursor = 0; } + else { self.formula_cursor = self.formula_cursor.min(flen - 1); } + match key.code { KeyCode::Esc | KeyCode::Tab => { self.mode = AppMode::Normal; } KeyCode::Char('a') | KeyCode::Char('n') | KeyCode::Char('o') => { @@ -882,8 +887,10 @@ impl App { KeyCode::Backspace => wizard.pop_name_char(), KeyCode::Enter => { match wizard.build_model() { - Ok(model) => { + Ok(mut model) => { + model.normalize_view_state(); self.model = model; + self.formula_cursor = 0; self.dirty = true; self.status_msg = "Import successful! Press :w to save.".to_string(); self.mode = AppMode::Normal; @@ -956,9 +963,16 @@ impl App { } fn scroll_rows(&mut self, delta: i32) { + let row_max = { + let view = match self.model.active_view() { Some(v) => v, None => return }; + let row_cats: Vec = view.categories_on(Axis::Row).into_iter().map(String::from).collect(); + cross_product_strs(&row_cats, &self.model, view).len().saturating_sub(1) + }; if let Some(view) = self.model.active_view_mut() { - let new_r = (view.selected.0 as i32 + delta).max(0) as usize; - view.selected.0 = new_r; + let nr = (view.selected.0 as i32 + delta).clamp(0, row_max as i32) as usize; + view.selected.0 = nr; + if nr < view.row_offset { view.row_offset = nr; } + if nr >= view.row_offset + 20 { view.row_offset = nr.saturating_sub(19); } } }