Skip to content

Commit

Permalink
feat: scroll independently from selection
Browse files Browse the repository at this point in the history
  • Loading branch information
EdJoPaTo committed Feb 3, 2024
1 parent 14b9e42 commit 01726df
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
27 changes: 24 additions & 3 deletions examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ impl<'a> App<'a> {
)
.expect("all item identifiers are unique"),
TreeItem::new_leaf("h", "Hotel"),
TreeItem::new(
"i",
"India",
vec![
TreeItem::new_leaf("j", "Juliett"),
TreeItem::new_leaf("k", "Kilo"),
TreeItem::new_leaf("l", "Lima"),
TreeItem::new_leaf("m", "Mike"),
TreeItem::new_leaf("n", "November"),
],
)
.expect("all item identifiers are unique"),
TreeItem::new_leaf("o", "Oscar"),
],
}
}
Expand Down Expand Up @@ -95,8 +108,8 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<(
f.render_stateful_widget(items, area, &mut app.state);
})?;

if let Event::Key(key) = event::read()? {
match key.code {
match event::read()? {
Event::Key(key) => match key.code {
KeyCode::Char('q') => return Ok(()),
KeyCode::Char('\n' | ' ') => app.state.toggle_selected(),
KeyCode::Left => app.state.key_left(),
Expand All @@ -109,8 +122,16 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<(
KeyCode::End => {
app.state.select_last(&app.items);
}
KeyCode::PageDown => app.state.scroll_down(3),
KeyCode::PageUp => app.state.scroll_up(3),
_ => {}
},
Event::Mouse(mouse) => match mouse.kind {
event::MouseEventKind::ScrollDown => app.state.scroll_down(1),
event::MouseEventKind::ScrollUp => app.state.scroll_up(1),
_ => {}
}
},
_ => {}
}
}
}
37 changes: 29 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub struct TreeState<Identifier> {
offset: usize,
opened: HashSet<Vec<Identifier>>,
selected: Vec<Identifier>,
ensure_selected_in_view_on_next_render: bool,
}

impl<Identifier> TreeState<Identifier>
Expand Down Expand Up @@ -85,12 +86,7 @@ where
pub fn select(&mut self, identifier: Vec<Identifier>) -> bool {
let changed = self.selected != identifier;
self.selected = identifier;

// TODO: ListState does this. Is this relevant?
if self.selected.is_empty() {
self.offset = 0;
}

self.ensure_selected_in_view_on_next_render = true;
changed
}

Expand Down Expand Up @@ -126,6 +122,7 @@ where
/// See also [`toggle`](TreeState::toggle)
pub fn toggle_selected(&mut self) {
self.toggle(self.selected());
self.ensure_selected_in_view_on_next_render = true;
}

pub fn close_all(&mut self) {
Expand Down Expand Up @@ -210,6 +207,21 @@ where
self.select(new_identifier)
}

/// Ensure the selected [`TreeItem`] is visible on next render
pub fn scroll_selected_into_view(&mut self) {
self.ensure_selected_in_view_on_next_render = true;
}

/// Scroll the specified amount of lines up
pub fn scroll_up(&mut self, lines: usize) {
self.offset = self.offset.saturating_sub(lines);
}

/// Scroll the specified amount of lines down
pub fn scroll_down(&mut self, lines: usize) {
self.offset = self.offset.saturating_add(lines);
}

/// Handles the up arrow key.
/// Moves up in the current depth or to its parent.
pub fn key_up(&mut self, items: &[TreeItem<Identifier>]) {
Expand All @@ -235,12 +247,14 @@ where
// Select the parent by removing the leaf from selection
self.selected.pop();
}
self.ensure_selected_in_view_on_next_render = true;
}

/// Handles the right arrow key.
/// Opens the currently selected.
pub fn key_right(&mut self) {
self.open(self.selected());
self.ensure_selected_in_view_on_next_render = true;
}
}

Expand Down Expand Up @@ -579,7 +593,13 @@ where
.unwrap_or(0)
};

let mut start = state.offset.min(selected_index);
// Ensure last line is still visible
let mut start = state.offset.min(visible.len().saturating_sub(1));

if state.ensure_selected_in_view_on_next_render {
start = start.min(selected_index);
}

let mut end = start;
let mut height = 0;
for item in visible.iter().skip(start) {
Expand All @@ -591,7 +611,7 @@ where
end += 1;
}

while selected_index >= end {
while state.ensure_selected_in_view_on_next_render && selected_index >= end {
height = height.saturating_add(visible[end].item.height());
end += 1;
while height > available_height {
Expand All @@ -601,6 +621,7 @@ where
}

state.offset = start;
state.ensure_selected_in_view_on_next_render = false;

let blank_symbol = " ".repeat(self.highlight_symbol.width());

Expand Down

0 comments on commit 01726df

Please sign in to comment.