Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ui/gradients.rs
6595 views
1
//! Simple example demonstrating linear gradients.
2
3
use bevy::color::palettes::css::BLUE;
4
use bevy::color::palettes::css::GREEN;
5
use bevy::color::palettes::css::INDIGO;
6
use bevy::color::palettes::css::LIME;
7
use bevy::color::palettes::css::ORANGE;
8
use bevy::color::palettes::css::RED;
9
use bevy::color::palettes::css::VIOLET;
10
use bevy::color::palettes::css::YELLOW;
11
use bevy::prelude::*;
12
use bevy::ui::ColorStop;
13
use std::f32::consts::TAU;
14
15
#[derive(Component)]
16
struct CurrentColorSpaceLabel;
17
18
fn main() {
19
App::new()
20
.add_plugins(DefaultPlugins)
21
.add_systems(Startup, setup)
22
.add_systems(Update, update)
23
.run();
24
}
25
26
fn setup(mut commands: Commands) {
27
commands.spawn(Camera2d);
28
29
commands
30
.spawn(Node {
31
flex_direction: FlexDirection::Column,
32
row_gap: px(20),
33
margin: UiRect::all(px(20)),
34
..Default::default()
35
})
36
.with_children(|commands| {
37
for (b, stops) in [
38
(
39
4.,
40
vec![
41
ColorStop::new(Color::WHITE, percent(15)),
42
ColorStop::new(Color::BLACK, percent(85)),
43
],
44
),
45
(4., vec![RED.into(), BLUE.into(), LIME.into()]),
46
(
47
0.,
48
vec![
49
RED.into(),
50
ColorStop::new(RED, percent(100. / 7.)),
51
ColorStop::new(ORANGE, percent(100. / 7.)),
52
ColorStop::new(ORANGE, percent(200. / 7.)),
53
ColorStop::new(YELLOW, percent(200. / 7.)),
54
ColorStop::new(YELLOW, percent(300. / 7.)),
55
ColorStop::new(GREEN, percent(300. / 7.)),
56
ColorStop::new(GREEN, percent(400. / 7.)),
57
ColorStop::new(BLUE, percent(400. / 7.)),
58
ColorStop::new(BLUE, percent(500. / 7.)),
59
ColorStop::new(INDIGO, percent(500. / 7.)),
60
ColorStop::new(INDIGO, percent(600. / 7.)),
61
ColorStop::new(VIOLET, percent(600. / 7.)),
62
VIOLET.into(),
63
],
64
),
65
] {
66
commands.spawn(Node::default()).with_children(|commands| {
67
commands
68
.spawn(Node {
69
flex_direction: FlexDirection::Column,
70
row_gap: px(5),
71
..Default::default()
72
})
73
.with_children(|commands| {
74
for (w, h) in [(70., 70.), (35., 70.), (70., 35.)] {
75
commands
76
.spawn(Node {
77
column_gap: px(10),
78
..Default::default()
79
})
80
.with_children(|commands| {
81
for angle in (0..8).map(|i| i as f32 * TAU / 8.) {
82
commands.spawn((
83
Node {
84
width: px(w),
85
height: px(h),
86
border: UiRect::all(px(b)),
87
..default()
88
},
89
BorderRadius::all(px(20)),
90
BackgroundGradient::from(LinearGradient {
91
angle,
92
stops: stops.clone(),
93
..default()
94
}),
95
BorderGradient::from(LinearGradient {
96
angle: 3. * TAU / 8.,
97
stops: vec![
98
YELLOW.into(),
99
Color::WHITE.into(),
100
ORANGE.into(),
101
],
102
..default()
103
}),
104
));
105
}
106
});
107
}
108
});
109
110
commands.spawn(Node::default()).with_children(|commands| {
111
commands.spawn((
112
Node {
113
aspect_ratio: Some(1.),
114
height: percent(100),
115
border: UiRect::all(px(b)),
116
margin: UiRect::left(px(20)),
117
..default()
118
},
119
BorderRadius::all(px(20)),
120
BackgroundGradient::from(LinearGradient {
121
angle: 0.,
122
stops: stops.clone(),
123
..default()
124
}),
125
BorderGradient::from(LinearGradient {
126
angle: 3. * TAU / 8.,
127
stops: vec![YELLOW.into(), Color::WHITE.into(), ORANGE.into()],
128
..default()
129
}),
130
AnimateMarker,
131
));
132
133
commands.spawn((
134
Node {
135
aspect_ratio: Some(1.),
136
height: percent(100),
137
border: UiRect::all(px(b)),
138
margin: UiRect::left(px(20)),
139
..default()
140
},
141
BorderRadius::all(px(20)),
142
BackgroundGradient::from(RadialGradient {
143
stops: stops.clone(),
144
shape: RadialGradientShape::ClosestSide,
145
position: UiPosition::CENTER,
146
..default()
147
}),
148
BorderGradient::from(LinearGradient {
149
angle: 3. * TAU / 8.,
150
stops: vec![YELLOW.into(), Color::WHITE.into(), ORANGE.into()],
151
..default()
152
}),
153
AnimateMarker,
154
));
155
commands.spawn((
156
Node {
157
aspect_ratio: Some(1.),
158
height: percent(100),
159
border: UiRect::all(px(b)),
160
margin: UiRect::left(px(20)),
161
..default()
162
},
163
BorderRadius::all(px(20)),
164
BackgroundGradient::from(ConicGradient {
165
start: 0.,
166
stops: stops
167
.iter()
168
.map(|stop| AngularColorStop::auto(stop.color))
169
.collect(),
170
position: UiPosition::CENTER,
171
..default()
172
}),
173
BorderGradient::from(LinearGradient {
174
angle: 3. * TAU / 8.,
175
stops: vec![YELLOW.into(), Color::WHITE.into(), ORANGE.into()],
176
..default()
177
}),
178
AnimateMarker,
179
));
180
});
181
});
182
}
183
184
let button = commands.spawn((
185
Button,
186
Node {
187
border: UiRect::all(px(2)),
188
padding: UiRect::axes(px(8), px(4)),
189
// horizontally center child text
190
justify_content: JustifyContent::Center,
191
// vertically center child text
192
align_items: AlignItems::Center,
193
..default()
194
},
195
BorderColor::all(Color::WHITE),
196
BorderRadius::MAX,
197
BackgroundColor(Color::BLACK),
198
children![(
199
Text::new("next color space"),
200
TextColor(Color::srgb(0.9, 0.9, 0.9)),
201
TextShadow::default(),
202
)]
203
)).observe(
204
|_event: On<Pointer<Over>>, mut border_query: Query<&mut BorderColor, With<Button>>| {
205
*border_query.single_mut().unwrap() = BorderColor::all(RED);
206
207
208
})
209
.observe(
210
|_event: On<Pointer<Out>>, mut border_query: Query<&mut BorderColor, With<Button>>| {
211
*border_query.single_mut().unwrap() = BorderColor::all(Color::WHITE);
212
})
213
.observe(
214
|_event: On<Pointer<Click>>,
215
mut gradients_query: Query<&mut BackgroundGradient>,
216
mut label_query: Query<
217
&mut Text,
218
With<CurrentColorSpaceLabel>,
219
>| {
220
let mut current_space = InterpolationColorSpace::default();
221
for mut gradients in gradients_query.iter_mut() {
222
for gradient in gradients.0.iter_mut() {
223
let space = match gradient {
224
Gradient::Linear(linear_gradient) => {
225
&mut linear_gradient.color_space
226
}
227
Gradient::Radial(radial_gradient) => {
228
&mut radial_gradient.color_space
229
}
230
Gradient::Conic(conic_gradient) => {
231
&mut conic_gradient.color_space
232
}
233
};
234
*space = match *space {
235
InterpolationColorSpace::Oklaba => {
236
InterpolationColorSpace::Oklcha
237
}
238
InterpolationColorSpace::Oklcha => {
239
InterpolationColorSpace::OklchaLong
240
}
241
InterpolationColorSpace::OklchaLong => {
242
InterpolationColorSpace::Srgba
243
}
244
InterpolationColorSpace::Srgba => {
245
InterpolationColorSpace::LinearRgba
246
}
247
InterpolationColorSpace::LinearRgba => {
248
InterpolationColorSpace::Hsla
249
}
250
InterpolationColorSpace::Hsla => {
251
InterpolationColorSpace::HslaLong
252
}
253
InterpolationColorSpace::HslaLong => {
254
InterpolationColorSpace::Hsva
255
}
256
InterpolationColorSpace::Hsva => {
257
InterpolationColorSpace::HsvaLong
258
}
259
InterpolationColorSpace::HsvaLong => {
260
InterpolationColorSpace::Oklaba
261
}
262
};
263
current_space = *space;
264
}
265
}
266
for mut label in label_query.iter_mut() {
267
label.0 = format!("{current_space:?}");
268
}
269
}
270
).id();
271
272
commands.spawn(
273
Node {
274
flex_direction: FlexDirection::Column,
275
row_gap: px(10),
276
align_items: AlignItems::Center,
277
..Default::default()
278
}
279
).with_children(|commands| {
280
commands.spawn((Text::new(format!("{:?}", InterpolationColorSpace::default())), TextFont { font_size: 25., ..default() }, CurrentColorSpaceLabel));
281
282
})
283
.add_child(button);
284
});
285
}
286
287
#[derive(Component)]
288
struct AnimateMarker;
289
290
fn update(time: Res<Time>, mut query: Query<&mut BackgroundGradient, With<AnimateMarker>>) {
291
for mut gradients in query.iter_mut() {
292
for gradient in gradients.0.iter_mut() {
293
if let Gradient::Linear(LinearGradient { angle, .. }) = gradient {
294
*angle += 0.5 * time.delta_secs();
295
}
296
}
297
}
298
}
299
300