vmin

Function vmin 

Source
pub fn vmin<T>(value: T) -> Val
where T: ValNum,
Expand description

Returns a Val::VMin representing a percentage of the viewport’s smaller dimension.

Examples found in repository?
examples/stress_tests/many_buttons.rs (line 166)
152fn setup_flex(mut commands: Commands, asset_server: Res<AssetServer>, args: Res<Args>) {
153    let images = if 0 < args.image_freq {
154        Some(vec![
155            asset_server.load("branding/icon.png"),
156            asset_server.load("textures/Game Icons/wrench.png"),
157        ])
158    } else {
159        None
160    };
161
162    let buttons_f = args.buttons as f32;
163    let border = if args.no_borders {
164        UiRect::ZERO
165    } else {
166        UiRect::all(vmin(0.05 * 90. / buttons_f))
167    };
168
169    let as_rainbow = |i: usize| Color::hsl((i as f32 / buttons_f) * 360.0, 0.9, 0.8);
170    commands
171        .spawn(Node {
172            display: if args.display_none {
173                Display::None
174            } else {
175                Display::Flex
176            },
177            flex_direction: FlexDirection::Column,
178            justify_content: JustifyContent::Center,
179            align_items: AlignItems::Center,
180            width: percent(100),
181            height: percent(100),
182            ..default()
183        })
184        .with_children(|commands| {
185            for column in 0..args.buttons {
186                commands.spawn(Node::default()).with_children(|commands| {
187                    for row in 0..args.buttons {
188                        let color = as_rainbow(row % column.max(1));
189                        let border_color = Color::WHITE.with_alpha(0.5).into();
190                        spawn_button(
191                            commands,
192                            color,
193                            buttons_f,
194                            column,
195                            row,
196                            args.text,
197                            border,
198                            border_color,
199                            images.as_ref().map(|images| {
200                                images[((column + row) / args.image_freq) % images.len()].clone()
201                            }),
202                        );
203                    }
204                });
205            }
206        });
207}
208
209fn setup_grid(mut commands: Commands, asset_server: Res<AssetServer>, args: Res<Args>) {
210    let images = if 0 < args.image_freq {
211        Some(vec![
212            asset_server.load("branding/icon.png"),
213            asset_server.load("textures/Game Icons/wrench.png"),
214        ])
215    } else {
216        None
217    };
218
219    let buttons_f = args.buttons as f32;
220    let border = if args.no_borders {
221        UiRect::ZERO
222    } else {
223        UiRect::all(vmin(0.05 * 90. / buttons_f))
224    };
225
226    let as_rainbow = |i: usize| Color::hsl((i as f32 / buttons_f) * 360.0, 0.9, 0.8);
227    commands
228        .spawn(Node {
229            display: if args.display_none {
230                Display::None
231            } else {
232                Display::Grid
233            },
234            width: percent(100),
235            height: percent(100),
236            grid_template_columns: RepeatedGridTrack::flex(args.buttons as u16, 1.0),
237            grid_template_rows: RepeatedGridTrack::flex(args.buttons as u16, 1.0),
238            ..default()
239        })
240        .with_children(|commands| {
241            for column in 0..args.buttons {
242                for row in 0..args.buttons {
243                    let color = as_rainbow(row % column.max(1));
244                    let border_color = Color::WHITE.with_alpha(0.5).into();
245                    spawn_button(
246                        commands,
247                        color,
248                        buttons_f,
249                        column,
250                        row,
251                        args.text,
252                        border,
253                        border_color,
254                        images.as_ref().map(|images| {
255                            images[((column + row) / args.image_freq) % images.len()].clone()
256                        }),
257                    );
258                }
259            }
260        });
261}
262
263fn spawn_button(
264    commands: &mut ChildSpawnerCommands,
265    background_color: Color,
266    buttons: f32,
267    column: usize,
268    row: usize,
269    spawn_text: bool,
270    border: UiRect,
271    border_color: BorderColor,
272    image: Option<Handle<Image>>,
273) {
274    let width = vw(90.0 / buttons);
275    let height = vh(90.0 / buttons);
276    let margin = UiRect::axes(width * 0.05, height * 0.05);
277    let mut builder = commands.spawn((
278        Button,
279        Node {
280            width,
281            height,
282            margin,
283            align_items: AlignItems::Center,
284            justify_content: JustifyContent::Center,
285            border,
286            ..default()
287        },
288        BackgroundColor(background_color),
289        border_color,
290        IdleColor(background_color),
291    ));
292
293    if let Some(image) = image {
294        builder.insert(ImageNode::new(image));
295    }
296
297    if spawn_text {
298        builder.with_children(|parent| {
299            // These labels are split to stress test multi-span text
300            parent
301                .spawn((
302                    Text(format!("{column}, ")),
303                    TextFont {
304                        font_size: FONT_SIZE,
305                        ..default()
306                    },
307                    TextColor(Color::srgb(0.5, 0.2, 0.2)),
308                ))
309                .with_child((
310                    TextSpan(format!("{row}")),
311                    TextFont {
312                        font_size: FONT_SIZE,
313                        ..default()
314                    },
315                    TextColor(Color::srgb(0.2, 0.2, 0.5)),
316                ));
317        });
318    }
319}
320
321fn despawn_ui(mut commands: Commands, root_node: Single<Entity, (With<Node>, Without<ChildOf>)>) {
322    commands.entity(*root_node).despawn();
323}
324
325fn setup_many_cameras(mut commands: Commands, asset_server: Res<AssetServer>, args: Res<Args>) {
326    let images = if 0 < args.image_freq {
327        Some(vec![
328            asset_server.load("branding/icon.png"),
329            asset_server.load("textures/Game Icons/wrench.png"),
330        ])
331    } else {
332        None
333    };
334
335    let buttons_f = args.buttons as f32;
336    let border = if args.no_borders {
337        UiRect::ZERO
338    } else {
339        UiRect::all(vmin(0.05 * 90. / buttons_f))
340    };
341
342    let as_rainbow = |i: usize| Color::hsl((i as f32 / buttons_f) * 360.0, 0.9, 0.8);
343    for column in 0..args.buttons {
344        for row in 0..args.buttons {
345            let color = as_rainbow(row % column.max(1));
346            let border_color = Color::WHITE.with_alpha(0.5).into();
347            let camera = commands
348                .spawn((
349                    Camera2d,
350                    Camera {
351                        order: (column * args.buttons + row) as isize + 1,
352                        ..Default::default()
353                    },
354                ))
355                .id();
356            commands
357                .spawn((
358                    Node {
359                        display: if args.display_none {
360                            Display::None
361                        } else {
362                            Display::Flex
363                        },
364                        flex_direction: FlexDirection::Column,
365                        justify_content: JustifyContent::Center,
366                        align_items: AlignItems::Center,
367                        width: percent(100),
368                        height: percent(100),
369                        ..default()
370                    },
371                    UiTargetCamera(camera),
372                ))
373                .with_children(|commands| {
374                    commands
375                        .spawn(Node {
376                            position_type: PositionType::Absolute,
377                            top: vh(column as f32 * 100. / buttons_f),
378                            left: vw(row as f32 * 100. / buttons_f),
379                            ..Default::default()
380                        })
381                        .with_children(|commands| {
382                            spawn_button(
383                                commands,
384                                color,
385                                buttons_f,
386                                column,
387                                row,
388                                args.text,
389                                border,
390                                border_color,
391                                images.as_ref().map(|images| {
392                                    images[((column + row) / args.image_freq) % images.len()]
393                                        .clone()
394                                }),
395                            );
396                        });
397                });
398        }
399    }
400}
More examples
Hide additional examples
examples/ui/viewport_debug.rs (line 86)
68fn spawn_with_viewport_coords(commands: &mut Commands) {
69    commands
70        .spawn((
71            Node {
72                width: vw(100),
73                height: vh(100),
74                border: UiRect::axes(vw(5), vh(5)),
75                flex_wrap: FlexWrap::Wrap,
76                ..default()
77            },
78            BorderColor::all(PALETTE[0]),
79            Coords::Viewport,
80        ))
81        .with_children(|builder| {
82            builder.spawn((
83                Node {
84                    width: vw(30),
85                    height: vh(30),
86                    border: UiRect::all(vmin(5)),
87                    ..default()
88                },
89                BackgroundColor(PALETTE[2].into()),
90                BorderColor::all(PALETTE[9]),
91            ));
92
93            builder.spawn((
94                Node {
95                    width: vw(60),
96                    height: vh(30),
97                    ..default()
98                },
99                BackgroundColor(PALETTE[3].into()),
100            ));
101
102            builder.spawn((
103                Node {
104                    width: vw(45),
105                    height: vh(30),
106                    border: UiRect::left(vmax(45. / 2.)),
107                    ..default()
108                },
109                BackgroundColor(PALETTE[4].into()),
110                BorderColor::all(PALETTE[8]),
111            ));
112
113            builder.spawn((
114                Node {
115                    width: vw(45),
116                    height: vh(30),
117                    border: UiRect::right(vmax(45. / 2.)),
118                    ..default()
119                },
120                BackgroundColor(PALETTE[5].into()),
121                BorderColor::all(PALETTE[8]),
122            ));
123
124            builder.spawn((
125                Node {
126                    width: vw(60),
127                    height: vh(30),
128                    ..default()
129                },
130                BackgroundColor(PALETTE[6].into()),
131            ));
132
133            builder.spawn((
134                Node {
135                    width: vw(30),
136                    height: vh(30),
137                    border: UiRect::all(vmin(5)),
138                    ..default()
139                },
140                BackgroundColor(PALETTE[7].into()),
141                BorderColor::all(PALETTE[9]),
142            ));
143        });
144}
examples/testbed/full_ui.rs (line 353)
31fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
32    // Camera
33    commands.spawn((Camera2d, IsDefaultUiCamera, BoxShadowSamples(6)));
34
35    // root node
36    commands
37        .spawn(Node {
38            width: percent(100),
39            height: percent(100),
40            justify_content: JustifyContent::SpaceBetween,
41            ..default()
42        })
43        .insert(Pickable::IGNORE)
44        .with_children(|parent| {
45            // left vertical fill (border)
46            parent
47                .spawn((
48                    Node {
49                        width: px(200),
50                        border: UiRect::all(px(2)),
51                        ..default()
52                    },
53                    BackgroundColor(Color::srgb(0.65, 0.65, 0.65)),
54                ))
55                .with_children(|parent| {
56                    // left vertical fill (content)
57                    parent
58                        .spawn((
59                            Node {
60                                width: percent(100),
61                                flex_direction: FlexDirection::Column,
62                                padding: UiRect::all(px(5)),
63                                row_gap: px(5),
64                                ..default()
65                            },
66                            BackgroundColor(Color::srgb(0.15, 0.15, 0.15)),
67                            Visibility::Visible,
68                        ))
69                        .with_children(|parent| {
70                            // text
71                            parent.spawn((
72                                Text::new("Text Example"),
73                                TextFont {
74                                    font: asset_server.load("fonts/FiraSans-Bold.ttf"),
75                                    font_size: 25.0,
76                                    ..default()
77                                },
78                                // Because this is a distinct label widget and
79                                // not button/list item text, this is necessary
80                                // for accessibility to treat the text accordingly.
81                                Label,
82                            ));
83
84                            #[cfg(feature = "bevy_ui_debug")]
85                            {
86                                // Debug overlay text
87                                parent.spawn((
88                                    Text::new("Press Space to toggle debug outlines."),
89                                    TextFont {
90                                        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
91                                        ..default()
92                                    },
93                                    Label,
94                                ));
95
96                                parent.spawn((
97                                    Text::new("V: toggle UI root's visibility"),
98                                    TextFont {
99                                        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
100                                        font_size: 12.,
101                                        ..default()
102                                    },
103                                    Label,
104                                ));
105
106                                parent.spawn((
107                                    Text::new("S: toggle outlines for hidden nodes"),
108                                    TextFont {
109                                        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
110                                        font_size: 12.,
111                                        ..default()
112                                    },
113                                    Label,
114                                ));
115                                parent.spawn((
116                                    Text::new("C: toggle outlines for clipped nodes"),
117                                    TextFont {
118                                        font: asset_server.load("fonts/FiraSans-Bold.ttf"),
119                                        font_size: 12.,
120                                        ..default()
121                                    },
122                                    Label,
123                                ));
124                            }
125                            #[cfg(not(feature = "bevy_ui_debug"))]
126                            parent.spawn((
127                                Text::new("Try enabling feature \"bevy_ui_debug\"."),
128                                TextFont {
129                                    font: asset_server.load("fonts/FiraSans-Bold.ttf"),
130                                    ..default()
131                                },
132                                Label,
133                            ));
134                        });
135                });
136            // right vertical fill
137            parent
138                .spawn(Node {
139                    flex_direction: FlexDirection::Column,
140                    justify_content: JustifyContent::Center,
141                    align_items: AlignItems::Center,
142                    width: px(200),
143                    ..default()
144                })
145                .with_children(|parent| {
146                    // Title
147                    parent.spawn((
148                        Text::new("Scrolling list"),
149                        TextFont {
150                            font: asset_server.load("fonts/FiraSans-Bold.ttf"),
151                            font_size: 21.,
152                            ..default()
153                        },
154                        Label,
155                    ));
156                    // Scrolling list
157                    parent
158                        .spawn((
159                            Node {
160                                flex_direction: FlexDirection::Column,
161                                align_self: AlignSelf::Stretch,
162                                height: percent(50),
163                                overflow: Overflow::scroll_y(),
164                                ..default()
165                            },
166                            BackgroundColor(Color::srgb(0.10, 0.10, 0.10)),
167                        ))
168                        .with_children(|parent| {
169                            parent
170                                .spawn((
171                                    Node {
172                                        flex_direction: FlexDirection::Column,
173                                        ..Default::default()
174                                    },
175                                    BackgroundGradient::from(LinearGradient::to_bottom(vec![
176                                        ColorStop::auto(NAVY),
177                                        ColorStop::auto(Color::BLACK),
178                                    ])),
179                                    Pickable {
180                                        should_block_lower: false,
181                                        ..Default::default()
182                                    },
183                                ))
184                                .with_children(|parent| {
185                                    // List items
186                                    for i in 0..25 {
187                                        parent
188                                            .spawn((
189                                                Text(format!("Item {i}")),
190                                                TextFont {
191                                                    font: asset_server
192                                                        .load("fonts/FiraSans-Bold.ttf"),
193                                                    ..default()
194                                                },
195                                                Label,
196                                                AccessibilityNode(Accessible::new(Role::ListItem)),
197                                            ))
198                                            .insert(Pickable {
199                                                should_block_lower: false,
200                                                ..default()
201                                            });
202                                    }
203                                });
204                        });
205                });
206
207            parent
208                .spawn(Node {
209                    left: px(210),
210                    bottom: px(10),
211                    position_type: PositionType::Absolute,
212                    ..default()
213                })
214                .with_children(|parent| {
215                    parent
216                        .spawn((
217                            Node {
218                                width: px(200),
219                                height: px(200),
220                                border: UiRect::all(px(20)),
221                                flex_direction: FlexDirection::Column,
222                                justify_content: JustifyContent::Center,
223                                ..default()
224                            },
225                            BorderColor::all(LIME),
226                            BackgroundColor(Color::srgb(0.8, 0.8, 1.)),
227                        ))
228                        .with_children(|parent| {
229                            parent.spawn((
230                                ImageNode::new(asset_server.load("branding/bevy_logo_light.png")),
231                                // Uses the transform to rotate the logo image by 45 degrees
232                                Node {
233                                    ..Default::default()
234                                },
235                                UiTransform {
236                                    rotation: Rot2::radians(0.25 * PI),
237                                    ..Default::default()
238                                },
239                                BorderRadius::all(px(10)),
240                                Outline {
241                                    width: px(2),
242                                    offset: px(4),
243                                    color: DARK_GRAY.into(),
244                                },
245                            ));
246                        });
247                });
248
249            let shadow_style = ShadowStyle {
250                color: Color::BLACK.with_alpha(0.5),
251                blur_radius: px(2),
252                x_offset: px(10),
253                y_offset: px(10),
254                ..default()
255            };
256
257            // render order test: reddest in the back, whitest in the front (flex center)
258            parent
259                .spawn(Node {
260                    width: percent(100),
261                    height: percent(100),
262                    position_type: PositionType::Absolute,
263                    align_items: AlignItems::Center,
264                    justify_content: JustifyContent::Center,
265                    ..default()
266                })
267                .insert(Pickable::IGNORE)
268                .with_children(|parent| {
269                    parent
270                        .spawn((
271                            Node {
272                                width: px(100),
273                                height: px(100),
274                                ..default()
275                            },
276                            BackgroundColor(Color::srgb(1.0, 0.0, 0.)),
277                            BoxShadow::from(shadow_style),
278                        ))
279                        .with_children(|parent| {
280                            parent.spawn((
281                                Node {
282                                    // Take the size of the parent node.
283                                    width: percent(100),
284                                    height: percent(100),
285                                    position_type: PositionType::Absolute,
286                                    left: px(20),
287                                    bottom: px(20),
288                                    ..default()
289                                },
290                                BackgroundColor(Color::srgb(1.0, 0.3, 0.3)),
291                                BoxShadow::from(shadow_style),
292                            ));
293                            parent.spawn((
294                                Node {
295                                    width: percent(100),
296                                    height: percent(100),
297                                    position_type: PositionType::Absolute,
298                                    left: px(40),
299                                    bottom: px(40),
300                                    ..default()
301                                },
302                                BackgroundColor(Color::srgb(1.0, 0.5, 0.5)),
303                                BoxShadow::from(shadow_style),
304                            ));
305                            parent.spawn((
306                                Node {
307                                    width: percent(100),
308                                    height: percent(100),
309                                    position_type: PositionType::Absolute,
310                                    left: px(60),
311                                    bottom: px(60),
312                                    ..default()
313                                },
314                                BackgroundColor(Color::srgb(0.0, 0.7, 0.7)),
315                                BoxShadow::from(shadow_style),
316                            ));
317                            // alpha test
318                            parent.spawn((
319                                Node {
320                                    width: percent(100),
321                                    height: percent(100),
322                                    position_type: PositionType::Absolute,
323                                    left: px(80),
324                                    bottom: px(80),
325                                    ..default()
326                                },
327                                BackgroundColor(Color::srgba(1.0, 0.9, 0.9, 0.4)),
328                                BoxShadow::from(ShadowStyle {
329                                    color: Color::BLACK.with_alpha(0.3),
330                                    ..shadow_style
331                                }),
332                            ));
333                        });
334                });
335            // bevy logo (flex center)
336            parent
337                .spawn(Node {
338                    width: percent(100),
339                    position_type: PositionType::Absolute,
340                    justify_content: JustifyContent::Center,
341                    align_items: AlignItems::FlexStart,
342                    ..default()
343                })
344                .with_children(|parent| {
345                    // bevy logo (image)
346                    parent
347                        .spawn((
348                            ImageNode::new(asset_server.load("branding/bevy_logo_dark_big.png"))
349                                .with_mode(NodeImageMode::Stretch),
350                            Node {
351                                width: px(500),
352                                height: px(125),
353                                margin: UiRect::top(vmin(5)),
354                                ..default()
355                            },
356                        ))
357                        .with_children(|parent| {
358                            // alt text
359                            // This UI node takes up no space in the layout and the `Text` component is used by the accessibility module
360                            // and is not rendered.
361                            parent.spawn((
362                                Node {
363                                    display: Display::None,
364                                    ..default()
365                                },
366                                Text::new("Bevy logo"),
367                            ));
368                        });
369                });
370
371            // four bevy icons demonstrating image flipping
372            parent
373                .spawn(Node {
374                    width: percent(100),
375                    height: percent(100),
376                    position_type: PositionType::Absolute,
377                    justify_content: JustifyContent::Center,
378                    align_items: AlignItems::FlexEnd,
379                    column_gap: px(10),
380                    padding: UiRect::all(px(10)),
381                    ..default()
382                })
383                .insert(Pickable::IGNORE)
384                .with_children(|parent| {
385                    for (flip_x, flip_y) in
386                        [(false, false), (false, true), (true, true), (true, false)]
387                    {
388                        parent.spawn((
389                            ImageNode {
390                                image: asset_server.load("branding/icon.png"),
391                                flip_x,
392                                flip_y,
393                                ..default()
394                            },
395                            Node {
396                                // The height will be chosen automatically to preserve the image's aspect ratio
397                                width: px(75),
398                                ..default()
399                            },
400                        ));
401                    }
402                });
403        });
404}