feat: scroll independently from selection
This commit is contained in:
+24
-3
@@ -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"),
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
@@ -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),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-8
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -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>]) {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -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 {
|
||||
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user