tui_components/components/
checkbox.rs1use crossterm::event::KeyCode;
2use tui::{
3 buffer::Buffer,
4 layout::Rect,
5 style::{Color, Style},
6 text::{Span, Spans},
7 widgets::{Paragraph, Widget},
8};
9
10use crate::{Component, Event, Spannable};
11
12pub const TRUE_CHAR: char = '☑';
13pub const FALSE_CHAR: char = '☐';
14
15#[derive(Debug, Default)]
16pub struct Checkbox {
17 pub value: bool,
18}
19
20impl Checkbox {
21 pub fn new(value: bool) -> Self {
22 Self { value }
23 }
24
25 pub fn invert(&mut self) {
26 self.value = !self.value;
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum CheckboxResponse {
32 Edited,
33 None,
34 Submit,
35 Exit,
36}
37
38impl Component for Checkbox {
39 type Response = CheckboxResponse;
40 type DrawResponse = ();
41
42 fn handle_event(&mut self, event: crate::Event) -> Self::Response {
43 if let Event::Key(key) = event {
44 match key.code {
45 KeyCode::Char('t') | KeyCode::Char('y') => {
46 self.value = true;
47 CheckboxResponse::Edited
48 }
49 KeyCode::Char('f') | KeyCode::Char('n') => {
50 self.value = false;
51 CheckboxResponse::Edited
52 }
53 KeyCode::Down | KeyCode::Up => {
54 self.value = !self.value;
55 CheckboxResponse::Edited
56 }
57 KeyCode::Backspace => CheckboxResponse::Exit,
58 KeyCode::Enter => CheckboxResponse::Submit,
59 _ => CheckboxResponse::None,
60 }
61 } else {
62 CheckboxResponse::None
63 }
64 }
65
66 fn draw(&mut self, rect: Rect, buffer: &mut Buffer) -> Self::DrawResponse {
67 let spans = Spans::from(vec![
68 Span::styled("> ", Style::default()),
69 if self.value {
70 Span::styled(TRUE_CHAR.to_string(), Style::default().fg(Color::Green))
71 } else {
72 Span::styled(FALSE_CHAR.to_string(), Style::default().fg(Color::Red))
73 },
74 ]);
75 let paragraph = Paragraph::new(spans);
76 Widget::render(paragraph, rect, buffer);
77 }
78}
79
80impl Spannable for Checkbox {
81 fn get_spans<'a, 'b>(&'a self) -> Spans<'b> {
82 let mut spans = Spans::default();
83 spans.0.push(Span::raw(String::from("> ")));
84 if self.value {
85 spans.0.push(Span::styled(
86 TRUE_CHAR.to_string(),
87 Style::default().fg(Color::Green),
88 ));
89 } else {
90 spans.0.push(Span::styled(
91 FALSE_CHAR.to_string(),
92 Style::default().fg(Color::Yellow),
93 ));
94 }
95 spans
96 }
97}