Skip to main content

itools_tui/components/
table.rs

1//! 表格组件
2
3use crate::{event::Event, layout::Rect, render::Frame, style::Style};
4use crossterm::event::KeyCode;
5
6/// 表格单元格
7pub struct Cell {
8    /// 单元格内容
9    content: String,
10    /// 单元格样式
11    style: Style,
12}
13
14impl Cell {
15    /// 创建新的单元格
16    pub fn new(content: &str) -> Self {
17        Self { content: content.to_string(), style: Style::new() }
18    }
19
20    /// 设置单元格样式
21    pub fn style(mut self, style: Style) -> Self {
22        self.style = style;
23        self
24    }
25
26    /// 获取单元格内容
27    pub fn content(&self) -> &str {
28        &self.content
29    }
30
31    /// 获取单元格样式
32    pub fn get_style(&self) -> &Style {
33        &self.style
34    }
35}
36
37/// 表格行
38pub struct Row {
39    /// 行单元格
40    cells: Vec<Cell>,
41    /// 行样式
42    style: Style,
43    /// 选中样式
44    selected_style: Style,
45}
46
47impl Row {
48    /// 创建新的行
49    pub fn new(cells: Vec<Cell>) -> Self {
50        Self { cells, style: Style::new(), selected_style: Style::new().reversed() }
51    }
52
53    /// 设置行样式
54    pub fn style(mut self, style: Style) -> Self {
55        self.style = style;
56        self
57    }
58
59    /// 设置选中样式
60    pub fn selected_style(mut self, style: Style) -> Self {
61        self.selected_style = style;
62        self
63    }
64
65    /// 获取行单元格
66    pub fn cells(&self) -> &Vec<Cell> {
67        &self.cells
68    }
69
70    /// 获取行样式
71    pub fn get_style(&self) -> &Style {
72        &self.style
73    }
74
75    /// 获取选中样式
76    pub fn get_selected_style(&self) -> &Style {
77        &self.selected_style
78    }
79}
80
81/// 表格组件
82pub struct Table {
83    /// 表头
84    header: Option<Row>,
85    /// 表格行
86    rows: Vec<Row>,
87    /// 选中行索引
88    selected: usize,
89    /// 表格样式
90    style: Style,
91    /// 选中回调
92    on_select: Option<Box<dyn Fn(usize)>>,
93}
94
95impl Table {
96    /// 创建新的表格
97    pub fn new(rows: Vec<Row>) -> Self {
98        Self { header: None, rows, selected: 0, style: Style::new(), on_select: None }
99    }
100
101    /// 设置表头
102    pub fn header(mut self, header: Row) -> Self {
103        self.header = Some(header);
104        self
105    }
106
107    /// 设置样式
108    pub fn style(mut self, style: Style) -> Self {
109        self.style = style;
110        self
111    }
112
113    /// 设置选中回调
114    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    /// 获取选中行索引
120    pub fn get_selected(&self) -> usize {
121        self.selected
122    }
123
124    /// 设置选中行
125    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    /// 处理键盘事件
135    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}