Skip to main content

ez_tui/components/concrete/forms/inputs/
number_input.rs

1use 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 eztui_derive::MockProps;
8use ratatui::buffer::Buffer;
9use ratatui::layout::{Alignment, Rect};
10use ratatui::prelude::Widget;
11use ratatui::widgets::{BorderType, Paragraph};
12use std::fmt::Debug;
13/// A component drawing a [`FormField`] of type [`FormFieldType::Number`].
14#[derive(Debug, MockProps)]
15pub struct NumberInputCpt<FID>
16where
17    FID: EzCptIds,
18{
19    props: Props,
20    #[allow(dead_code)]
21    // I need a phantom if i remove this. So it's better keeping it as i need it in the constructor
22    field: FormField<FID>,
23    buffer: NumberBuffer,
24}
25
26impl<FID> NumberInputCpt<FID>
27where
28    FID: EzCptIds,
29{
30    /// Create a new [`NumberInputCpt`] component with a given form.
31    #[must_use]
32    pub(crate) fn new(field: FormField<FID>) -> Self {
33        assert_eq!(field.field_type(), &FormFieldType::Number {});
34        let mut props = Props::default();
35        props.set(
36            Attribute::Title,
37            AttrValue::Title((field.name(), Alignment::Left)),
38        );
39        Self {
40            props,
41            field,
42            buffer: NumberBuffer::default(),
43        }
44    }
45}
46
47impl<FID, CID, CA, CS, CM> InputCpt<CID, CA, CS, CM> for NumberInputCpt<FID>
48where
49    FID: EzCptIds,
50    CID: EzCptIds,
51    CA: EzArgs,
52    CS: EzState,
53    CM: EzMsg,
54{
55    fn get_value(&self) -> FormFieldValue {
56        FormFieldValue::Number(self.buffer.parsed())
57    }
58}
59impl<FID> MockComponent for NumberInputCpt<FID>
60where
61    FID: EzCptIds,
62{
63    fn draw(&mut self, area: Rect, buf: &mut Buffer, theme: &Theme) {
64        Paragraph::new(self.buffer.raw())
65            .block(theme.block(self.props()).border_type(BorderType::Double))
66            .render(area, buf);
67    }
68}
69
70impl<FID, CID, CA, CS, CM> Component<CID, CA, CS, CM> for NumberInputCpt<FID>
71where
72    FID: EzCptIds,
73    CID: EzCptIds,
74    CA: EzArgs,
75    CS: EzState,
76    CM: EzMsg,
77{
78    fn on_event(
79        &mut self,
80        event: EzEvent<CID, CM>,
81        _state: &mut State<CS>,
82    ) -> Vec<EzEvent<CID, CM>> {
83        if let EzEvent::Keyboard(kev) = event {
84            self.buffer.handle(kev);
85        }
86
87        vec![]
88    }
89
90    fn focusable(&self) -> bool {
91        true
92    }
93}