Skip to main content

gpg_tui/widget/
list.rs

1use ratatui::widgets::ListState;
2
3/// List widget with TUI controlled states.
4#[derive(Debug)]
5pub struct StatefulList<T> {
6	/// List items (states).
7	pub items: Vec<T>,
8	/// State that can be modified by TUI.
9	pub state: ListState,
10}
11
12impl<T> StatefulList<T> {
13	/// Constructs a new instance of `StatefulList`.
14	pub fn new(items: Vec<T>, state: ListState) -> StatefulList<T> {
15		Self { items, state }
16	}
17
18	/// Construct a new `StatefulList` with given items.
19	pub fn with_items(items: Vec<T>) -> StatefulList<T> {
20		Self::new(items, ListState::default())
21	}
22
23	/// Returns the selected item.
24	pub fn selected(&self) -> Option<&T> {
25		self.items.get(self.state.selected()?)
26	}
27
28	/// Selects the next item.
29	pub fn next(&mut self) {
30		let i = match self.state.selected() {
31			Some(i) => {
32				if i >= self.items.len() - 1 {
33					0
34				} else {
35					i + 1
36				}
37			}
38			None => 0,
39		};
40		self.state.select(Some(i));
41	}
42
43	/// Selects the previous item.
44	pub fn previous(&mut self) {
45		let i = match self.state.selected() {
46			Some(i) => {
47				if i == 0 {
48					self.items.len() - 1
49				} else {
50					i - 1
51				}
52			}
53			None => 0,
54		};
55		self.state.select(Some(i));
56	}
57}
58
59#[cfg(test)]
60mod tests {
61	use super::*;
62	use pretty_assertions::assert_eq;
63	#[test]
64	fn test_widget_list() {
65		let mut list =
66			StatefulList::with_items(vec!["data1", "data2", "data3"]);
67		list.state.select(Some(1));
68		assert_eq!(Some(&"data2"), list.selected());
69		list.next();
70		assert_eq!(Some(2), list.state.selected());
71		list.previous();
72		assert_eq!(Some(1), list.state.selected());
73	}
74}