Skip to main content

guise/flex/
container.rs

1//! `Container`, `Padding`, `Align`, and `Center` — Flutter's box wrappers.
2
3use gpui::prelude::*;
4use gpui::{div, px, AnyElement, App, IntoElement, Window};
5
6use super::{apply_alignment, apply_margin, apply_padding, Alignment, EdgeInsets};
7use crate::theme::Color;
8
9/// A configurable box: size, padding, margin, color, radius, border, and child
10/// alignment. Flutter's `Container`.
11#[derive(IntoElement)]
12pub struct Container {
13    child: Option<AnyElement>,
14    width: Option<f32>,
15    height: Option<f32>,
16    padding: EdgeInsets,
17    margin: EdgeInsets,
18    color: Option<Color>,
19    radius: f32,
20    border: Option<(f32, Color)>,
21    alignment: Option<Alignment>,
22}
23
24impl Container {
25    pub fn new() -> Self {
26        Container {
27            child: None,
28            width: None,
29            height: None,
30            padding: EdgeInsets::default(),
31            margin: EdgeInsets::default(),
32            color: None,
33            radius: 0.0,
34            border: None,
35            alignment: None,
36        }
37    }
38
39    pub fn child(mut self, child: impl IntoElement) -> Self {
40        self.child = Some(child.into_any_element());
41        self
42    }
43
44    pub fn width(mut self, width: f32) -> Self {
45        self.width = Some(width);
46        self
47    }
48
49    pub fn height(mut self, height: f32) -> Self {
50        self.height = Some(height);
51        self
52    }
53
54    pub fn padding(mut self, padding: EdgeInsets) -> Self {
55        self.padding = padding;
56        self
57    }
58
59    pub fn margin(mut self, margin: EdgeInsets) -> Self {
60        self.margin = margin;
61        self
62    }
63
64    pub fn color(mut self, color: Color) -> Self {
65        self.color = Some(color);
66        self
67    }
68
69    pub fn radius(mut self, radius: f32) -> Self {
70        self.radius = radius;
71        self
72    }
73
74    pub fn border(mut self, width: f32, color: Color) -> Self {
75        self.border = Some((width, color));
76        self
77    }
78
79    pub fn alignment(mut self, alignment: Alignment) -> Self {
80        self.alignment = Some(alignment);
81        self
82    }
83}
84
85impl Default for Container {
86    fn default() -> Self {
87        Container::new()
88    }
89}
90
91impl RenderOnce for Container {
92    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
93        let mut el = div();
94        if let Some(w) = self.width {
95            el = el.w(px(w));
96        }
97        if let Some(h) = self.height {
98            el = el.h(px(h));
99        }
100        el = apply_padding(el, self.padding);
101        el = apply_margin(el, self.margin);
102        if let Some(color) = self.color {
103            el = el.bg(color.hsla());
104        }
105        if self.radius > 0.0 {
106            el = el.rounded(px(self.radius));
107        }
108        if let Some((width, color)) = self.border {
109            el = el.border(px(width)).border_color(color.hsla());
110        }
111        if let Some(alignment) = self.alignment {
112            el = apply_alignment(el.flex(), alignment);
113        }
114        if let Some(child) = self.child {
115            el = el.child(child);
116        }
117        el
118    }
119}
120
121/// Insets a single child. Flutter's `Padding`.
122#[derive(IntoElement)]
123pub struct Padding {
124    insets: EdgeInsets,
125    child: Option<AnyElement>,
126}
127
128impl Padding {
129    pub fn all(value: f32) -> Self {
130        Padding {
131            insets: EdgeInsets::all(value),
132            child: None,
133        }
134    }
135
136    pub fn symmetric(horizontal: f32, vertical: f32) -> Self {
137        Padding {
138            insets: EdgeInsets::symmetric(horizontal, vertical),
139            child: None,
140        }
141    }
142
143    pub fn only(insets: EdgeInsets) -> Self {
144        Padding {
145            insets,
146            child: None,
147        }
148    }
149
150    pub fn child(mut self, child: impl IntoElement) -> Self {
151        self.child = Some(child.into_any_element());
152        self
153    }
154}
155
156impl RenderOnce for Padding {
157    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
158        let mut el = apply_padding(div(), self.insets);
159        if let Some(child) = self.child {
160            el = el.child(child);
161        }
162        el
163    }
164}
165
166/// Aligns a single child within the available space. Flutter's `Align`.
167#[derive(IntoElement)]
168pub struct Align {
169    alignment: Alignment,
170    child: Option<AnyElement>,
171}
172
173impl Align {
174    pub fn new(alignment: Alignment) -> Self {
175        Align {
176            alignment,
177            child: None,
178        }
179    }
180
181    pub fn child(mut self, child: impl IntoElement) -> Self {
182        self.child = Some(child.into_any_element());
183        self
184    }
185}
186
187impl RenderOnce for Align {
188    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
189        let mut el = apply_alignment(div().flex().size_full(), self.alignment);
190        if let Some(child) = self.child {
191            el = el.child(child);
192        }
193        el
194    }
195}
196
197/// Centers a single child. Flutter's `Center`.
198#[derive(IntoElement)]
199pub struct Center {
200    child: Option<AnyElement>,
201}
202
203impl Center {
204    pub fn new() -> Self {
205        Center { child: None }
206    }
207
208    pub fn child(mut self, child: impl IntoElement) -> Self {
209        self.child = Some(child.into_any_element());
210        self
211    }
212}
213
214impl Default for Center {
215    fn default() -> Self {
216        Center::new()
217    }
218}
219
220impl RenderOnce for Center {
221    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
222        let mut el = div().flex().size_full().items_center().justify_center();
223        if let Some(child) = self.child {
224            el = el.child(child);
225        }
226        el
227    }
228}