Skip to main content

gpui_component/form/
form.rs

1use gpui::{
2    App, Axis, IntoElement, ParentElement, Pixels, Rems, RenderOnce, StyleRefinement, Styled,
3    Window, px,
4};
5
6use crate::{
7    Sizable, Size,
8    form::{Field, FieldProps},
9    v_flex,
10};
11
12/// A form element that contains multiple form fields.
13#[derive(IntoElement)]
14pub struct Form {
15    style: StyleRefinement,
16    fields: Vec<Field>,
17    props: FieldProps,
18}
19
20impl Form {
21    fn new() -> Self {
22        Self {
23            style: StyleRefinement::default(),
24            props: FieldProps::default(),
25            fields: Vec::new(),
26        }
27    }
28
29    /// Creates a new form with a horizontal layout.
30    pub fn horizontal() -> Self {
31        Self::new().layout(Axis::Horizontal)
32    }
33
34    /// Creates a new form with a vertical layout.
35    pub fn vertical() -> Self {
36        Self::new().layout(Axis::Vertical)
37    }
38
39    /// Set the layout for the form, default is `Axis::Vertical`.
40    pub fn layout(mut self, layout: Axis) -> Self {
41        self.props.layout = layout;
42        self
43    }
44
45    /// Set the width of the labels in the form. Default is `px(100.)`.
46    pub fn label_width(mut self, width: Pixels) -> Self {
47        self.props.label_width = Some(width);
48        self
49    }
50
51    /// Set the text size of the labels in the form. Default is `None`.
52    pub fn label_text_size(mut self, size: Rems) -> Self {
53        self.props.label_text_size = Some(size);
54        self
55    }
56
57    /// Add a child to the form.
58    pub fn child(mut self, field: impl Into<Field>) -> Self {
59        self.fields.push(field.into());
60        self
61    }
62
63    /// Add multiple children to the form.
64    pub fn children(mut self, fields: impl IntoIterator<Item = Field>) -> Self {
65        self.fields.extend(fields);
66        self
67    }
68
69    /// Set the column count for the form.
70    ///
71    /// Default is 1.
72    pub fn columns(mut self, columns: usize) -> Self {
73        self.props.columns = columns;
74        self
75    }
76}
77
78impl Styled for Form {
79    fn style(&mut self) -> &mut StyleRefinement {
80        &mut self.style
81    }
82}
83
84impl Sizable for Form {
85    fn with_size(mut self, size: impl Into<Size>) -> Self {
86        self.props.size = size.into();
87        self
88    }
89}
90
91impl RenderOnce for Form {
92    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
93        let props = self.props;
94
95        let gap = match props.size {
96            Size::XSmall | Size::Small => px(6.),
97            Size::Large => px(12.),
98            _ => px(8.),
99        };
100
101        v_flex()
102            .w_full()
103            .gap_x(gap * 3.)
104            .gap_y(gap)
105            .grid()
106            .grid_cols(props.columns as u16)
107            .children(
108                self.fields
109                    .into_iter()
110                    .enumerate()
111                    .map(|(ix, field)| field.props(ix, props)),
112            )
113    }
114}