itools_tui/components/
table.rs1use crate::{event::Event, layout::Rect, render::Frame, style::Style};
4use crossterm::event::KeyCode;
5
6pub struct Cell {
8 content: String,
10 style: Style,
12}
13
14impl Cell {
15 pub fn new(content: &str) -> Self {
17 Self { content: content.to_string(), style: Style::new() }
18 }
19
20 pub fn style(mut self, style: Style) -> Self {
22 self.style = style;
23 self
24 }
25
26 pub fn content(&self) -> &str {
28 &self.content
29 }
30
31 pub fn get_style(&self) -> &Style {
33 &self.style
34 }
35}
36
37pub struct Row {
39 cells: Vec<Cell>,
41 style: Style,
43 selected_style: Style,
45}
46
47impl Row {
48 pub fn new(cells: Vec<Cell>) -> Self {
50 Self { cells, style: Style::new(), selected_style: Style::new().reversed() }
51 }
52
53 pub fn style(mut self, style: Style) -> Self {
55 self.style = style;
56 self
57 }
58
59 pub fn selected_style(mut self, style: Style) -> Self {
61 self.selected_style = style;
62 self
63 }
64
65 pub fn cells(&self) -> &Vec<Cell> {
67 &self.cells
68 }
69
70 pub fn get_style(&self) -> &Style {
72 &self.style
73 }
74
75 pub fn get_selected_style(&self) -> &Style {
77 &self.selected_style
78 }
79}
80
81pub struct Table {
83 header: Option<Row>,
85 rows: Vec<Row>,
87 selected: usize,
89 style: Style,
91 on_select: Option<Box<dyn Fn(usize)>>,
93}
94
95impl Table {
96 pub fn new(rows: Vec<Row>) -> Self {
98 Self { header: None, rows, selected: 0, style: Style::new(), on_select: None }
99 }
100
101 pub fn header(mut self, header: Row) -> Self {
103 self.header = Some(header);
104 self
105 }
106
107 pub fn style(mut self, style: Style) -> Self {
109 self.style = style;
110 self
111 }
112
113 pub fn on_select<F: Fn(usize) + 'static>(mut self, f: F) -> Self {
115 self.on_select = Some(Box::new(f));
116 self
117 }
118
119 pub fn get_selected(&self) -> usize {
121 self.selected
122 }
123
124 pub fn set_selected(&mut self, index: usize) {
126 if index < self.rows.len() {
127 self.selected = index;
128 if let Some(callback) = &self.on_select {
129 callback(self.selected);
130 }
131 }
132 }
133
134 fn handle_key(&mut self, key: KeyCode) {
136 match key {
137 KeyCode::Up => {
138 if self.selected > 0 {
139 self.selected -= 1;
140 if let Some(callback) = &self.on_select {
141 callback(self.selected);
142 }
143 }
144 }
145 KeyCode::Down => {
146 if self.selected < self.rows.len() - 1 {
147 self.selected += 1;
148 if let Some(callback) = &self.on_select {
149 callback(self.selected);
150 }
151 }
152 }
153 KeyCode::Home => {
154 self.selected = 0;
155 if let Some(callback) = &self.on_select {
156 callback(self.selected);
157 }
158 }
159 KeyCode::End => {
160 self.selected = self.rows.len().saturating_sub(1);
161 if let Some(callback) = &self.on_select {
162 callback(self.selected);
163 }
164 }
165 _ => {}
166 }
167 }
168}
169
170impl super::Component for Table {
171 fn render(&self, frame: &mut Frame, area: Rect) {
172 frame.render_table(self.header.as_ref(), &self.rows, self.selected, area, self.style.clone());
173 }
174
175 fn handle_event(&mut self, event: &Event) -> bool {
176 match event {
177 Event::Key(key_event) => {
178 self.handle_key(key_event.code);
179 true
180 }
181 _ => false,
182 }
183 }
184}