ui_texture_slice/
ui_texture_slice.rs

1//! This example illustrates how to create buttons with their textures sliced
2//! and kept in proportion instead of being stretched by the button dimensions
3
4use bevy::{
5    color::palettes::css::{GOLD, ORANGE},
6    prelude::*,
7    ui::widget::NodeImageMode,
8    winit::WinitSettings,
9};
10
11fn main() {
12    App::new()
13        .add_plugins(DefaultPlugins)
14        // Only run the app when there is user input. This will significantly reduce CPU/GPU use.
15        .insert_resource(WinitSettings::desktop_app())
16        .add_systems(Startup, setup)
17        .add_systems(Update, button_system)
18        .run();
19}
20
21fn button_system(
22    mut interaction_query: Query<
23        (&Interaction, &Children, &mut ImageNode),
24        (Changed<Interaction>, With<Button>),
25    >,
26    mut text_query: Query<&mut Text>,
27) {
28    for (interaction, children, mut image) in &mut interaction_query {
29        let mut text = text_query.get_mut(children[0]).unwrap();
30        match *interaction {
31            Interaction::Pressed => {
32                **text = "Press".to_string();
33                image.color = GOLD.into();
34            }
35            Interaction::Hovered => {
36                **text = "Hover".to_string();
37                image.color = ORANGE.into();
38            }
39            Interaction::None => {
40                **text = "Button".to_string();
41                image.color = Color::WHITE;
42            }
43        }
44    }
45}
46
47fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
48    let image = asset_server.load("textures/fantasy_ui_borders/panel-border-010.png");
49
50    let slicer = TextureSlicer {
51        border: BorderRect::all(22.0),
52        center_scale_mode: SliceScaleMode::Stretch,
53        sides_scale_mode: SliceScaleMode::Stretch,
54        max_corner_scale: 1.0,
55    };
56    // ui camera
57    commands.spawn(Camera2d);
58    commands
59        .spawn(Node {
60            width: Val::Percent(100.0),
61            height: Val::Percent(100.0),
62            align_items: AlignItems::Center,
63            justify_content: JustifyContent::Center,
64            ..default()
65        })
66        .with_children(|parent| {
67            for [w, h] in [[150.0, 150.0], [300.0, 150.0], [150.0, 300.0]] {
68                parent
69                    .spawn((
70                        Button,
71                        ImageNode {
72                            image: image.clone(),
73                            image_mode: NodeImageMode::Sliced(slicer.clone()),
74                            ..default()
75                        },
76                        Node {
77                            width: Val::Px(w),
78                            height: Val::Px(h),
79                            // horizontally center child text
80                            justify_content: JustifyContent::Center,
81                            // vertically center child text
82                            align_items: AlignItems::Center,
83                            margin: UiRect::all(Val::Px(20.0)),
84                            ..default()
85                        },
86                    ))
87                    .with_child((
88                        Text::new("Button"),
89                        TextFont {
90                            font: asset_server.load("fonts/FiraSans-Bold.ttf"),
91                            font_size: 33.0,
92                            ..default()
93                        },
94                        TextColor(Color::srgb(0.9, 0.9, 0.9)),
95                    ));
96            }
97        });
98}