wiki_tui/ui/
stateful_list.rs1use ratatui::widgets::ListState;
2
3#[derive(Default)]
4pub enum ScrollBehaviour {
5 StickToTop,
6 StickToBottom,
7 StickToEnds,
8 #[default]
9 Circle,
10}
11
12pub struct StatefulList<T> {
13 state: ListState,
14 items: Vec<T>,
15 behvaiour: ScrollBehaviour,
16}
17
18impl<T> StatefulList<T> {
19 pub fn with_items(items: Vec<T>) -> Self {
20 StatefulList {
21 state: ListState::default().with_selected(Some(0)),
22 items,
23 behvaiour: ScrollBehaviour::default(),
24 }
25 }
26
27 pub fn scroll_behavior(mut self, behavior: ScrollBehaviour) -> Self {
28 self.behvaiour = behavior;
29 self
30 }
31
32 pub fn get_items(&self) -> &Vec<T> {
33 &self.items
34 }
35
36 pub fn get_items_mut(&mut self) -> &mut Vec<T> {
37 &mut self.items
38 }
39
40 pub fn get_state_mut(&mut self) -> &mut ListState {
41 &mut self.state
42 }
43
44 pub fn next(&mut self) {
45 let i = match self.state.selected() {
46 Some(i) => {
47 if i >= self.items.len().saturating_sub(1) {
48 match self.behvaiour {
49 ScrollBehaviour::StickToBottom | ScrollBehaviour::StickToEnds => i,
50 ScrollBehaviour::StickToTop | ScrollBehaviour::Circle => 0,
51 }
52 } else {
53 i.saturating_add(1)
54 }
55 }
56 None => 0,
57 };
58 self.state.select(Some(i));
59 }
60
61 pub fn previous(&mut self) {
62 let i = match self.state.selected() {
63 Some(i) => {
64 if i == 0 {
65 match self.behvaiour {
66 ScrollBehaviour::StickToBottom | ScrollBehaviour::Circle => {
67 self.items.len().saturating_sub(1)
68 }
69 ScrollBehaviour::StickToTop | ScrollBehaviour::StickToEnds => i,
70 }
71 } else {
72 i.saturating_sub(1)
73 }
74 }
75 None => 0,
76 };
77 self.state.select(Some(i))
78 }
79
80 pub fn unselect(&mut self) {
81 self.state.select(None)
82 }
83
84 pub fn is_selected(&self) -> bool {
85 self.state.selected().is_some()
86 }
87
88 pub fn selected(&self) -> Option<&T> {
89 if self.state.selected().unwrap_or_default() >= self.items.len() {
90 return None;
91 }
92 self.state.selected().map(|i| &self.items[i])
93 }
94}