itools_tui/components/
list.rs1use crate::{event::Event, layout::Rect, render::Frame, style::Style};
4use crossterm::event::KeyCode;
5
6pub struct ListItem {
8 text: String,
10 style: Style,
12 selected_style: Style,
14}
15
16impl ListItem {
17 pub fn new(text: &str) -> Self {
19 Self { text: text.to_string(), style: Style::new(), selected_style: Style::new().reversed() }
20 }
21
22 pub fn style(mut self, style: Style) -> Self {
24 self.style = style;
25 self
26 }
27
28 pub fn selected_style(mut self, style: Style) -> Self {
30 self.selected_style = style;
31 self
32 }
33
34 pub fn text(&self) -> &str {
36 &self.text
37 }
38
39 pub fn get_style(&self) -> &Style {
41 &self.style
42 }
43
44 pub fn get_selected_style(&self) -> &Style {
46 &self.selected_style
47 }
48}
49
50pub struct List {
52 items: Vec<ListItem>,
54 selected: usize,
56 style: Style,
58 on_select: Option<Box<dyn Fn(usize)>>,
60}
61
62impl List {
63 pub fn new(items: Vec<ListItem>) -> Self {
65 Self { items, selected: 0, style: Style::new(), on_select: None }
66 }
67
68 pub fn style(mut self, style: Style) -> Self {
70 self.style = style;
71 self
72 }
73
74 pub fn on_select<F: Fn(usize) + 'static>(mut self, f: F) -> Self {
76 self.on_select = Some(Box::new(f));
77 self
78 }
79
80 pub fn get_selected(&self) -> usize {
82 self.selected
83 }
84
85 pub fn set_selected(&mut self, index: usize) {
87 if index < self.items.len() {
88 self.selected = index;
89 if let Some(callback) = &self.on_select {
90 callback(self.selected);
91 }
92 }
93 }
94
95 fn handle_key(&mut self, key: KeyCode) {
97 match key {
98 KeyCode::Up => {
99 if self.selected > 0 {
100 self.selected -= 1;
101 if let Some(callback) = &self.on_select {
102 callback(self.selected);
103 }
104 }
105 }
106 KeyCode::Down => {
107 if self.selected < self.items.len() - 1 {
108 self.selected += 1;
109 if let Some(callback) = &self.on_select {
110 callback(self.selected);
111 }
112 }
113 }
114 KeyCode::Home => {
115 self.selected = 0;
116 if let Some(callback) = &self.on_select {
117 callback(self.selected);
118 }
119 }
120 KeyCode::End => {
121 self.selected = self.items.len().saturating_sub(1);
122 if let Some(callback) = &self.on_select {
123 callback(self.selected);
124 }
125 }
126 _ => {}
127 }
128 }
129}
130
131impl super::Component for List {
132 fn render(&self, frame: &mut Frame, area: Rect) {
133 frame.render_list(&self.items, self.selected, area, self.style.clone());
134 }
135
136 fn handle_event(&mut self, event: &Event) -> bool {
137 match event {
138 Event::Key(key_event) => {
139 self.handle_key(key_event.code);
140 true
141 }
142 _ => false,
143 }
144 }
145}