1use bevy::prelude::*;
3
4const ALIGN_ITEMS_COLOR: Color = Color::srgb(1., 0.066, 0.349);
5const JUSTIFY_CONTENT_COLOR: Color = Color::srgb(0.102, 0.522, 1.);
6const MARGIN: Val = Val::Px(12.);
7
8fn main() {
9 App::new()
10 .add_plugins(DefaultPlugins.set(WindowPlugin {
11 primary_window: Some(Window {
12 title: "Bevy Flex Layout Example".to_string(),
13 ..Default::default()
14 }),
15 ..Default::default()
16 }))
17 .add_systems(Startup, spawn_layout)
18 .run();
19}
20
21fn spawn_layout(mut commands: Commands, asset_server: Res<AssetServer>) {
22 let font = asset_server.load("fonts/FiraSans-Bold.ttf");
23 commands.spawn(Camera2d);
24 commands
25 .spawn((
26 Node {
27 width: percent(100),
29 height: percent(100),
30 flex_direction: FlexDirection::Column,
31 align_items: AlignItems::Center,
32 padding: UiRect::all(MARGIN),
33 row_gap: MARGIN,
34 ..Default::default()
35 },
36 BackgroundColor(Color::BLACK),
37 ))
38 .with_children(|builder| {
39 builder
41 .spawn(Node {
42 flex_direction: FlexDirection::Row,
43 ..default()
44 })
45 .with_children(|builder| {
46 spawn_nested_text_bundle(
47 builder,
48 font.clone(),
49 ALIGN_ITEMS_COLOR,
50 UiRect::right(MARGIN),
51 "AlignItems",
52 );
53 spawn_nested_text_bundle(
54 builder,
55 font.clone(),
56 JUSTIFY_CONTENT_COLOR,
57 UiRect::default(),
58 "JustifyContent",
59 );
60 });
61
62 builder
63 .spawn(Node {
64 width: percent(100),
65 height: percent(100),
66 flex_direction: FlexDirection::Column,
67 row_gap: MARGIN,
68 ..default()
69 })
70 .with_children(|builder| {
71 let justifications = [
73 JustifyContent::FlexStart,
74 JustifyContent::Center,
75 JustifyContent::FlexEnd,
76 JustifyContent::SpaceEvenly,
77 JustifyContent::SpaceAround,
78 JustifyContent::SpaceBetween,
79 ];
80 let alignments = [
81 AlignItems::Baseline,
82 AlignItems::FlexStart,
83 AlignItems::Center,
84 AlignItems::FlexEnd,
85 AlignItems::Stretch,
86 ];
87 for align_items in alignments {
88 builder
89 .spawn(Node {
90 width: percent(100),
91 height: percent(100),
92 flex_direction: FlexDirection::Row,
93 column_gap: MARGIN,
94 ..Default::default()
95 })
96 .with_children(|builder| {
97 for justify_content in justifications {
98 spawn_child_node(
99 builder,
100 font.clone(),
101 align_items,
102 justify_content,
103 );
104 }
105 });
106 }
107 });
108 });
109}
110
111fn spawn_child_node(
112 builder: &mut ChildSpawnerCommands,
113 font: Handle<Font>,
114 align_items: AlignItems,
115 justify_content: JustifyContent,
116) {
117 builder
118 .spawn((
119 Node {
120 flex_direction: FlexDirection::Column,
121 align_items,
122 justify_content,
123 width: percent(100),
124 height: percent(100),
125 ..default()
126 },
127 BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
128 ))
129 .with_children(|builder| {
130 let labels = [
131 (format!("{align_items:?}"), ALIGN_ITEMS_COLOR, 0.),
132 (format!("{justify_content:?}"), JUSTIFY_CONTENT_COLOR, 3.),
133 ];
134 for (text, color, top_margin) in labels {
135 spawn_nested_text_bundle(
137 builder,
138 font.clone(),
139 color,
140 UiRect::top(px(top_margin)),
141 &text,
142 );
143 }
144 });
145}
146
147fn spawn_nested_text_bundle(
148 builder: &mut ChildSpawnerCommands,
149 font: Handle<Font>,
150 background_color: Color,
151 margin: UiRect,
152 text: &str,
153) {
154 builder
155 .spawn((
156 Node {
157 margin,
158 padding: UiRect::axes(px(5), px(1)),
159 ..default()
160 },
161 BackgroundColor(background_color),
162 ))
163 .with_children(|builder| {
164 builder.spawn((
165 Text::new(text),
166 TextFont { font, ..default() },
167 TextColor::BLACK,
168 ));
169 });
170}