tui_components/components/
input.rs1use crate::{Component, Event, Spannable};
2use crossterm::event::KeyCode;
3use tui::buffer::Buffer;
4use tui::layout::Rect;
5use tui::style::Style;
6use tui::text::{Span, Spans};
7use tui::widgets::{Paragraph, Widget};
8
9#[derive(Debug, Default, Clone)]
10pub struct Input {
12 pub value: String,
13 pub error: Option<String>,
14 pub focused: bool,
15 text_style: Style,
16 editing_style: Style,
17 error_style: Style,
18}
19
20impl Input {
21 pub fn text_style(mut self, style: Style) -> Self {
22 self.text_style = style;
23 self
24 }
25
26 pub fn editing_style(mut self, style: Style) -> Self {
27 self.editing_style = style;
28 self
29 }
30
31 pub fn error_style(mut self, style: Style) -> Self {
32 self.error_style = style;
33 self
34 }
35}
36
37#[derive(Debug)]
38pub enum InputResponse {
39 None,
40 Edited { deletion: bool },
41 Submit,
42 Cancel,
43}
44
45impl Component for Input {
46 type Response = InputResponse;
47 type DrawResponse = ();
48
49 fn handle_event(&mut self, event: Event) -> Self::Response {
50 if let Event::Key(key_event) = event {
51 match key_event.code {
52 KeyCode::Char(c) => {
53 self.value.push(c);
54 InputResponse::Edited { deletion: false }
55 }
56 KeyCode::Backspace => {
57 self.value.pop();
58 InputResponse::Edited { deletion: true }
59 }
60 KeyCode::Enter => InputResponse::Submit,
61 KeyCode::Esc => InputResponse::Cancel,
62 _ => InputResponse::None,
63 }
64 } else {
65 InputResponse::None
66 }
67 }
68
69 fn draw(&mut self, rect: Rect, buf: &mut Buffer) {
70 let p = Paragraph::new(self.get_spans());
71 p.render(rect, buf);
72 }
73}
74
75impl Spannable for Input {
76 fn get_spans<'a, 'b>(&'a self) -> Spans<'b> {
77 let mut spans = Spans::default();
78 if self.focused {
79 spans.0.push(Span::raw("> "));
80 spans
81 .0
82 .push(Span::styled(self.value.clone(), self.editing_style));
83 if let Some(e) = &self.error {
84 spans
85 .0
86 .push(Span::styled(format!(" {}", e), self.error_style));
87 }
88 } else {
89 let style = if self.error.is_some() {
90 self.error_style
91 } else {
92 self.text_style
93 };
94 spans.0.push(Span::styled(self.value.clone(), style));
95 }
96 spans
97 }
98}