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