#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TableState {
pub(crate) offset: usize,
pub(crate) selected: Option<usize>,
}
impl TableState {
pub const fn new() -> Self {
Self {
offset: 0,
selected: None,
}
}
#[must_use = "method moves the value of self and returns the modified value"]
pub const fn with_offset(mut self, offset: usize) -> Self {
self.offset = offset;
self
}
#[must_use = "method moves the value of self and returns the modified value"]
pub fn with_selected<T>(mut self, selected: T) -> Self
where
T: Into<Option<usize>>,
{
self.selected = selected.into();
self
}
pub const fn offset(&self) -> usize {
self.offset
}
pub fn offset_mut(&mut self) -> &mut usize {
&mut self.offset
}
pub const fn selected(&self) -> Option<usize> {
self.selected
}
pub fn selected_mut(&mut self) -> &mut Option<usize> {
&mut self.selected
}
pub fn select(&mut self, index: Option<usize>) {
self.selected = index;
if index.is_none() {
self.offset = 0;
}
}
pub fn select_next(&mut self) {
let next = self.selected.map_or(0, |i| i.saturating_add(1));
self.select(Some(next));
}
pub fn select_previous(&mut self) {
let previous = self.selected.map_or(usize::MAX, |i| i.saturating_sub(1));
self.select(Some(previous));
}
pub fn select_first(&mut self) {
self.select(Some(0));
}
pub fn select_last(&mut self) {
self.select(Some(usize::MAX));
}
pub fn scroll_down_by(&mut self, amount: u16) {
let selected = self.selected.unwrap_or_default();
self.select(Some(selected.saturating_add(amount as usize)));
}
pub fn scroll_up_by(&mut self, amount: u16) {
let selected = self.selected.unwrap_or_default();
self.select(Some(selected.saturating_sub(amount as usize)));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new() {
let state = TableState::new();
assert_eq!(state.offset, 0);
assert_eq!(state.selected, None);
}
#[test]
fn with_offset() {
let state = TableState::new().with_offset(1);
assert_eq!(state.offset, 1);
}
#[test]
fn with_selected() {
let state = TableState::new().with_selected(Some(1));
assert_eq!(state.selected, Some(1));
}
#[test]
fn offset() {
let state = TableState::new();
assert_eq!(state.offset(), 0);
}
#[test]
fn offset_mut() {
let mut state = TableState::new();
*state.offset_mut() = 1;
assert_eq!(state.offset, 1);
}
#[test]
fn selected() {
let state = TableState::new();
assert_eq!(state.selected(), None);
}
#[test]
fn selected_mut() {
let mut state = TableState::new();
*state.selected_mut() = Some(1);
assert_eq!(state.selected, Some(1));
}
#[test]
fn select() {
let mut state = TableState::new();
state.select(Some(1));
assert_eq!(state.selected, Some(1));
}
#[test]
fn select_none() {
let mut state = TableState::new().with_selected(Some(1));
state.select(None);
assert_eq!(state.selected, None);
}
#[test]
fn test_table_state_navigation() {
let mut state = TableState::default();
state.select_first();
assert_eq!(state.selected, Some(0));
state.select_previous(); assert_eq!(state.selected, Some(0));
state.select_next();
assert_eq!(state.selected, Some(1));
state.select_previous();
assert_eq!(state.selected, Some(0));
state.select_last();
assert_eq!(state.selected, Some(usize::MAX));
state.select_next(); assert_eq!(state.selected, Some(usize::MAX));
state.select_previous();
assert_eq!(state.selected, Some(usize::MAX - 1));
state.select_next();
assert_eq!(state.selected, Some(usize::MAX));
let mut state = TableState::default();
state.select_next();
assert_eq!(state.selected, Some(0));
let mut state = TableState::default();
state.select_previous();
assert_eq!(state.selected, Some(usize::MAX));
let mut state = TableState::default();
state.select(Some(2));
state.scroll_down_by(4);
assert_eq!(state.selected, Some(6));
let mut state = TableState::default();
state.scroll_up_by(3);
assert_eq!(state.selected, Some(0));
state.select(Some(6));
state.scroll_up_by(4);
assert_eq!(state.selected, Some(2));
state.scroll_up_by(4);
assert_eq!(state.selected, Some(0));
}
}