Skip to main content

borders/
borders.rs

1//! Example demonstrating bordered UI nodes
2
3use bevy::{color::palettes::css::*, ecs::spawn::SpawnIter, prelude::*};
4
5fn main() {
6    App::new()
7        .add_plugins(DefaultPlugins)
8        .add_systems(Startup, setup)
9        .run();
10}
11
12fn setup(mut commands: Commands) {
13    commands.spawn(Camera2d);
14
15    // labels for the different border edges
16    let border_labels = [
17        "None",
18        "All",
19        "Left",
20        "Right",
21        "Top",
22        "Bottom",
23        "Horizontal",
24        "Vertical",
25        "Top Left",
26        "Bottom Left",
27        "Top Right",
28        "Bottom Right",
29        "Top Bottom Right",
30        "Top Bottom Left",
31        "Top Left Right",
32        "Bottom Left Right",
33    ];
34
35    // all the different combinations of border edges
36    // these correspond to the labels above
37    let borders = [
38        UiRect::default(),
39        UiRect::all(px(10)),
40        UiRect::left(px(10)),
41        UiRect::right(px(10)),
42        UiRect::top(px(10)),
43        UiRect::bottom(px(10)),
44        UiRect::horizontal(px(10)),
45        UiRect::vertical(px(10)),
46        UiRect {
47            left: px(20),
48            top: px(10),
49            ..default()
50        },
51        UiRect {
52            left: px(10),
53            bottom: px(20),
54            ..default()
55        },
56        UiRect {
57            right: px(20),
58            top: px(10),
59            ..default()
60        },
61        UiRect {
62            right: px(10),
63            bottom: px(10),
64            ..default()
65        },
66        UiRect {
67            right: px(10),
68            top: px(20),
69            bottom: px(10),
70            ..default()
71        },
72        UiRect {
73            left: px(10),
74            top: px(10),
75            bottom: px(10),
76            ..default()
77        },
78        UiRect {
79            left: px(20),
80            right: px(10),
81            top: px(10),
82            ..default()
83        },
84        UiRect {
85            left: px(10),
86            right: px(10),
87            bottom: px(20),
88            ..default()
89        },
90    ];
91
92    let borders_examples = (
93        Node {
94            margin: px(25).all(),
95            flex_wrap: FlexWrap::Wrap,
96            ..default()
97        },
98        Children::spawn(SpawnIter(border_labels.into_iter().zip(borders).map(
99            |(label, border)| {
100                (
101                    Node {
102                        flex_direction: FlexDirection::Column,
103                        align_items: AlignItems::Center,
104                        ..default()
105                    },
106                    children![
107                        (
108                            Node {
109                                width: px(50),
110                                height: px(50),
111                                border,
112                                margin: px(20).all(),
113                                align_items: AlignItems::Center,
114                                justify_content: JustifyContent::Center,
115                                ..default()
116                            },
117                            BackgroundColor(MAROON.into()),
118                            BorderColor {
119                                top: RED.into(),
120                                bottom: YELLOW.into(),
121                                left: GREEN.into(),
122                                right: BLUE.into(),
123                            },
124                            Outline {
125                                width: px(6),
126                                offset: px(6),
127                                color: Color::WHITE,
128                            },
129                            children![(
130                                Node {
131                                    width: px(10),
132                                    height: px(10),
133                                    ..default()
134                                },
135                                BackgroundColor(YELLOW.into()),
136                            )]
137                        ),
138                        (Text::new(label), TextFont::from_font_size(9.0))
139                    ],
140                )
141            },
142        ))),
143    );
144
145    let non_zero = |x, y| x != px(0) && y != px(0);
146    let border_size = move |x, y| {
147        if non_zero(x, y) {
148            f32::MAX
149        } else {
150            0.
151        }
152    };
153
154    let rounded_border_radii = borders.map(|border| {
155        BorderRadius::px(
156            border_size(border.left, border.top),
157            border_size(border.right, border.top),
158            border_size(border.right, border.bottom),
159            border_size(border.left, border.bottom),
160        )
161    });
162
163    let elliptical_border_labels = [
164        "Ellipse Wide",
165        "Ellipse Tall",
166        "Ellipse Mixed",
167        "Ellipse Percent",
168    ];
169    let elliptical_borders = [
170        UiRect::all(px(10)),
171        UiRect::all(px(10)),
172        UiRect::all(px(10)),
173        UiRect::all(px(10)),
174    ];
175    let elliptical_border_radii = [
176        BorderRadius {
177            top_left: CornerRadius {
178                x: px(25),
179                y: px(8),
180            },
181            top_right: CornerRadius {
182                x: px(25),
183                y: px(8),
184            },
185            bottom_right: CornerRadius {
186                x: px(25),
187                y: px(8),
188            },
189            bottom_left: CornerRadius {
190                x: px(25),
191                y: px(8),
192            },
193        },
194        BorderRadius {
195            top_left: (px(8), px(25)).into(),
196            top_right: (px(8), px(25)).into(),
197            bottom_right: [px(8), px(25)].into(),
198            bottom_left: [px(8), px(25)].into(),
199        },
200        BorderRadius {
201            top_left: CornerRadius {
202                x: px(25),
203                y: px(12),
204            },
205            top_right: CornerRadius {
206                x: px(12),
207                y: px(25),
208            },
209            bottom_right: CornerRadius {
210                x: px(25),
211                y: px(12),
212            },
213            bottom_left: CornerRadius {
214                x: px(12),
215                y: px(25),
216            },
217        },
218        BorderRadius {
219            top_left: CornerRadius {
220                x: percent(50),
221                y: percent(20),
222            },
223            top_right: CornerRadius {
224                x: percent(20),
225                y: percent(50),
226            },
227            bottom_right: CornerRadius {
228                x: percent(50),
229                y: percent(20),
230            },
231            bottom_left: CornerRadius {
232                x: percent(20),
233                y: percent(50),
234            },
235        },
236    ];
237
238    let borders_examples_rounded = (
239        Node {
240            margin: px(25).all(),
241            flex_wrap: FlexWrap::Wrap,
242            ..default()
243        },
244        Children::spawn(SpawnIter(
245            border_labels
246                .into_iter()
247                .zip(borders)
248                .zip(rounded_border_radii)
249                .map(|((label, border), border_radius)| (label, border, border_radius))
250                .chain(
251                    elliptical_border_labels
252                        .into_iter()
253                        .zip(elliptical_borders)
254                        .zip(elliptical_border_radii)
255                        .map(|((label, border), border_radius)| (label, border, border_radius)),
256                )
257                .map(move |(label, border, border_radius)| {
258                    (
259                        Node {
260                            flex_direction: FlexDirection::Column,
261                            align_items: AlignItems::Center,
262                            ..default()
263                        },
264                        children![
265                            (
266                                Node {
267                                    width: px(50),
268                                    height: px(50),
269                                    border,
270                                    margin: px(20).all(),
271                                    align_items: AlignItems::Center,
272                                    justify_content: JustifyContent::Center,
273                                    border_radius,
274                                    ..default()
275                                },
276                                BackgroundColor(MAROON.into()),
277                                BorderColor {
278                                    top: RED.into(),
279                                    bottom: YELLOW.into(),
280                                    left: GREEN.into(),
281                                    right: BLUE.into(),
282                                },
283                                Outline {
284                                    width: px(6),
285                                    offset: px(6),
286                                    color: Color::WHITE,
287                                },
288                                children![(
289                                    Node {
290                                        width: px(10),
291                                        height: px(10),
292                                        border_radius: BorderRadius::MAX,
293                                        ..default()
294                                    },
295                                    BackgroundColor(YELLOW.into()),
296                                )],
297                            ),
298                            (Text::new(label), TextFont::from_font_size(9.0))
299                        ],
300                    )
301                }),
302        )),
303    );
304
305    commands.spawn((
306        Node {
307            margin: px(25).all(),
308            flex_direction: FlexDirection::Column,
309            align_self: AlignSelf::Stretch,
310            justify_self: JustifySelf::Stretch,
311            ..default()
312        },
313        BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
314        children![
315            label("Borders"),
316            borders_examples,
317            label("Borders Rounded"),
318            borders_examples_rounded
319        ],
320    ));
321}
322
323// A label widget that accepts a &str and returns
324// a Bundle that can be spawned
325fn label(text: &str) -> impl Bundle {
326    (
327        Node {
328            margin: px(25).all(),
329            ..default()
330        },
331        children![(Text::new(text), TextFont::from_font_size(20.0))],
332    )
333}