1use crate::{CustomLayout, EzCptIds, FormField, FormNode, LayoutItem};
2use derive_more::Constructor;
3use ratatui::layout::{Constraint, Direction, Layout};
4use std::collections::VecDeque;
5
6#[derive(Debug, Constructor)]
9pub struct Form<FID>
10where
11 FID: EzCptIds,
12{
13 pub(crate) name: String,
14 pub(crate) direction: Direction,
15 pub(crate) nodes: Vec<FormNode<FID>>,
16}
17impl<FID> Form<FID>
18where
19 FID: EzCptIds,
20{
21 #[must_use]
23 pub fn name(&self) -> &str {
24 &self.name
25 }
26
27 #[allow(clippy::missing_panics_doc)]
29 #[must_use]
30 pub fn custom_layout(&self) -> CustomLayout<FID> {
31 let ids = self
32 .nodes
33 .iter()
34 .map(|f| f.as_layout_item(self.direction, self.nodes.len()))
35 .collect::<VecDeque<LayoutItem<FID>>>();
36 let layout = Layout::default().direction(self.direction).constraints(
37 self.nodes
38 .iter()
39 .map(|f| f.as_constraint(self.direction, self.nodes.len()))
40 .collect::<Vec<Constraint>>(),
41 );
42 CustomLayout::named( self.name.clone(), layout, ids, )
43 .expect("Failed to create custom layout; probably due to mismatched constraints and components resulting from the lib logic (it's a bug for sure)")
44 }
45
46 #[must_use]
48 pub fn flatten_fields(&self) -> Vec<&FormField<FID>> {
49 self.nodes
50 .iter()
51 .flat_map(|node| match node {
52 FormNode::Field(field) => vec![field],
53 FormNode::Form(form) => form.flatten_fields(),
54 })
55 .collect()
56 }
57 #[allow(unused_variables)]
58 #[allow(clippy::unused_self)] pub(crate) fn as_constraint(&self, direction: Direction, _count: usize) -> Constraint {
60 Constraint::Min(1)
61 }
62
63 pub(crate) fn get(&self, id: &FID) -> Option<&FormField<FID>> {
64 for node in &self.nodes {
65 match node {
66 FormNode::Field(field) => {
67 if field.id() == id {
68 return Some(field);
69 }
70 }
71 FormNode::Form(form) => {
72 if let Some(field) = form.get(id) {
73 return Some(field);
74 }
75 }
76 }
77 }
78 None
79 }
80}