feat(state)!: return true when something changed

This commit is contained in:
EdJoPaTo
2024-02-26 18:42:14 +01:00
parent 0a5c7d6cfb
commit ed9a54a55a
2 changed files with 68 additions and 36 deletions
+11 -15
View File
@@ -134,10 +134,9 @@ fn main() -> std::io::Result<()> {
} }
fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> std::io::Result<()> { fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> std::io::Result<()> {
terminal.draw(|frame| app.draw(frame))?;
loop { loop {
terminal.draw(|frame| app.draw(frame))?; let update = match crossterm::event::read()? {
match crossterm::event::read()? {
Event::Key(key) => match key.code { Event::Key(key) => match key.code {
KeyCode::Char('q') => return Ok(()), KeyCode::Char('q') => return Ok(()),
KeyCode::Char('\n' | ' ') => app.state.toggle_selected(), KeyCode::Char('\n' | ' ') => app.state.toggle_selected(),
@@ -145,25 +144,22 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> std::io::Res
KeyCode::Right => app.state.key_right(), KeyCode::Right => app.state.key_right(),
KeyCode::Down => app.state.key_down(&app.items), KeyCode::Down => app.state.key_down(&app.items),
KeyCode::Up => app.state.key_up(&app.items), KeyCode::Up => app.state.key_up(&app.items),
KeyCode::Esc => { KeyCode::Esc => app.state.select(Vec::new()),
app.state.select(Vec::new()); KeyCode::Home => app.state.select_first(&app.items),
} KeyCode::End => app.state.select_last(&app.items),
KeyCode::Home => {
app.state.select_first(&app.items);
}
KeyCode::End => {
app.state.select_last(&app.items);
}
KeyCode::PageDown => app.state.scroll_down(3), KeyCode::PageDown => app.state.scroll_down(3),
KeyCode::PageUp => app.state.scroll_up(3), KeyCode::PageUp => app.state.scroll_up(3),
_ => {} _ => false,
}, },
Event::Mouse(mouse) => match mouse.kind { Event::Mouse(mouse) => match mouse.kind {
MouseEventKind::ScrollDown => app.state.scroll_down(1), MouseEventKind::ScrollDown => app.state.scroll_down(1),
MouseEventKind::ScrollUp => app.state.scroll_up(1), MouseEventKind::ScrollUp => app.state.scroll_up(1),
_ => {} _ => false,
}, },
_ => {} _ => false,
};
if update {
terminal.draw(|frame| app.draw(frame))?;
} }
} }
} }
+57 -21
View File
@@ -61,9 +61,9 @@ where
/// state.select(Vec::new()); /// state.select(Vec::new());
/// ``` /// ```
pub fn select(&mut self, identifier: Vec<Identifier>) -> bool { pub fn select(&mut self, identifier: Vec<Identifier>) -> bool {
self.ensure_selected_in_view_on_next_render = true;
let changed = self.selected != identifier; let changed = self.selected != identifier;
self.selected = identifier; self.selected = identifier;
self.ensure_selected_in_view_on_next_render = true;
changed changed
} }
@@ -87,23 +87,39 @@ where
/// Toggles a tree node. /// Toggles a tree node.
/// If the node is in opened then it calls [`close`](State::close). Otherwise it calls [`open`](State::open). /// If the node is in opened then it calls [`close`](State::close). Otherwise it calls [`open`](State::open).
pub fn toggle(&mut self, identifier: Vec<Identifier>) { ///
if self.opened.contains(&identifier) { /// Returns `true` when a node is opened / closed.
self.close(&identifier); /// As toggle always changes something, this only returns `false` when an empty identifier is given.
pub fn toggle(&mut self, identifier: Vec<Identifier>) -> bool {
if identifier.is_empty() {
false
} else if self.opened.contains(&identifier) {
self.close(&identifier)
} else { } else {
self.open(identifier); self.open(identifier)
} }
} }
/// Toggles the currently selected tree node. /// Toggles the currently selected tree node.
/// See also [`toggle`](State::toggle) /// See also [`toggle`](State::toggle)
pub fn toggle_selected(&mut self) { ///
self.toggle(self.selected()); /// Returns `true` when a node is opened / closed.
/// As toggle always changes something, this only returns `false` when nothing is selected.
pub fn toggle_selected(&mut self) -> bool {
self.ensure_selected_in_view_on_next_render = true; self.ensure_selected_in_view_on_next_render = true;
self.toggle(self.selected())
} }
pub fn close_all(&mut self) { /// Closes all open nodes.
self.opened.clear(); ///
/// Returns `true` when any node was closed.
pub fn close_all(&mut self) -> bool {
if self.opened.is_empty() {
false
} else {
self.opened.clear();
true
}
} }
/// Select the first node. /// Select the first node.
@@ -189,47 +205,67 @@ where
} }
/// Scroll the specified amount of lines up /// Scroll the specified amount of lines up
pub fn scroll_up(&mut self, lines: usize) { ///
/// Returns `true` when the scroll position changed.
/// Returns `false` when the scrolling has reached the top.
pub fn scroll_up(&mut self, lines: usize) -> bool {
let before = self.offset;
self.offset = self.offset.saturating_sub(lines); self.offset = self.offset.saturating_sub(lines);
before != self.offset
} }
/// Scroll the specified amount of lines down /// Scroll the specified amount of lines down
pub fn scroll_down(&mut self, lines: usize) { ///
/// In contrast to [`scroll_up()`](Self::scroll_up) this can not return whether the view position changed or not as the actual change is determined on render.
/// Always returns `true`.
pub fn scroll_down(&mut self, lines: usize) -> bool {
self.offset = self.offset.saturating_add(lines); self.offset = self.offset.saturating_add(lines);
true
} }
/// Handles the up arrow key. /// Handles the up arrow key.
/// Moves up in the current depth or to its parent. /// Moves up in the current depth or to its parent.
pub fn key_up(&mut self, items: &[Item<Identifier>]) { ///
/// Returns `true` when the selection changed.
pub fn key_up(&mut self, items: &[Item<Identifier>]) -> bool {
self.select_visible_relative(items, |current| { self.select_visible_relative(items, |current| {
current.map_or(usize::MAX, |current| current.saturating_sub(1)) current.map_or(usize::MAX, |current| current.saturating_sub(1))
}); })
} }
/// Handles the down arrow key. /// Handles the down arrow key.
/// Moves down in the current depth or into a child node. /// Moves down in the current depth or into a child node.
pub fn key_down(&mut self, items: &[Item<Identifier>]) { ///
/// Returns `true` when the selection changed.
pub fn key_down(&mut self, items: &[Item<Identifier>]) -> bool {
self.select_visible_relative(items, |current| { self.select_visible_relative(items, |current| {
current.map_or(0, |current| current.saturating_add(1)) current.map_or(0, |current| current.saturating_add(1))
}); })
} }
/// Handles the left arrow key. /// Handles the left arrow key.
/// Closes the currently selected or moves to its parent. /// Closes the currently selected or moves to its parent.
pub fn key_left(&mut self) { ///
/// Returns `true` when the selection or the open state changed.
pub fn key_left(&mut self) -> bool {
self.ensure_selected_in_view_on_next_render = true;
// Reimplement self.close because of multiple different borrows // Reimplement self.close because of multiple different borrows
let changed = self.opened.remove(&self.selected); let mut changed = self.opened.remove(&self.selected);
if !changed { if !changed {
// Select the parent by removing the leaf from selection // Select the parent by removing the leaf from selection
self.selected.pop(); let popped = self.selected.pop();
changed = popped.is_some();
} }
self.ensure_selected_in_view_on_next_render = true; changed
} }
/// Handles the right arrow key. /// Handles the right arrow key.
/// Opens the currently selected. /// Opens the currently selected.
pub fn key_right(&mut self) { ///
self.open(self.selected()); /// Returns `true` if the node was closed and has been opened.
/// Returns `false` if the node was already open.
pub fn key_right(&mut self) -> bool {
self.ensure_selected_in_view_on_next_render = true; self.ensure_selected_in_view_on_next_render = true;
self.open(self.selected())
} }
} }