diff --git a/src/main.rs b/src/main.rs index 730af89..2468ffd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -217,7 +217,7 @@ fn handle_key(app: &mut App, code: KeyCode) { _ => return, } } - + match code { KeyCode::Char('q') => app.should_exit = true, @@ -298,9 +298,34 @@ fn ui(frame: &mut Frame, app: &App) { ); } +fn compute_window(len: usize, selected: usize, viewport: usize) -> (usize, usize) { + if len == 0 || viewport == 0 { + return (0, 0); + } + + let viewport = viewport.min(len); + let half = viewport / 2; + + let mut start = selected.saturating_sub(half); + if start + viewport > len { + start = len - viewport; + } + + let end = start + viewport; + (start, end) +} + + fn render_categories(frame: &mut Frame, app: &App, left: Rect, right: Rect) { - let items: Vec = app - .items + // how many rows can we show inside the bordered block? + let viewport = left.height.saturating_sub(2) as usize; + + let len = app.items.len(); + let selected = app.selected.min(len.saturating_sub(1)); + + let (start, end) = compute_window(len, selected, viewport); + + let items: Vec = app.items[start..end] .iter() .map(|s| ListItem::new(s.as_str())) .collect(); @@ -311,11 +336,17 @@ fn render_categories(frame: &mut Frame, app: &App, left: Rect, right: Rect) { .highlight_style(Style::default().add_modifier(Modifier::REVERSED)); let mut state = ListState::default(); - state.select(Some(app.selected)); + state.select(Some(selected - start)); // selection relative to slice frame.render_stateful_widget(list, left, &mut state); - let detail = format!("Details for:\n\n{}", app.items[app.selected]); + // Right pane details (use the real selected item) + let detail = if len > 0 { + format!("Details for:\n\n{}", app.items[selected]) + } else { + "No items".to_string() + }; + frame.render_widget( Paragraph::new(detail) .block(Block::bordered().title("Details").merge_borders(MergeStrategy::Exact)),