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 border_color: Option<Color>,
32}
33
34impl PanelBuilder {
35 pub fn new() -> Self {
36 Self {
37 style: PanelStyle::Default,
38 width: Val::Auto,
39 height: Val::Auto,
40 min_width: Val::Auto,
41 min_height: Val::Auto,
42 max_width: Val::Auto,
43 max_height: Val::Auto,
44 padding: UiRect::all(Val::Px(dimensions::PANEL_PADDING)),
45 margin: UiRect::all(Val::Px(0.0)),
46 flex_direction: FlexDirection::Column,
47 justify_content: JustifyContent::Start,
48 align_items: AlignItems::Stretch,
49 position_type: PositionType::Relative,
50 display: Display::Flex,
51 overflow: Overflow::visible(),
52 custom_background: None,
53 title: None,
54 column_gap: Val::Px(0.0),
55 row_gap: Val::Px(0.0),
56 flex_basis: Val::Auto,
57 flex_grow: 0.0,
58 custom_border: None,
59 border_color: None,
60 }
61 }
62
63 pub fn style(mut self, style: PanelStyle) -> Self {
64 self.style = style;
65 self
66 }
67
68 pub fn width(mut self, width: Val) -> Self {
69 self.width = width;
70 self
71 }
72
73 pub fn height(mut self, height: Val) -> Self {
74 self.height = height;
75 self
76 }
77
78 pub fn min_width(mut self, min_width: Val) -> Self {
79 self.min_width = min_width;
80 self
81 }
82
83 pub fn min_height(mut self, min_height: Val) -> Self {
84 self.min_height = min_height;
85 self
86 }
87
88 pub fn max_width(mut self, max_width: Val) -> Self {
89 self.max_width = max_width;
90 self
91 }
92
93 pub fn max_height(mut self, max_height: Val) -> Self {
94 self.max_height = max_height;
95 self
96 }
97
98 pub fn overflow(mut self, overflow: Overflow) -> Self {
99 self.overflow = overflow;
100 self
101 }
102
103 pub fn scrollable(mut self) -> Self {
105 self.overflow = Overflow::scroll_y();
106 self
107 }
108
109 pub fn scrollable_both(mut self) -> Self {
111 self.overflow = Overflow::scroll();
112 self
113 }
114
115 pub fn responsive_padding(mut self) -> Self {
117 self.padding = UiRect::all(Val::Vw(2.0)); self
119 }
120
121 pub fn padding(mut self, padding: UiRect) -> Self {
122 self.padding = padding;
123 self
124 }
125
126 pub fn margin(mut self, margin: UiRect) -> Self {
127 self.margin = margin;
128 self
129 }
130
131 pub fn flex_direction(mut self, direction: FlexDirection) -> Self {
132 self.flex_direction = direction;
133 self
134 }
135
136 pub fn justify_content(mut self, justify: JustifyContent) -> Self {
137 self.justify_content = justify;
138 self
139 }
140
141 pub fn align_items(mut self, align: AlignItems) -> Self {
142 self.align_items = align;
143 self
144 }
145
146 pub fn position_type(mut self, position: PositionType) -> Self {
147 self.position_type = position;
148 self
149 }
150
151 pub fn display(mut self, display: Display) -> Self {
152 self.display = display;
153 self
154 }
155
156 pub fn custom_background(mut self, color: Color) -> Self {
158 self.custom_background = Some(color);
159 self
160 }
161
162 pub fn with_title(mut self, title: impl Into<String>) -> Self {
164 self.title = Some(title.into());
165 self
166 }
167
168 pub fn column_gap(mut self, gap: Val) -> Self {
170 self.column_gap = gap;
171 self
172 }
173
174 pub fn row_gap(mut self, gap: Val) -> Self {
176 self.row_gap = gap;
177 self
178 }
179
180 pub fn flex_basis(mut self, basis: Val) -> Self {
182 self.flex_basis = basis;
183 self
184 }
185
186 pub fn flex_grow(mut self, grow: f32) -> Self {
188 self.flex_grow = grow;
189 self
190 }
191
192 pub fn background_color(mut self, color: Color) -> Self {
194 self.custom_background = Some(color);
195 self
196 }
197
198 pub fn border(mut self, border: UiRect) -> Self {
200 self.custom_border = Some(border);
201 self
202 }
203
204 pub fn border_color(mut self, color: Color) -> Self {
206 self.border_color = Some(color);
207 self
208 }
209
210 pub fn build(self, parent: &mut ChildSpawnerCommands) -> Entity {
211 let background_color = self
212 .custom_background
213 .unwrap_or_else(|| self.style.background_color());
214
215 let border = self
216 .custom_border
217 .unwrap_or_else(|| UiRect::all(self.style.border_width()));
218
219 let border_color = self
220 .border_color
221 .unwrap_or_else(|| self.style.border_color());
222
223 let mut panel_entity = parent.spawn((
224 Node {
225 width: self.width,
226 height: self.height,
227 min_width: self.min_width,
228 min_height: self.min_height,
229 max_width: self.max_width,
230 max_height: self.max_height,
231 padding: self.padding,
232 margin: self.margin,
233 border,
234 flex_direction: self.flex_direction,
235 justify_content: self.justify_content,
236 align_items: self.align_items,
237 position_type: self.position_type,
238 display: self.display,
239 overflow: self.overflow,
240 column_gap: self.column_gap,
241 row_gap: self.row_gap,
242 flex_basis: self.flex_basis,
243 flex_grow: self.flex_grow,
244 ..default()
245 },
246 BackgroundColor(background_color),
247 BorderColor(border_color),
248 Panel { style: self.style },
249 ));
250
251 if let Some(title) = self.title {
253 panel_entity.with_children(|parent| {
254 LabelBuilder::new(title)
255 .style(LabelStyle::Title)
256 .margin(UiRect::bottom(Val::Px(dimensions::MARGIN_SMALL)))
257 .build(parent);
258 });
259 }
260
261 panel_entity.id()
262 }
263
264 pub fn build_with_children<F>(
265 self,
266 parent: &mut ChildSpawnerCommands,
267 children: F,
268 ) -> Entity
269 where
270 F: FnOnce(&mut ChildSpawnerCommands),
271 {
272 let background_color = self
273 .custom_background
274 .unwrap_or_else(|| self.style.background_color());
275
276 let border = self
277 .custom_border
278 .unwrap_or_else(|| UiRect::all(self.style.border_width()));
279 let title = self.title.clone(); parent
282 .spawn((
283 Node {
284 width: self.width,
285 height: self.height,
286 min_width: self.min_width,
287 min_height: self.min_height,
288 max_width: self.max_width,
289 max_height: self.max_height,
290 padding: self.padding,
291 margin: self.margin,
292 border,
293 flex_direction: self.flex_direction,
294 justify_content: self.justify_content,
295 align_items: self.align_items,
296 position_type: self.position_type,
297 display: self.display,
298 overflow: self.overflow,
299 column_gap: self.column_gap,
300 row_gap: self.row_gap,
301 flex_basis: self.flex_basis,
302 flex_grow: self.flex_grow,
303 ..default()
304 },
305 BackgroundColor(background_color),
306 BorderColor(self.style.border_color()),
307 Panel { style: self.style },
308 ))
309 .with_children(|parent| {
310 if let Some(title_text) = title {
312 LabelBuilder::new(title_text)
313 .style(LabelStyle::Title)
314 .margin(UiRect::bottom(Val::Px(dimensions::MARGIN_SMALL)))
315 .build(parent);
316 }
317
318 children(parent);
320 })
321 .id()
322 }
323}
324
325pub fn panel() -> PanelBuilder {
327 PanelBuilder::new()
328}