Skip to main content

itools_tui/components/
list.rs

1//! 列表组件
2
3use crate::{event::Event, layout::Rect, render::Frame, style::Style};
4use crossterm::event::KeyCode;
5
6/// 列表项
7pub struct ListItem {
8    /// 项文本
9    text: String,
10    /// 项样式
11    style: Style,
12    /// 选中样式
13    selected_style: Style,
14}
15
16impl ListItem {
17    /// 创建新的列表项
18    pub fn new(text: &str) -> Self {
19        Self { text: text.to_string(), style: Style::new(), selected_style: Style::new().reversed() }
20    }
21
22    /// 设置项样式
23    pub fn style(mut self, style: Style) -> Self {
24        self.style = style;
25        self
26    }
27
28    /// 设置选中样式
29    pub fn selected_style(mut self, style: Style) -> Self {
30        self.selected_style = style;
31        self
32    }
33
34    /// 获取项文本
35    pub fn text(&self) -> &str {
36        &self.text
37    }
38
39    /// 获取项样式
40    pub fn get_style(&self) -> &Style {
41        &self.style
42    }
43
44    /// 获取选中样式
45    pub fn get_selected_style(&self) -> &Style {
46        &self.selected_style
47    }
48}
49
50/// 列表组件
51pub struct List {
52    /// 列表项
53    items: Vec<ListItem>,
54    /// 选中索引
55    selected: usize,
56    /// 列表样式
57    style: Style,
58    /// 选中回调
59    on_select: Option<Box<dyn Fn(usize)>>,
60}
61
62impl List {
63    /// 创建新的列表
64    pub fn new(items: Vec<ListItem>) -> Self {
65        Self { items, selected: 0, style: Style::new(), on_select: None }
66    }
67
68    /// 设置样式
69    pub fn style(mut self, style: Style) -> Self {
70        self.style = style;
71        self
72    }
73
74    /// 设置选中回调
75    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    /// 获取选中项索引
81    pub fn get_selected(&self) -> usize {
82        self.selected
83    }
84
85    /// 设置选中项
86    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    /// 处理键盘事件
96    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}