1use crate::field::Field;
4use crate::submit::{SubmitFn, SubmitOutcome};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum FormMode {
9 Normal,
10 Insert,
11}
12
13#[derive(Debug)]
15pub enum FormEvent {
16 Changed,
18 Cancelled,
20 Submitted(SubmitOutcome),
23 ValidationFailed,
26}
27
28pub struct Form {
32 pub title: Option<String>,
33 pub fields: Vec<Field>,
34 pub mode: FormMode,
35 pub(crate) focused: usize,
36 pub(crate) submit: Option<SubmitFn>,
37 pub(crate) dirty_gen: u64,
38 pub(crate) pending_g: bool,
39}
40
41impl Form {
42 pub fn new() -> Self {
44 Self {
45 title: None,
46 fields: Vec::new(),
47 mode: FormMode::Normal,
48 focused: 0,
49 submit: None,
50 dirty_gen: 0,
51 pending_g: false,
52 }
53 }
54
55 pub fn with_title(mut self, title: impl Into<String>) -> Self {
57 self.title = Some(title.into());
58 self
59 }
60
61 pub fn with_field(mut self, field: Field) -> Self {
64 self.fields.push(field);
65 self
66 }
67
68 pub fn with_submit(mut self, submit: SubmitFn) -> Self {
71 self.submit = Some(submit);
72 self
73 }
74
75 pub fn focused(&self) -> usize {
77 self.focused
78 }
79
80 pub fn focused_field(&self) -> Option<&Field> {
82 self.fields.get(self.focused)
83 }
84
85 pub fn focused_field_mut(&mut self) -> Option<&mut Field> {
87 self.fields.get_mut(self.focused)
88 }
89
90 pub fn set_focus(&mut self, index: usize) {
93 if index < self.fields.len() {
94 self.focused = index;
95 self.dirty_gen = self.dirty_gen.wrapping_add(1);
96 }
97 }
98
99 pub fn dirty_gen(&self) -> u64 {
103 let mut sum = self.dirty_gen;
104 for field in &self.fields {
105 match field {
106 Field::SingleLineText(f) | Field::MultiLineText(f) => {
107 sum = sum.wrapping_add(f.editor.buffer().dirty_gen());
108 }
109 _ => {}
110 }
111 }
112 sum
113 }
114
115 pub(crate) fn bump_dirty(&mut self) {
116 self.dirty_gen = self.dirty_gen.wrapping_add(1);
117 }
118}
119
120impl Default for Form {
121 fn default() -> Self {
122 Self::new()
123 }
124}