1
pub mod amount;
2
pub mod date;
3
pub mod editor;
4
pub mod select;
5
pub mod splits;
6

            
7
pub use amount::AmountWidget;
8
pub use date::DateWidget;
9
pub use editor::{EditMode, Editor, VimAction, VimMode};
10
pub use select::{SelectOption, SelectWidget};
11
pub use splits::{FocusedSubWidget, SplitRow, SplitRowPrefill, SplitsWidget};
12

            
13
#[cfg(test)]
14
mod tests;
15

            
16
/// Discriminant for widget-first key routing without carrying widget data.
17
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18
pub enum WidgetKind {
19
    Text,
20
    Select,
21
    Amount,
22
    Date,
23
    Splits,
24
}
25

            
26
/// The primary widget union — enum dispatch, no `Box<dyn>`, derives `Debug`.
27
#[derive(Debug)]
28
pub enum Widget {
29
    Text(Editor),
30
    Select(SelectWidget),
31
    Amount(AmountWidget),
32
    Date(DateWidget),
33
    Splits(SplitsWidget),
34
}
35

            
36
impl Widget {
37
    /// The submittable string value of this widget.
38
    ///
39
    /// Returns `""` for `Splits` (rows validated separately via [`SplitsWidget::rows`]).
40
    #[must_use]
41
99
    pub fn value(&self) -> &str {
42
99
        match self {
43
47
            Self::Text(ed) => ed.buffer(),
44
31
            Self::Select(sw) => sw.value(),
45
12
            Self::Amount(aw) => aw.value(),
46
9
            Self::Date(dw) => dw.value(),
47
            Self::Splits(_) => "",
48
        }
49
99
    }
50

            
51
    /// The display string for rendering (label for `Select`, buffer for others).
52
    #[must_use]
53
12
    pub fn display(&self) -> String {
54
12
        match self {
55
6
            Self::Text(ed) => ed.buffer().to_string(),
56
3
            Self::Select(sw) => sw.display().to_string(),
57
1
            Self::Amount(aw) => aw.value().to_string(),
58
2
            Self::Date(dw) => dw.value().to_string(),
59
            Self::Splits(sw) => sw.display(),
60
        }
61
12
    }
62

            
63
    /// Mutable reference to the inner [`Editor`] for `Text`, `Amount`, and
64
    /// `Date` variants. Returns `None` for `Select` and `Splits`.
65
    #[must_use]
66
11
    pub fn as_text_mut(&mut self) -> Option<&mut Editor> {
67
11
        match self {
68
8
            Self::Text(ed) => Some(ed),
69
1
            Self::Amount(aw) => Some(aw.as_editor_mut()),
70
1
            Self::Date(dw) => Some(dw.as_editor_mut()),
71
1
            Self::Select(_) | Self::Splits(_) => None,
72
        }
73
11
    }
74

            
75
    /// Variant discriminant used for widget-first key routing decisions.
76
    #[must_use]
77
25
    pub fn kind(&self) -> WidgetKind {
78
25
        match self {
79
4
            Self::Text(_) => WidgetKind::Text,
80
5
            Self::Select(_) => WidgetKind::Select,
81
1
            Self::Amount(_) => WidgetKind::Amount,
82
1
            Self::Date(_) => WidgetKind::Date,
83
14
            Self::Splits(_) => WidgetKind::Splits,
84
        }
85
25
    }
86
}