1use bevy::prelude::*;
4use crate::{dimensions, label::{LabelBuilder, LabelStyle}};
5use super::types::*;
6
7pub struct PanelBuilder {
9 style: PanelStyle,
10 width: Val,
11 height: Val,
12 min_width: Val,
13 min_height: Val,
14 max_width: Val,
15 max_height: Val,
16 padding: UiRect,
17 margin: UiRect,
18 flex_direction: FlexDirection,
19 justify_content: JustifyContent,
20 align_items: AlignItems,
21 position_type: PositionType,
22 display: Display,
23 overflow: Overflow,
24 custom_background: Option<Color>,
25 title: Option<String>,
26 column_gap: Val,
27 row_gap: Val,
28 flex_basis: Val,
29 flex_grow: f32,
30 custom_border: Option<UiRect>,
31}
32
33impl PanelBuilder {
34 pub fn new() -> Self {
35 Self {
36 style: PanelStyle::Default,
37 width: Val::Auto,
38 height: Val::Auto,
39 min_width: Val::Auto,
40 min_height: Val::Auto,
41 max_width: Val::Auto,
42 max_height: Val::Auto,
43 padding: UiRect::all(Val::Px(dimensions::PANEL_PADDING)),
44 margin: UiRect::all(Val::Px(0.0)),
45 flex_direction: FlexDirection::Column,
46 justify_content: JustifyContent::Start,
47 align_items: AlignItems::Stretch,
48 position_type: PositionType::Relative,
49 display: Display::Flex,
50 overflow: Overflow::visible(),
51 custom_background: None,
52 title: None,
53 column_gap: Val::Px(0.0),
54 row_gap: Val::Px(0.0),
55 flex_basis: Val::Auto,
56 flex_grow: 0.0,
57 custom_border: None,
58 }
59 }
60
61 pub fn style(mut self, style: PanelStyle) -> Self {
62 self.style = style;
63 self
64 }
65
66 pub fn width(mut self, width: Val) -> Self {
67 self.width = width;
68 self
69 }
70
71 pub fn height(mut self, height: Val) -> Self {
72 self.height = height;
73 self
74 }
75
76 pub fn min_width(mut self, min_width: Val) -> Self {
77 self.min_width = min_width;
78 self
79 }
80
81 pub fn min_height(mut self, min_height: Val) -> Self {
82 self.min_height = min_height;
83 self
84 }
85
86 pub fn max_width(mut self, max_width: Val) -> Self {
87 self.max_width = max_width;
88 self
89 }
90
91 pub fn max_height(mut self, max_height: Val) -> Self {
92 self.max_height = max_height;
93 self
94 }
95
96 pub fn overflow(mut self, overflow: Overflow) -> Self {
97 self.overflow = overflow;
98 self
99 }
100
101 pub fn padding(mut self, padding: UiRect) -> Self {
102 self.padding = padding;
103 self
104 }
105
106 pub fn margin(mut self, margin: UiRect) -> Self {
107 self.margin = margin;
108 self
109 }
110
111 pub fn flex_direction(mut self, direction: FlexDirection) -> Self {
112 self.flex_direction = direction;
113 self
114 }
115
116 pub fn justify_content(mut self, justify: JustifyContent) -> Self {
117 self.justify_content = justify;
118 self
119 }
120
121 pub fn align_items(mut self, align: AlignItems) -> Self {
122 self.align_items = align;
123 self
124 }
125
126 pub fn position_type(mut self, position: PositionType) -> Self {
127 self.position_type = position;
128 self
129 }
130
131 pub fn display(mut self, display: Display) -> Self {
132 self.display = display;
133 self
134 }
135
136 pub fn custom_background(mut self, color: Color) -> Self {
138 self.custom_background = Some(color);
139 self
140 }
141
142 pub fn with_title(mut self, title: impl Into<String>) -> Self {
144 self.title = Some(title.into());
145 self
146 }
147
148 pub fn column_gap(mut self, gap: Val) -> Self {
150 self.column_gap = gap;
151 self
152 }
153
154 pub fn row_gap(mut self, gap: Val) -> Self {
156 self.row_gap = gap;
157 self
158 }
159
160 pub fn flex_basis(mut self, basis: Val) -> Self {
162 self.flex_basis = basis;
163 self
164 }
165
166 pub fn flex_grow(mut self, grow: f32) -> Self {
168 self.flex_grow = grow;
169 self
170 }
171
172 pub fn background_color(mut self, color: Color) -> Self {
174 self.custom_background = Some(color);
175 self
176 }
177
178 pub fn border(mut self, border: UiRect) -> Self {
180 self.custom_border = Some(border);
181 self
182 }
183
184 pub fn build(self, parent: &mut ChildSpawnerCommands) -> Entity {
185 let background_color = self
186 .custom_background
187 .unwrap_or_else(|| self.style.background_color());
188
189 let border = self
190 .custom_border
191 .unwrap_or_else(|| UiRect::all(self.style.border_width()));
192
193 let mut panel_entity = parent.spawn((
194 Node {
195 width: self.width,
196 height: self.height,
197 min_width: self.min_width,
198 min_height: self.min_height,
199 max_width: self.max_width,
200 max_height: self.max_height,
201 padding: self.padding,
202 margin: self.margin,
203 border,
204 flex_direction: self.flex_direction,
205 justify_content: self.justify_content,
206 align_items: self.align_items,
207 position_type: self.position_type,
208 display: self.display,
209 overflow: self.overflow,
210 column_gap: self.column_gap,
211 row_gap: self.row_gap,
212 flex_basis: self.flex_basis,
213 flex_grow: self.flex_grow,
214 ..default()
215 },
216 BackgroundColor(background_color),
217 BorderColor(self.style.border_color()),
218 Panel { style: self.style },
219 ));
220
221 if let Some(title) = self.title {
223 panel_entity.with_children(|parent| {
224 LabelBuilder::new(title)
225 .style(LabelStyle::Title)
226 .margin(UiRect::bottom(Val::Px(dimensions::MARGIN_SMALL)))
227 .build(parent);
228 });
229 }
230
231 panel_entity.id()
232 }
233
234 pub fn build_with_children<F>(
235 self,
236 parent: &mut ChildSpawnerCommands,
237 children: F,
238 ) -> Entity
239 where
240 F: FnOnce(&mut ChildSpawnerCommands),
241 {
242 let background_color = self
243 .custom_background
244 .unwrap_or_else(|| self.style.background_color());
245
246 let border = self
247 .custom_border
248 .unwrap_or_else(|| UiRect::all(self.style.border_width()));
249 let title = self.title.clone(); parent
252 .spawn((
253 Node {
254 width: self.width,
255 height: self.height,
256 min_width: self.min_width,
257 min_height: self.min_height,
258 max_width: self.max_width,
259 max_height: self.max_height,
260 padding: self.padding,
261 margin: self.margin,
262 border,
263 flex_direction: self.flex_direction,
264 justify_content: self.justify_content,
265 align_items: self.align_items,
266 position_type: self.position_type,
267 display: self.display,
268 overflow: self.overflow,
269 column_gap: self.column_gap,
270 row_gap: self.row_gap,
271 flex_basis: self.flex_basis,
272 flex_grow: self.flex_grow,
273 ..default()
274 },
275 BackgroundColor(background_color),
276 BorderColor(self.style.border_color()),
277 Panel { style: self.style },
278 ))
279 .with_children(|parent| {
280 if let Some(title_text) = title {
282 LabelBuilder::new(title_text)
283 .style(LabelStyle::Title)
284 .margin(UiRect::bottom(Val::Px(dimensions::MARGIN_SMALL)))
285 .build(parent);
286 }
287
288 children(parent);
290 })
291 .id()
292 }
293}
294
295pub fn panel() -> PanelBuilder {
297 PanelBuilder::new()
298}