use ratatui::widgets::TableState as State;
#[derive(Debug)]
pub struct SelectableList<T> {
pub items: Vec<T>,
pub state: State,
}
impl<T> Default for SelectableList<T> {
fn default() -> Self {
Self::with_items(Vec::new())
}
}
impl<T> SelectableList<T> {
pub fn new(items: Vec<T>, mut state: State) -> SelectableList<T> {
state.select(Some(0));
Self { items, state }
}
pub fn with_items(items: Vec<T>) -> SelectableList<T> {
Self::new(items, State::default())
}
pub fn selected(&self) -> Option<&T> {
self.items.get(self.state.selected()?)
}
pub fn first(&mut self) {
self.state.select(Some(0));
}
pub fn last(&mut self) {
self.state.select(Some(self.items.len().saturating_sub(1)));
}
pub fn next(&mut self, amount: usize) {
let i = match self.state.selected() {
Some(i) => {
if i.saturating_add(amount) >= self.items.len() {
0
} else {
i.saturating_add(amount)
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn previous(&mut self, amount: usize) {
let i = match self.state.selected() {
Some(i) => {
if i == 0 {
self.items.len().saturating_sub(1)
} else {
i.saturating_sub(amount)
}
}
None => 0,
};
self.state.select(Some(i));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_selectable_list() {
let mut list = SelectableList::with_items(vec!["data1", "data2", "data3"]);
list.state.select(Some(1));
assert_eq!(Some(&"data2"), list.selected());
list.next(1);
assert_eq!(Some(2), list.state.selected());
list.previous(1);
assert_eq!(Some(1), list.state.selected());
let mut list = SelectableList::<()>::default();
list.state.select(None);
list.next(1);
list.state.select(None);
list.previous(1);
assert_eq!(Some(0), list.state.selected());
}
}