bevy/crates
Marco Meijer 66b5128b6f
Add rect field to UI image (#15095)
# Objective

Fixes #14424 

## Solution

Add a rect field to UiImage, and update the extraction of ui images and
slices.

## Testing

I tested all possible combinations of having a rect, using a texture
atlas, setting image scale mode to sliced and image scale mode to tiled.
See the showcase section.

---

## Showcase

<img width="1279" alt="Screenshot 2024-09-08 at 16 23 05"
src="https://github.com/user-attachments/assets/183e53eb-f27c-4c8e-9fd5-4678825db3b6">

<details>
  <summary>Click to view showcase</summary>

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
        .add_systems(Startup, create_ui)
        .run();
}

fn create_ui(
    mut commands: Commands,
    assets: Res<AssetServer>,
    mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
) {
    let texture = assets.load("textures/fantasy_ui_borders/numbered_slices.png");
    let layout = TextureAtlasLayout::from_grid(UVec2::splat(16), 3, 3, None, None);
    let texture_atlas_layout = texture_atlas_layouts.add(layout);

    commands.spawn(Camera2dBundle::default());

    let style = Style {
        width: Val::Px(96.),
        height: Val::Px(96.),
        ..default()
    };

    commands
        .spawn(NodeBundle { ..default() })
        .with_children(|parent| {
            // nothing
            parent.spawn(ImageBundle {
                image: UiImage::new(texture.clone()),
                style: style.clone(),
                ..default()
            });

            // with rect
            parent.spawn(ImageBundle {
                image: UiImage::new(texture.clone()).with_rect(Rect::new(0., 0., 16., 16.)),
                style: style.clone(),
                ..default()
            });

            // with rect and texture atlas
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()).with_rect(Rect::new(0., 0., 8., 8.)),
                    style: style.clone(),
                    ..default()
                },
                TextureAtlas {
                    layout: texture_atlas_layout.clone(),
                    index: 1,
                },
            ));

            // with texture atlas
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()),
                    style: style.clone(),
                    ..default()
                },
                TextureAtlas {
                    layout: texture_atlas_layout.clone(),
                    index: 2,
                },
            ));

            // with texture slicer
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()),
                    style: style.clone(),
                    ..default()
                },
                ImageScaleMode::Sliced(TextureSlicer {
                    border: BorderRect::square(16.),
                    center_scale_mode: SliceScaleMode::Stretch,
                    sides_scale_mode: SliceScaleMode::Stretch,
                    max_corner_scale: 1.,
                }),
            ));

            // with rect and texture slicer
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()).with_rect(Rect::new(0., 0., 16., 16.)),
                    style: style.clone(),
                    ..default()
                },
                ImageScaleMode::Sliced(TextureSlicer {
                    border: BorderRect::square(2.),
                    center_scale_mode: SliceScaleMode::Stretch,
                    sides_scale_mode: SliceScaleMode::Stretch,
                    max_corner_scale: 1.,
                }),
            ));

            // with rect, texture atlas and texture slicer
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()).with_rect(Rect::new(0., 0., 8., 8.)),
                    style: style.clone(),
                    ..default()
                },
                TextureAtlas {
                    layout: texture_atlas_layout.clone(),
                    index: 1,
                },
                ImageScaleMode::Sliced(TextureSlicer {
                    border: BorderRect::square(1.),
                    center_scale_mode: SliceScaleMode::Stretch,
                    sides_scale_mode: SliceScaleMode::Stretch,
                    max_corner_scale: 1.,
                }),
            ));

            // with texture atlas and texture slicer
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()),
                    style: style.clone(),
                    ..default()
                },
                TextureAtlas {
                    layout: texture_atlas_layout.clone(),
                    index: 2,
                },
                ImageScaleMode::Sliced(TextureSlicer {
                    border: BorderRect::square(2.),
                    center_scale_mode: SliceScaleMode::Stretch,
                    sides_scale_mode: SliceScaleMode::Stretch,
                    max_corner_scale: 1.,
                }),
            ));

            // with tiled
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()),
                    style: style.clone(),
                    ..default()
                },
                ImageScaleMode::Tiled {
                    tile_x: true,
                    tile_y: true,
                    stretch_value: 1.,
                },
            ));

            // with rect and tiled
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()).with_rect(Rect::new(0., 0., 16., 16.)),
                    style: style.clone(),
                    ..default()
                },
                ImageScaleMode::Tiled {
                    tile_x: true,
                    tile_y: true,
                    stretch_value: 1.,
                },
            ));

            // with rect, texture atlas and tiled
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()).with_rect(Rect::new(0., 0., 8., 8.)),
                    style: style.clone(),
                    ..default()
                },
                TextureAtlas {
                    layout: texture_atlas_layout.clone(),
                    index: 1,
                },
                ImageScaleMode::Tiled {
                    tile_x: true,
                    tile_y: true,
                    stretch_value: 1.,
                },
            ));

            // with texture atlas and tiled
            parent.spawn((
                ImageBundle {
                    image: UiImage::new(texture.clone()),
                    style: style.clone(),
                    ..default()
                },
                TextureAtlas {
                    layout: texture_atlas_layout.clone(),
                    index: 2,
                },
                ImageScaleMode::Tiled {
                    tile_x: true,
                    tile_y: true,
                    stretch_value: 1.,
                },
            ));
        });
}
```

</details>
2024-09-09 16:16:33 +00:00
..
bevy_a11y Add Reflect derive to bevy_a11y::Focus (#14763) 2024-08-15 17:33:20 +00:00
bevy_animation Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_app Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_asset Depreciate LoadAndSave Asset Processor (#15090) 2024-09-09 16:01:14 +00:00
bevy_audio Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_color Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_core Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_core_pipeline Add common aspect ratio constants and improve documentation (#15091) 2024-09-09 16:04:41 +00:00
bevy_derive Remove deprecated bevy_dynamic_plugin (#14534) 2024-07-30 15:31:08 +00:00
bevy_dev_tools Split OrthographicProjection::default into 2d & 3d (Adopted) (#15073) 2024-09-09 15:51:28 +00:00
bevy_diagnostic Apply unused_qualifications lint (#14828) 2024-08-21 12:29:33 +00:00
bevy_dylib Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_ecs Remove remnant EntityHash and related types from bevy_utils (#15039) 2024-09-09 15:24:17 +00:00
bevy_encase_derive Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_gilrs Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_gizmos Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_gltf Split OrthographicProjection::default into 2d & 3d (Adopted) (#15073) 2024-09-09 15:51:28 +00:00
bevy_hierarchy Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_input Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_internal Remove all existing system order ambiguities in DefaultPlugins (#15031) 2024-09-03 20:24:34 +00:00
bevy_log Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_macro_utils Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_math Add common aspect ratio constants and improve documentation (#15091) 2024-09-09 16:04:41 +00:00
bevy_mikktspace Fix underflow panic in InitTriInfo (#14893) 2024-08-25 14:13:23 +00:00
bevy_pbr bevy_pbr: Make choosing of diffuse indirect lighting explicit. (#15093) 2024-09-09 16:11:16 +00:00
bevy_picking Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_ptr Migrated NonZero* to NonZero<*> (#14978) 2024-08-30 02:37:47 +00:00
bevy_reflect Remove remnant EntityHash and related types from bevy_utils (#15039) 2024-09-09 15:24:17 +00:00
bevy_render Add common aspect ratio constants and improve documentation (#15091) 2024-09-09 16:04:41 +00:00
bevy_scene Sorts the scene entries by path before serializing. (#15047) 2024-09-09 15:31:30 +00:00
bevy_sprite Remove deprecated SpriteSheetBundle and AtlasImageBundle (#15062) 2024-09-09 15:36:09 +00:00
bevy_state Add set_state extension method to Commands (#15083) 2024-09-09 15:58:09 +00:00
bevy_tasks Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_text Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_time Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_transform Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_ui Add rect field to UI image (#15095) 2024-09-09 16:16:33 +00:00
bevy_utils Remove remnant EntityHash and related types from bevy_utils (#15039) 2024-09-09 15:24:17 +00:00
bevy_window Unify crate-level preludes (#15080) 2024-09-08 17:10:57 +00:00
bevy_winit Picking event ordering (#14862) 2024-09-04 19:41:06 +00:00