ez_tui/components/concrete/forms/inputs/
range_input.rs1use crate::components::concrete::forms::inputs::core::{FormFieldValue, InputCpt};
2use crate::components::concrete::forms::inputs::number_buffer::NumberBuffer;
3use crate::{
4 AttrValue, Attribute, Component, EzArgs, EzCptIds, EzEvent, EzMsg, EzState, FormField,
5 FormFieldType, MockComponent, MockProps, Props, State, Theme,
6};
7use crossterm::event::KeyCode;
8use eztui_derive::MockProps;
9use ratatui::buffer::Buffer;
10use ratatui::layout::{Alignment, Rect};
11use ratatui::prelude::{Stylize, Widget};
12use ratatui::text::{Line, Span};
13use ratatui::widgets::{BorderType, Paragraph};
14use std::fmt::Debug;
15#[derive(Debug, MockProps)]
17pub struct RangeInputCpt<FID>
18where
19 FID: EzCptIds,
20{
21 props: Props,
22 #[allow(dead_code)]
23 field: FormField<FID>,
25 editing_first: bool,
26 buffers: (NumberBuffer, NumberBuffer),
27}
28
29impl<FID> RangeInputCpt<FID>
30where
31 FID: EzCptIds,
32{
33 #[must_use]
35 pub(crate) fn new(field: FormField<FID>) -> Self {
36 assert_eq!(field.field_type(), &FormFieldType::Range {});
37 let mut props = Props::default();
38 props.set(
39 Attribute::Title,
40 AttrValue::Title((field.name(), Alignment::Left)),
41 );
42 Self {
43 props,
44 field,
45 editing_first: true,
46 buffers: (NumberBuffer::default(), NumberBuffer::default()),
47 }
48 }
49}
50
51impl<FID, CID, CA, CS, CM> InputCpt<CID, CA, CS, CM> for RangeInputCpt<FID>
52where
53 FID: EzCptIds,
54 CID: EzCptIds,
55 CA: EzArgs,
56 CS: EzState,
57 CM: EzMsg,
58{
59 fn get_value(&self) -> FormFieldValue {
60 FormFieldValue::Range((self.buffers.0.parsed(), self.buffers.1.parsed()))
61 }
62}
63impl<FID> MockComponent for RangeInputCpt<FID>
64where
65 FID: EzCptIds,
66{
67 fn draw(&mut self, area: Rect, buf: &mut Buffer, theme: &Theme) {
68 let mut a = Span::raw(self.buffers.0.parsed().to_string());
69 let mut b = Span::raw(self.buffers.1.parsed().to_string());
70 if self.editing_first {
71 a = a.bold();
72 } else {
73 b = b.bold();
74 }
75
76 let spans = vec![a, Span::raw(" .. "), b];
77 Paragraph::new(Line::from(spans))
78 .block(theme.block(self.props()).border_type(BorderType::Double))
79 .render(area, buf);
80 }
81}
82
83impl<FID, CID, CA, CS, CM> Component<CID, CA, CS, CM> for RangeInputCpt<FID>
84where
85 FID: EzCptIds,
86 CID: EzCptIds,
87 CA: EzArgs,
88 CS: EzState,
89 CM: EzMsg,
90{
91 fn on_event(
92 &mut self,
93 event: EzEvent<CID, CM>,
94 _state: &mut State<CS>,
95 ) -> Vec<EzEvent<CID, CM>> {
96 if let EzEvent::Keyboard(kev) = event {
97 if let KeyCode::Char(' ') = kev.code {
98 self.editing_first = !self.editing_first;
99 } else if self.editing_first {
100 self.buffers.0.handle(kev);
101 } else {
102 self.buffers.1.handle(kev);
103 }
104 }
105
106 vec![]
107 }
108
109 fn focusable(&self) -> bool {
110 true
111 }
112}