itools_tui/components/
select_menu.rs1use crate::{event::Event, layout::Rect, render::Frame, style::Style};
4use crossterm::event::KeyCode;
5
6pub struct SelectItem {
8 text: String,
10 style: Style,
12 selected_style: Style,
14}
15
16impl SelectItem {
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 SelectMenu {
52 prompt: String,
54 items: Vec<SelectItem>,
56 selected: usize,
58 style: Style,
60 on_select: Option<Box<dyn Fn(usize)>>,
62 on_cancel: Option<Box<dyn Fn()>>,
64}
65
66impl SelectMenu {
67 pub fn new(prompt: &str, items: Vec<SelectItem>) -> Self {
69 Self { prompt: prompt.to_string(), items, selected: 0, style: Style::new(), on_select: None, on_cancel: None }
70 }
71
72 pub fn style(mut self, style: Style) -> Self {
74 self.style = style;
75 self
76 }
77
78 pub fn on_select<F: Fn(usize) + 'static>(mut self, f: F) -> Self {
80 self.on_select = Some(Box::new(f));
81 self
82 }
83
84 pub fn on_cancel<F: Fn() + 'static>(mut self, f: F) -> Self {
86 self.on_cancel = Some(Box::new(f));
87 self
88 }
89
90 pub fn get_selected(&self) -> usize {
92 self.selected
93 }
94
95 fn handle_key(&mut self, key: KeyCode) -> bool {
97 match key {
98 KeyCode::Up => {
99 if self.selected > 0 {
100 self.selected -= 1;
101 }
102 true
103 }
104 KeyCode::Down => {
105 if self.selected < self.items.len() - 1 {
106 self.selected += 1;
107 }
108 true
109 }
110 KeyCode::Enter => {
111 if let Some(callback) = &self.on_select {
112 callback(self.selected);
113 }
114 true
115 }
116 KeyCode::Esc => {
117 if let Some(callback) = &self.on_cancel {
118 callback();
119 }
120 true
121 }
122 _ => false,
123 }
124 }
125}
126
127impl super::Component for SelectMenu {
128 fn render(&self, frame: &mut Frame, area: Rect) {
129 frame.render_select_menu(&self.prompt, &self.items, self.selected, area, self.style.clone());
130 }
131
132 fn handle_event(&mut self, event: &Event) -> bool {
133 match event {
134 Event::Key(key_event) => self.handle_key(key_event.code),
135 _ => false,
136 }
137 }
138}