itools_tui/components/
input.rs1use crate::{event::Event, layout::Rect, render::Frame, style::Style};
4use crossterm::event::{KeyCode, KeyEvent};
5
6pub struct Input {
8 value: String,
10 placeholder: Option<String>,
12 style: Style,
14 cursor_style: Style,
16 cursor_pos: usize,
18 focused: bool,
20 on_change: Option<Box<dyn Fn(&str)>>,
22}
23
24impl Input {
25 pub fn new() -> Self {
27 Self {
28 value: String::new(),
29 placeholder: None,
30 style: Style::new(),
31 cursor_style: Style::new().reversed(),
32 cursor_pos: 0,
33 focused: false,
34 on_change: None,
35 }
36 }
37
38 pub fn value(mut self, value: &str) -> Self {
40 self.value = value.to_string();
41 self.cursor_pos = self.value.len();
42 self
43 }
44
45 pub fn placeholder(mut self, placeholder: &str) -> Self {
47 self.placeholder = Some(placeholder.to_string());
48 self
49 }
50
51 pub fn style(mut self, style: Style) -> Self {
53 self.style = style;
54 self
55 }
56
57 pub fn cursor_style(mut self, style: Style) -> Self {
59 self.cursor_style = style;
60 self
61 }
62
63 pub fn focused(mut self, focused: bool) -> Self {
65 self.focused = focused;
66 self
67 }
68
69 pub fn on_change<F: Fn(&str) + 'static>(mut self, f: F) -> Self {
71 self.on_change = Some(Box::new(f));
72 self
73 }
74
75 pub fn get_value(&self) -> &str {
77 &self.value
78 }
79
80 fn handle_key(&mut self, key: KeyEvent) {
82 match key.code {
83 KeyCode::Backspace => {
84 if self.cursor_pos > 0 {
85 self.value.remove(self.cursor_pos - 1);
86 self.cursor_pos -= 1;
87 if let Some(callback) = &self.on_change {
88 callback(&self.value);
89 }
90 }
91 }
92 KeyCode::Delete => {
93 if self.cursor_pos < self.value.len() {
94 self.value.remove(self.cursor_pos);
95 if let Some(callback) = &self.on_change {
96 callback(&self.value);
97 }
98 }
99 }
100 KeyCode::Left => {
101 if self.cursor_pos > 0 {
102 self.cursor_pos -= 1;
103 }
104 }
105 KeyCode::Right => {
106 if self.cursor_pos < self.value.len() {
107 self.cursor_pos += 1;
108 }
109 }
110 KeyCode::Home => {
111 self.cursor_pos = 0;
112 }
113 KeyCode::End => {
114 self.cursor_pos = self.value.len();
115 }
116 KeyCode::Char(c) => {
117 self.value.insert(self.cursor_pos, c);
118 self.cursor_pos += 1;
119 if let Some(callback) = &self.on_change {
120 callback(&self.value);
121 }
122 }
123 _ => {}
124 }
125 }
126}
127
128impl super::Component for Input {
129 fn render(&self, frame: &mut Frame, area: Rect) {
130 let text =
131 if self.value.is_empty() && self.placeholder.is_some() { self.placeholder.as_ref().unwrap() } else { &self.value };
132
133 frame.render_input(text, self.cursor_pos, area, self.style.clone(), self.cursor_style.clone(), self.focused);
134 }
135
136 fn handle_event(&mut self, event: &Event) -> bool {
137 if !self.focused {
138 return false;
139 }
140
141 match event {
142 Event::Key(key_event) => {
143 self.handle_key(*key_event);
144 true
145 }
146 _ => false,
147 }
148 }
149}