Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/testbed/ui.rs
6592 views
1
//! UI testbed
2
//!
3
//! You can switch scene by pressing the spacebar
4
5
mod helpers;
6
7
use bevy::prelude::*;
8
use helpers::Next;
9
10
fn main() {
11
let mut app = App::new();
12
app.add_plugins((DefaultPlugins,))
13
.init_state::<Scene>()
14
.add_systems(OnEnter(Scene::Image), image::setup)
15
.add_systems(OnEnter(Scene::Text), text::setup)
16
.add_systems(OnEnter(Scene::Grid), grid::setup)
17
.add_systems(OnEnter(Scene::Borders), borders::setup)
18
.add_systems(OnEnter(Scene::BoxShadow), box_shadow::setup)
19
.add_systems(OnEnter(Scene::TextWrap), text_wrap::setup)
20
.add_systems(OnEnter(Scene::Overflow), overflow::setup)
21
.add_systems(OnEnter(Scene::Slice), slice::setup)
22
.add_systems(OnEnter(Scene::LayoutRounding), layout_rounding::setup)
23
.add_systems(OnEnter(Scene::LinearGradient), linear_gradient::setup)
24
.add_systems(OnEnter(Scene::RadialGradient), radial_gradient::setup)
25
.add_systems(Update, switch_scene);
26
27
#[cfg(feature = "bevy_ci_testing")]
28
app.add_systems(Update, helpers::switch_scene_in_ci::<Scene>);
29
30
app.run();
31
}
32
33
#[derive(Debug, Clone, Eq, PartialEq, Hash, States, Default)]
34
#[states(scoped_entities)]
35
enum Scene {
36
#[default]
37
Image,
38
Text,
39
Grid,
40
Borders,
41
BoxShadow,
42
TextWrap,
43
Overflow,
44
Slice,
45
LayoutRounding,
46
LinearGradient,
47
RadialGradient,
48
}
49
50
impl Next for Scene {
51
fn next(&self) -> Self {
52
match self {
53
Scene::Image => Scene::Text,
54
Scene::Text => Scene::Grid,
55
Scene::Grid => Scene::Borders,
56
Scene::Borders => Scene::BoxShadow,
57
Scene::BoxShadow => Scene::TextWrap,
58
Scene::TextWrap => Scene::Overflow,
59
Scene::Overflow => Scene::Slice,
60
Scene::Slice => Scene::LayoutRounding,
61
Scene::LayoutRounding => Scene::LinearGradient,
62
Scene::LinearGradient => Scene::RadialGradient,
63
Scene::RadialGradient => Scene::Image,
64
}
65
}
66
}
67
68
fn switch_scene(
69
keyboard: Res<ButtonInput<KeyCode>>,
70
scene: Res<State<Scene>>,
71
mut next_scene: ResMut<NextState<Scene>>,
72
) {
73
if keyboard.just_pressed(KeyCode::Space) {
74
info!("Switching scene");
75
next_scene.set(scene.get().next());
76
}
77
}
78
79
mod image {
80
use bevy::prelude::*;
81
82
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
83
commands.spawn((Camera2d, DespawnOnExit(super::Scene::Image)));
84
commands.spawn((
85
ImageNode::new(asset_server.load("branding/bevy_logo_dark.png")),
86
DespawnOnExit(super::Scene::Image),
87
));
88
}
89
}
90
91
mod text {
92
use bevy::{color::palettes::css::*, prelude::*};
93
94
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
95
commands.spawn((Camera2d, DespawnOnExit(super::Scene::Text)));
96
commands.spawn((
97
Text::new("Hello World."),
98
TextFont {
99
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
100
font_size: 200.,
101
..default()
102
},
103
DespawnOnExit(super::Scene::Text),
104
));
105
106
commands.spawn((
107
Node {
108
left: px(100.),
109
top: px(250.),
110
..Default::default()
111
},
112
Text::new("white "),
113
TextFont {
114
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
115
..default()
116
},
117
DespawnOnExit(super::Scene::Text),
118
children![
119
(TextSpan::new("red "), TextColor(RED.into()),),
120
(TextSpan::new("green "), TextColor(GREEN.into()),),
121
(TextSpan::new("blue "), TextColor(BLUE.into()),),
122
(
123
TextSpan::new("black"),
124
TextColor(Color::BLACK),
125
TextFont {
126
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
127
..default()
128
},
129
TextBackgroundColor(Color::WHITE)
130
),
131
],
132
));
133
134
commands.spawn((
135
Node {
136
left: px(100.),
137
top: px(300.),
138
..Default::default()
139
},
140
Text::new(""),
141
TextFont {
142
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
143
..default()
144
},
145
DespawnOnExit(super::Scene::Text),
146
children![
147
(
148
TextSpan::new("white "),
149
TextFont {
150
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
151
..default()
152
}
153
),
154
(TextSpan::new("red "), TextColor(RED.into()),),
155
(TextSpan::new("green "), TextColor(GREEN.into()),),
156
(TextSpan::new("blue "), TextColor(BLUE.into()),),
157
(
158
TextSpan::new("black"),
159
TextColor(Color::BLACK),
160
TextFont {
161
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
162
..default()
163
},
164
TextBackgroundColor(Color::WHITE)
165
),
166
],
167
));
168
169
commands.spawn((
170
Node {
171
left: px(100.),
172
top: px(350.),
173
..Default::default()
174
},
175
Text::new(""),
176
TextFont {
177
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
178
..default()
179
},
180
DespawnOnExit(super::Scene::Text),
181
children![
182
(TextSpan::new(""), TextColor(YELLOW.into()),),
183
TextSpan::new(""),
184
(
185
TextSpan::new("white "),
186
TextFont {
187
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
188
..default()
189
}
190
),
191
TextSpan::new(""),
192
(TextSpan::new("red "), TextColor(RED.into()),),
193
TextSpan::new(""),
194
TextSpan::new(""),
195
(TextSpan::new("green "), TextColor(GREEN.into()),),
196
(TextSpan::new(""), TextColor(YELLOW.into()),),
197
(TextSpan::new("blue "), TextColor(BLUE.into()),),
198
TextSpan::new(""),
199
(TextSpan::new(""), TextColor(YELLOW.into()),),
200
(
201
TextSpan::new("black"),
202
TextColor(Color::BLACK),
203
TextFont {
204
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
205
..default()
206
},
207
TextBackgroundColor(Color::WHITE)
208
),
209
TextSpan::new(""),
210
],
211
));
212
}
213
}
214
215
mod grid {
216
use bevy::{color::palettes::css::*, prelude::*};
217
218
pub fn setup(mut commands: Commands) {
219
commands.spawn((Camera2d, DespawnOnExit(super::Scene::Grid)));
220
// Top-level grid (app frame)
221
commands.spawn((
222
Node {
223
display: Display::Grid,
224
width: percent(100),
225
height: percent(100),
226
grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
227
grid_template_rows: vec![
228
GridTrack::auto(),
229
GridTrack::flex(1.0),
230
GridTrack::px(40.),
231
],
232
..default()
233
},
234
BackgroundColor(Color::WHITE),
235
DespawnOnExit(super::Scene::Grid),
236
children![
237
// Header
238
(
239
Node {
240
display: Display::Grid,
241
grid_column: GridPlacement::span(2),
242
padding: UiRect::all(px(40)),
243
..default()
244
},
245
BackgroundColor(RED.into()),
246
),
247
// Main content grid (auto placed in row 2, column 1)
248
(
249
Node {
250
height: percent(100),
251
aspect_ratio: Some(1.0),
252
display: Display::Grid,
253
grid_template_columns: RepeatedGridTrack::flex(3, 1.0),
254
grid_template_rows: RepeatedGridTrack::flex(2, 1.0),
255
row_gap: px(12),
256
column_gap: px(12),
257
..default()
258
},
259
BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
260
children![
261
(Node::default(), BackgroundColor(ORANGE.into())),
262
(Node::default(), BackgroundColor(BISQUE.into())),
263
(Node::default(), BackgroundColor(BLUE.into())),
264
(Node::default(), BackgroundColor(CRIMSON.into())),
265
(Node::default(), BackgroundColor(AQUA.into())),
266
]
267
),
268
// Right side bar (auto placed in row 2, column 2)
269
(Node::DEFAULT, BackgroundColor(BLACK.into())),
270
],
271
));
272
}
273
}
274
275
mod borders {
276
use bevy::{color::palettes::css::*, prelude::*};
277
278
pub fn setup(mut commands: Commands) {
279
commands.spawn((Camera2d, DespawnOnExit(super::Scene::Borders)));
280
let root = commands
281
.spawn((
282
Node {
283
flex_wrap: FlexWrap::Wrap,
284
..default()
285
},
286
DespawnOnExit(super::Scene::Borders),
287
))
288
.id();
289
290
// all the different combinations of border edges
291
let borders = [
292
UiRect::default(),
293
UiRect::all(px(20)),
294
UiRect::left(px(20)),
295
UiRect::vertical(px(20)),
296
UiRect {
297
left: px(40),
298
top: px(20),
299
..Default::default()
300
},
301
UiRect {
302
right: px(20),
303
bottom: px(30),
304
..Default::default()
305
},
306
UiRect {
307
right: px(20),
308
top: px(40),
309
bottom: px(20),
310
..Default::default()
311
},
312
UiRect {
313
left: px(20),
314
top: px(20),
315
bottom: px(20),
316
..Default::default()
317
},
318
UiRect {
319
left: px(20),
320
right: px(20),
321
bottom: px(40),
322
..Default::default()
323
},
324
];
325
326
let non_zero = |x, y| x != px(0) && y != px(0);
327
let border_size = |x, y| if non_zero(x, y) { f32::MAX } else { 0. };
328
329
for border in borders {
330
for rounded in [true, false] {
331
let border_node = commands
332
.spawn((
333
Node {
334
width: px(100),
335
height: px(100),
336
border,
337
margin: UiRect::all(px(30)),
338
align_items: AlignItems::Center,
339
justify_content: JustifyContent::Center,
340
..default()
341
},
342
BackgroundColor(MAROON.into()),
343
BorderColor::all(RED),
344
Outline {
345
width: px(10),
346
offset: px(10),
347
color: Color::WHITE,
348
},
349
))
350
.id();
351
352
if rounded {
353
let border_radius = BorderRadius::px(
354
border_size(border.left, border.top),
355
border_size(border.right, border.top),
356
border_size(border.right, border.bottom),
357
border_size(border.left, border.bottom),
358
);
359
commands.entity(border_node).insert(border_radius);
360
}
361
362
commands.entity(root).add_child(border_node);
363
}
364
}
365
}
366
}
367
368
mod box_shadow {
369
use bevy::{color::palettes::css::*, prelude::*};
370
371
pub fn setup(mut commands: Commands) {
372
commands.spawn((Camera2d, DespawnOnExit(super::Scene::BoxShadow)));
373
374
commands
375
.spawn((
376
Node {
377
width: percent(100),
378
height: percent(100),
379
padding: UiRect::all(px(30)),
380
column_gap: px(200),
381
flex_wrap: FlexWrap::Wrap,
382
..default()
383
},
384
BackgroundColor(GREEN.into()),
385
DespawnOnExit(super::Scene::BoxShadow),
386
))
387
.with_children(|commands| {
388
let example_nodes = [
389
(
390
Vec2::splat(100.),
391
Vec2::ZERO,
392
10.,
393
0.,
394
BorderRadius::bottom_right(px(10)),
395
),
396
(Vec2::new(200., 50.), Vec2::ZERO, 10., 0., BorderRadius::MAX),
397
(
398
Vec2::new(100., 50.),
399
Vec2::ZERO,
400
10.,
401
10.,
402
BorderRadius::ZERO,
403
),
404
(
405
Vec2::splat(100.),
406
Vec2::splat(20.),
407
10.,
408
10.,
409
BorderRadius::bottom_right(px(10)),
410
),
411
(
412
Vec2::splat(100.),
413
Vec2::splat(50.),
414
0.,
415
10.,
416
BorderRadius::ZERO,
417
),
418
(
419
Vec2::new(50., 100.),
420
Vec2::splat(10.),
421
0.,
422
10.,
423
BorderRadius::MAX,
424
),
425
];
426
427
for (size, offset, spread, blur, border_radius) in example_nodes {
428
commands.spawn((
429
Node {
430
width: px(size.x),
431
height: px(size.y),
432
border: UiRect::all(px(2)),
433
..default()
434
},
435
BorderColor::all(WHITE),
436
border_radius,
437
BackgroundColor(BLUE.into()),
438
BoxShadow::new(
439
Color::BLACK.with_alpha(0.9),
440
percent(offset.x),
441
percent(offset.y),
442
percent(spread),
443
px(blur),
444
),
445
));
446
}
447
});
448
}
449
}
450
451
mod text_wrap {
452
use bevy::prelude::*;
453
454
pub fn setup(mut commands: Commands) {
455
commands.spawn((Camera2d, DespawnOnExit(super::Scene::TextWrap)));
456
457
let root = commands
458
.spawn((
459
Node {
460
flex_direction: FlexDirection::Column,
461
width: px(200),
462
height: percent(100),
463
overflow: Overflow::clip_x(),
464
..default()
465
},
466
BackgroundColor(Color::BLACK),
467
DespawnOnExit(super::Scene::TextWrap),
468
))
469
.id();
470
471
for linebreak in [
472
LineBreak::AnyCharacter,
473
LineBreak::WordBoundary,
474
LineBreak::WordOrCharacter,
475
LineBreak::NoWrap,
476
] {
477
let messages = [
478
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.".to_string(),
479
"pneumonoultramicroscopicsilicovolcanoconiosis".to_string(),
480
];
481
482
for (j, message) in messages.into_iter().enumerate() {
483
commands.entity(root).with_child((
484
Text(message.clone()),
485
TextLayout::new(Justify::Left, linebreak),
486
BackgroundColor(Color::srgb(0.8 - j as f32 * 0.3, 0., 0.)),
487
));
488
}
489
}
490
}
491
}
492
493
mod overflow {
494
use bevy::{color::palettes::css::*, prelude::*};
495
496
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
497
commands.spawn((Camera2d, DespawnOnExit(super::Scene::Overflow)));
498
let image = asset_server.load("branding/icon.png");
499
500
commands
501
.spawn((
502
Node {
503
width: percent(100),
504
height: percent(100),
505
align_items: AlignItems::Center,
506
justify_content: JustifyContent::SpaceAround,
507
..Default::default()
508
},
509
BackgroundColor(BLUE.into()),
510
DespawnOnExit(super::Scene::Overflow),
511
))
512
.with_children(|parent| {
513
for overflow in [
514
Overflow::visible(),
515
Overflow::clip_x(),
516
Overflow::clip_y(),
517
Overflow::clip(),
518
] {
519
parent
520
.spawn((
521
Node {
522
width: px(100),
523
height: px(100),
524
padding: UiRect {
525
left: px(25),
526
top: px(25),
527
..Default::default()
528
},
529
border: UiRect::all(px(5)),
530
overflow,
531
..default()
532
},
533
BorderColor::all(RED),
534
BackgroundColor(Color::WHITE),
535
))
536
.with_children(|parent| {
537
parent.spawn((
538
ImageNode::new(image.clone()),
539
Node {
540
min_width: px(100),
541
min_height: px(100),
542
..default()
543
},
544
Interaction::default(),
545
Outline {
546
width: px(2),
547
offset: px(2),
548
color: Color::NONE,
549
},
550
));
551
});
552
}
553
});
554
}
555
}
556
557
mod slice {
558
use bevy::prelude::*;
559
560
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
561
commands.spawn((Camera2d, DespawnOnExit(super::Scene::Slice)));
562
let image = asset_server.load("textures/fantasy_ui_borders/numbered_slices.png");
563
564
let slicer = TextureSlicer {
565
border: BorderRect::all(16.0),
566
center_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
567
sides_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
568
..default()
569
};
570
commands
571
.spawn((
572
Node {
573
width: percent(100),
574
height: percent(100),
575
align_items: AlignItems::Center,
576
justify_content: JustifyContent::SpaceAround,
577
..default()
578
},
579
DespawnOnExit(super::Scene::Slice),
580
))
581
.with_children(|parent| {
582
for [w, h] in [[150.0, 150.0], [300.0, 150.0], [150.0, 300.0]] {
583
parent.spawn((
584
Button,
585
ImageNode {
586
image: image.clone(),
587
image_mode: NodeImageMode::Sliced(slicer.clone()),
588
..default()
589
},
590
Node {
591
width: px(w),
592
height: px(h),
593
..default()
594
},
595
));
596
}
597
598
parent.spawn((
599
ImageNode {
600
image: asset_server
601
.load("textures/fantasy_ui_borders/panel-border-010.png"),
602
image_mode: NodeImageMode::Sliced(TextureSlicer {
603
border: BorderRect::all(22.0),
604
center_scale_mode: SliceScaleMode::Stretch,
605
sides_scale_mode: SliceScaleMode::Stretch,
606
max_corner_scale: 1.0,
607
}),
608
..Default::default()
609
},
610
Node {
611
width: px(100),
612
height: px(100),
613
..default()
614
},
615
BackgroundColor(bevy::color::palettes::css::NAVY.into()),
616
));
617
});
618
}
619
}
620
621
mod layout_rounding {
622
use bevy::{color::palettes::css::*, prelude::*};
623
624
pub fn setup(mut commands: Commands) {
625
commands.spawn((Camera2d, DespawnOnExit(super::Scene::LayoutRounding)));
626
627
commands
628
.spawn((
629
Node {
630
display: Display::Grid,
631
width: percent(100),
632
height: percent(100),
633
grid_template_rows: vec![RepeatedGridTrack::fr(10, 1.)],
634
..Default::default()
635
},
636
BackgroundColor(Color::WHITE),
637
DespawnOnExit(super::Scene::LayoutRounding),
638
))
639
.with_children(|commands| {
640
for i in 2..12 {
641
commands
642
.spawn(Node {
643
display: Display::Grid,
644
grid_template_columns: vec![RepeatedGridTrack::fr(i, 1.)],
645
..Default::default()
646
})
647
.with_children(|commands| {
648
for _ in 0..i {
649
commands.spawn((
650
Node {
651
border: UiRect::all(px(5)),
652
..Default::default()
653
},
654
BackgroundColor(MAROON.into()),
655
BorderColor::all(DARK_BLUE),
656
));
657
}
658
});
659
}
660
});
661
}
662
}
663
664
mod linear_gradient {
665
use bevy::camera::Camera2d;
666
use bevy::color::palettes::css::BLUE;
667
use bevy::color::palettes::css::LIME;
668
use bevy::color::palettes::css::RED;
669
use bevy::color::palettes::css::YELLOW;
670
use bevy::color::Color;
671
use bevy::ecs::prelude::*;
672
use bevy::state::state_scoped::DespawnOnExit;
673
use bevy::text::TextFont;
674
use bevy::ui::AlignItems;
675
use bevy::ui::BackgroundGradient;
676
use bevy::ui::ColorStop;
677
use bevy::ui::GridPlacement;
678
use bevy::ui::InterpolationColorSpace;
679
use bevy::ui::JustifyContent;
680
use bevy::ui::LinearGradient;
681
use bevy::ui::Node;
682
use bevy::ui::PositionType;
683
use bevy::utils::default;
684
685
pub fn setup(mut commands: Commands) {
686
commands.spawn((Camera2d, DespawnOnExit(super::Scene::LinearGradient)));
687
commands
688
.spawn((
689
Node {
690
flex_direction: bevy::ui::FlexDirection::Column,
691
width: bevy::ui::percent(100),
692
height: bevy::ui::percent(100),
693
justify_content: JustifyContent::Center,
694
align_items: AlignItems::Center,
695
row_gap: bevy::ui::px(5),
696
..default()
697
},
698
DespawnOnExit(super::Scene::LinearGradient),
699
))
700
.with_children(|commands| {
701
let mut i = 0;
702
commands
703
.spawn(Node {
704
display: bevy::ui::Display::Grid,
705
row_gap: bevy::ui::px(4),
706
column_gap: bevy::ui::px(4),
707
..Default::default()
708
})
709
.with_children(|commands| {
710
for stops in [
711
vec![ColorStop::auto(RED), ColorStop::auto(YELLOW)],
712
vec![
713
ColorStop::auto(Color::BLACK),
714
ColorStop::auto(RED),
715
ColorStop::auto(Color::WHITE),
716
],
717
vec![
718
Color::hsl(180.71191, 0.0, 0.3137255).into(),
719
Color::hsl(180.71191, 0.5, 0.3137255).into(),
720
Color::hsl(180.71191, 1.0, 0.3137255).into(),
721
],
722
vec![
723
Color::hsl(180.71191, 0.825, 0.0).into(),
724
Color::hsl(180.71191, 0.825, 0.5).into(),
725
Color::hsl(180.71191, 0.825, 1.0).into(),
726
],
727
vec![
728
Color::hsl(0.0 + 0.0001, 1.0, 0.5).into(),
729
Color::hsl(180.0, 1.0, 0.5).into(),
730
Color::hsl(360.0 - 0.0001, 1.0, 0.5).into(),
731
],
732
vec![
733
Color::WHITE.into(),
734
RED.into(),
735
LIME.into(),
736
BLUE.into(),
737
Color::BLACK.into(),
738
],
739
] {
740
for color_space in [
741
InterpolationColorSpace::LinearRgba,
742
InterpolationColorSpace::Srgba,
743
InterpolationColorSpace::Oklaba,
744
InterpolationColorSpace::Oklcha,
745
InterpolationColorSpace::OklchaLong,
746
InterpolationColorSpace::Hsla,
747
InterpolationColorSpace::HslaLong,
748
InterpolationColorSpace::Hsva,
749
InterpolationColorSpace::HsvaLong,
750
] {
751
let row = i % 18 + 1;
752
let column = i / 18 + 1;
753
i += 1;
754
755
commands.spawn((
756
Node {
757
grid_row: GridPlacement::start(row as i16 + 1),
758
grid_column: GridPlacement::start(column as i16 + 1),
759
justify_content: JustifyContent::SpaceEvenly,
760
..Default::default()
761
},
762
children![(
763
Node {
764
height: bevy::ui::px(30),
765
width: bevy::ui::px(300),
766
justify_content: JustifyContent::Center,
767
..Default::default()
768
},
769
BackgroundGradient::from(LinearGradient {
770
color_space,
771
angle: LinearGradient::TO_RIGHT,
772
stops: stops.clone(),
773
}),
774
children![
775
Node {
776
position_type: PositionType::Absolute,
777
..default()
778
},
779
TextFont::from_font_size(10.),
780
bevy::ui::widget::Text(format!("{color_space:?}")),
781
]
782
)],
783
));
784
}
785
}
786
});
787
});
788
}
789
}
790
791
mod radial_gradient {
792
use bevy::color::palettes::css::RED;
793
use bevy::color::palettes::tailwind::GRAY_700;
794
use bevy::prelude::*;
795
use bevy::ui::ColorStop;
796
797
const CELL_SIZE: f32 = 80.;
798
const GAP: f32 = 10.;
799
800
pub fn setup(mut commands: Commands) {
801
let color_stops = vec![
802
ColorStop::new(Color::BLACK, px(5)),
803
ColorStop::new(Color::WHITE, px(5)),
804
ColorStop::new(Color::WHITE, percent(100)),
805
ColorStop::auto(RED),
806
];
807
808
commands.spawn((Camera2d, DespawnOnExit(super::Scene::RadialGradient)));
809
commands
810
.spawn((
811
Node {
812
width: percent(100),
813
height: percent(100),
814
display: Display::Grid,
815
align_items: AlignItems::Start,
816
grid_template_columns: vec![RepeatedGridTrack::px(
817
GridTrackRepetition::AutoFill,
818
CELL_SIZE,
819
)],
820
grid_auto_flow: GridAutoFlow::Row,
821
row_gap: px(GAP),
822
column_gap: px(GAP),
823
padding: UiRect::all(px(GAP)),
824
..default()
825
},
826
DespawnOnExit(super::Scene::RadialGradient),
827
))
828
.with_children(|commands| {
829
for (shape, shape_label) in [
830
(RadialGradientShape::ClosestSide, "ClosestSide"),
831
(RadialGradientShape::FarthestSide, "FarthestSide"),
832
(RadialGradientShape::Circle(percent(55)), "Circle(55%)"),
833
(RadialGradientShape::FarthestCorner, "FarthestCorner"),
834
] {
835
for (position, position_label) in [
836
(UiPosition::TOP_LEFT, "TOP_LEFT"),
837
(UiPosition::LEFT, "LEFT"),
838
(UiPosition::BOTTOM_LEFT, "BOTTOM_LEFT"),
839
(UiPosition::TOP, "TOP"),
840
(UiPosition::CENTER, "CENTER"),
841
(UiPosition::BOTTOM, "BOTTOM"),
842
(UiPosition::TOP_RIGHT, "TOP_RIGHT"),
843
(UiPosition::RIGHT, "RIGHT"),
844
(UiPosition::BOTTOM_RIGHT, "BOTTOM_RIGHT"),
845
] {
846
for (w, h) in [(CELL_SIZE, CELL_SIZE), (CELL_SIZE, CELL_SIZE / 2.)] {
847
commands
848
.spawn((
849
BackgroundColor(GRAY_700.into()),
850
Node {
851
display: Display::Grid,
852
width: px(CELL_SIZE),
853
..Default::default()
854
},
855
))
856
.with_children(|commands| {
857
commands.spawn((
858
Node {
859
margin: UiRect::all(px(2)),
860
..default()
861
},
862
Text(format!("{shape_label}\n{position_label}")),
863
TextFont::from_font_size(9.),
864
));
865
commands.spawn((
866
Node {
867
width: px(w),
868
height: px(h),
869
..default()
870
},
871
BackgroundGradient::from(RadialGradient {
872
stops: color_stops.clone(),
873
position,
874
shape,
875
..default()
876
}),
877
));
878
});
879
}
880
}
881
}
882
});
883
}
884
}
885
886