borders/
borders.rs

1//! Example demonstrating bordered UI nodes
2
3use bevy::{color::palettes::css::*, 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    let root = commands
15        .spawn((
16            Node {
17                margin: UiRect::all(Val::Px(25.0)),
18                align_self: AlignSelf::Stretch,
19                justify_self: JustifySelf::Stretch,
20                flex_wrap: FlexWrap::Wrap,
21                justify_content: JustifyContent::FlexStart,
22                align_items: AlignItems::FlexStart,
23                align_content: AlignContent::FlexStart,
24                ..default()
25            },
26            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
27        ))
28        .id();
29
30    let root_rounded = commands
31        .spawn((
32            Node {
33                margin: UiRect::all(Val::Px(25.0)),
34                align_self: AlignSelf::Stretch,
35                justify_self: JustifySelf::Stretch,
36                flex_wrap: FlexWrap::Wrap,
37                justify_content: JustifyContent::FlexStart,
38                align_items: AlignItems::FlexStart,
39                align_content: AlignContent::FlexStart,
40                ..default()
41            },
42            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
43        ))
44        .id();
45
46    // labels for the different border edges
47    let border_labels = [
48        "None",
49        "All",
50        "Left",
51        "Right",
52        "Top",
53        "Bottom",
54        "Horizontal",
55        "Vertical",
56        "Top Left",
57        "Bottom Left",
58        "Top Right",
59        "Bottom Right",
60        "Top Bottom Right",
61        "Top Bottom Left",
62        "Top Left Right",
63        "Bottom Left Right",
64    ];
65
66    // all the different combinations of border edges
67    // these correspond to the labels above
68    let borders = [
69        UiRect::default(),
70        UiRect::all(Val::Px(10.)),
71        UiRect::left(Val::Px(10.)),
72        UiRect::right(Val::Px(10.)),
73        UiRect::top(Val::Px(10.)),
74        UiRect::bottom(Val::Px(10.)),
75        UiRect::horizontal(Val::Px(10.)),
76        UiRect::vertical(Val::Px(10.)),
77        UiRect {
78            left: Val::Px(20.),
79            top: Val::Px(10.),
80            ..Default::default()
81        },
82        UiRect {
83            left: Val::Px(10.),
84            bottom: Val::Px(20.),
85            ..Default::default()
86        },
87        UiRect {
88            right: Val::Px(20.),
89            top: Val::Px(10.),
90            ..Default::default()
91        },
92        UiRect {
93            right: Val::Px(10.),
94            bottom: Val::Px(10.),
95            ..Default::default()
96        },
97        UiRect {
98            right: Val::Px(10.),
99            top: Val::Px(20.),
100            bottom: Val::Px(10.),
101            ..Default::default()
102        },
103        UiRect {
104            left: Val::Px(10.),
105            top: Val::Px(10.),
106            bottom: Val::Px(10.),
107            ..Default::default()
108        },
109        UiRect {
110            left: Val::Px(20.),
111            right: Val::Px(10.),
112            top: Val::Px(10.),
113            ..Default::default()
114        },
115        UiRect {
116            left: Val::Px(10.),
117            right: Val::Px(10.),
118            bottom: Val::Px(20.),
119            ..Default::default()
120        },
121    ];
122
123    for (label, border) in border_labels.into_iter().zip(borders) {
124        let inner_spot = commands
125            .spawn((
126                Node {
127                    width: Val::Px(10.),
128                    height: Val::Px(10.),
129                    ..default()
130                },
131                BackgroundColor(YELLOW.into()),
132            ))
133            .id();
134        let border_node = commands
135            .spawn((
136                Node {
137                    width: Val::Px(50.),
138                    height: Val::Px(50.),
139                    border,
140                    margin: UiRect::all(Val::Px(20.)),
141                    align_items: AlignItems::Center,
142                    justify_content: JustifyContent::Center,
143                    ..default()
144                },
145                BackgroundColor(MAROON.into()),
146                BorderColor(RED.into()),
147                Outline {
148                    width: Val::Px(6.),
149                    offset: Val::Px(6.),
150                    color: Color::WHITE,
151                },
152            ))
153            .add_child(inner_spot)
154            .id();
155        let label_node = commands
156            .spawn((
157                Text::new(label),
158                TextFont {
159                    font_size: 9.0,
160                    ..Default::default()
161                },
162            ))
163            .id();
164        let container = commands
165            .spawn(Node {
166                flex_direction: FlexDirection::Column,
167                align_items: AlignItems::Center,
168                ..default()
169            })
170            .add_children(&[border_node, label_node])
171            .id();
172        commands.entity(root).add_child(container);
173    }
174
175    for (label, border) in border_labels.into_iter().zip(borders) {
176        let inner_spot = commands
177            .spawn((
178                Node {
179                    width: Val::Px(10.),
180                    height: Val::Px(10.),
181                    ..default()
182                },
183                BorderRadius::MAX,
184                BackgroundColor(YELLOW.into()),
185            ))
186            .id();
187        let non_zero = |x, y| x != Val::Px(0.) && y != Val::Px(0.);
188        let border_size = |x, y| if non_zero(x, y) { f32::MAX } else { 0. };
189        let border_radius = BorderRadius::px(
190            border_size(border.left, border.top),
191            border_size(border.right, border.top),
192            border_size(border.right, border.bottom),
193            border_size(border.left, border.bottom),
194        );
195        let border_node = commands
196            .spawn((
197                Node {
198                    width: Val::Px(50.),
199                    height: Val::Px(50.),
200                    border,
201                    margin: UiRect::all(Val::Px(20.)),
202                    align_items: AlignItems::Center,
203                    justify_content: JustifyContent::Center,
204                    ..default()
205                },
206                BackgroundColor(MAROON.into()),
207                BorderColor(RED.into()),
208                border_radius,
209                Outline {
210                    width: Val::Px(6.),
211                    offset: Val::Px(6.),
212                    color: Color::WHITE,
213                },
214            ))
215            .add_child(inner_spot)
216            .id();
217        let label_node = commands
218            .spawn((
219                Text::new(label),
220                TextFont {
221                    font_size: 9.0,
222                    ..Default::default()
223                },
224            ))
225            .id();
226        let container = commands
227            .spawn(Node {
228                flex_direction: FlexDirection::Column,
229                align_items: AlignItems::Center,
230                ..default()
231            })
232            .add_children(&[border_node, label_node])
233            .id();
234        commands.entity(root_rounded).add_child(container);
235    }
236
237    let border_label = commands
238        .spawn((
239            Node {
240                margin: UiRect {
241                    left: Val::Px(25.0),
242                    right: Val::Px(25.0),
243                    top: Val::Px(25.0),
244                    bottom: Val::Px(0.0),
245                },
246                ..default()
247            },
248            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
249        ))
250        .with_children(|builder| {
251            builder.spawn((
252                Text::new("Borders"),
253                TextFont {
254                    font_size: 20.0,
255                    ..Default::default()
256                },
257            ));
258        })
259        .id();
260
261    let border_rounded_label = commands
262        .spawn((
263            Node {
264                margin: UiRect {
265                    left: Val::Px(25.0),
266                    right: Val::Px(25.0),
267                    top: Val::Px(25.0),
268                    bottom: Val::Px(0.0),
269                },
270                ..default()
271            },
272            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
273        ))
274        .with_children(|builder| {
275            builder.spawn((
276                Text::new("Borders Rounded"),
277                TextFont {
278                    font_size: 20.0,
279                    ..Default::default()
280                },
281            ));
282        })
283        .id();
284
285    commands
286        .spawn((
287            Node {
288                margin: UiRect::all(Val::Px(25.0)),
289                flex_direction: FlexDirection::Column,
290                align_self: AlignSelf::Stretch,
291                justify_self: JustifySelf::Stretch,
292                flex_wrap: FlexWrap::Wrap,
293                justify_content: JustifyContent::FlexStart,
294                align_items: AlignItems::FlexStart,
295                align_content: AlignContent::FlexStart,
296                ..default()
297            },
298            BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
299        ))
300        .add_child(border_label)
301        .add_child(root)
302        .add_child(border_rounded_label)
303        .add_child(root_rounded);
304}