1mod helpers;
6
7use bevy::prelude::*;
8use helpers::Next;
9
10fn 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)]
35enum 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
50impl 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
68fn 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
79mod 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
91mod 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
215mod 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 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 (
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 (
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 (Node::DEFAULT, BackgroundColor(BLACK.into())),
270 ],
271 ));
272 }
273}
274
275mod 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 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
368mod 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
451mod 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
493mod 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
557mod 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
621mod 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
664mod 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
791mod 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}