button/
button.rs

1//! This example illustrates how to create a button that changes color and text based on its
2//! interaction state.
3
4use bevy::{color::palettes::basic::*, input_focus::InputFocus, prelude::*};
5
6fn main() {
7    App::new()
8        .add_plugins(DefaultPlugins)
9        // `InputFocus` must be set for accessibility to recognize the button.
10        .init_resource::<InputFocus>()
11        .add_systems(Startup, setup)
12        .add_systems(Update, button_system)
13        .run();
14}
15
16const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
17const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
18const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
19
20fn button_system(
21    mut input_focus: ResMut<InputFocus>,
22    mut interaction_query: Query<
23        (
24            Entity,
25            &Interaction,
26            &mut BackgroundColor,
27            &mut BorderColor,
28            &mut Button,
29            &Children,
30        ),
31        Changed<Interaction>,
32    >,
33    mut text_query: Query<&mut Text>,
34) {
35    for (entity, interaction, mut color, mut border_color, mut button, children) in
36        &mut interaction_query
37    {
38        let mut text = text_query.get_mut(children[0]).unwrap();
39
40        match *interaction {
41            Interaction::Pressed => {
42                input_focus.set(entity);
43                **text = "Press".to_string();
44                *color = PRESSED_BUTTON.into();
45                *border_color = BorderColor::all(RED);
46
47                // The accessibility system's only update the button's state when the `Button` component is marked as changed.
48                button.set_changed();
49            }
50            Interaction::Hovered => {
51                input_focus.set(entity);
52                **text = "Hover".to_string();
53                *color = HOVERED_BUTTON.into();
54                *border_color = BorderColor::all(Color::WHITE);
55                button.set_changed();
56            }
57            Interaction::None => {
58                input_focus.clear();
59                **text = "Button".to_string();
60                *color = NORMAL_BUTTON.into();
61                *border_color = BorderColor::all(Color::BLACK);
62            }
63        }
64    }
65}
66
67fn setup(mut commands: Commands, assets: Res<AssetServer>) {
68    // ui camera
69    commands.spawn(Camera2d);
70    commands.spawn(button(&assets));
71}
72
73fn button(asset_server: &AssetServer) -> impl Bundle {
74    (
75        Node {
76            width: percent(100),
77            height: percent(100),
78            align_items: AlignItems::Center,
79            justify_content: JustifyContent::Center,
80            ..default()
81        },
82        children![(
83            Button,
84            Node {
85                width: px(150),
86                height: px(65),
87                border: UiRect::all(px(5)),
88                // horizontally center child text
89                justify_content: JustifyContent::Center,
90                // vertically center child text
91                align_items: AlignItems::Center,
92                ..default()
93            },
94            BorderColor::all(Color::WHITE),
95            BorderRadius::MAX,
96            BackgroundColor(Color::BLACK),
97            children![(
98                Text::new("Button"),
99                TextFont {
100                    font: asset_server.load("fonts/FiraSans-Bold.ttf"),
101                    font_size: 33.0,
102                    ..default()
103                },
104                TextColor(Color::srgb(0.9, 0.9, 0.9)),
105                TextShadow::default(),
106            )]
107        )],
108    )
109}