use crate::{measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiScale};
use bevy_asset::Assets;
use bevy_ecs::prelude::*;
use bevy_math::Vec2;
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::texture::Image;
use bevy_sprite::{TextureAtlas, TextureAtlasLayout};
use bevy_window::{PrimaryWindow, Window};
#[derive(Component, Debug, Copy, Clone, Default, Reflect)]
#[reflect(Component, Default)]
pub struct UiImageSize {
size: Vec2,
}
impl UiImageSize {
pub fn size(&self) -> Vec2 {
self.size
}
}
#[derive(Clone)]
pub struct ImageMeasure {
pub size: Vec2,
}
impl Measure for ImageMeasure {
fn measure(
&self,
width: Option<f32>,
height: Option<f32>,
_: AvailableSpace,
_: AvailableSpace,
) -> Vec2 {
let mut size = self.size;
match (width, height) {
(None, None) => {}
(Some(width), None) => {
size.y = width * size.y / size.x;
size.x = width;
}
(None, Some(height)) => {
size.x = height * size.x / size.y;
size.y = height;
}
(Some(width), Some(height)) => {
size.x = width;
size.y = height;
}
}
size
}
}
#[cfg(feature = "bevy_text")]
type UpdateImageFilter = (With<Node>, Without<bevy_text::Text>);
#[cfg(not(feature = "bevy_text"))]
type UpdateImageFilter = With<Node>;
pub fn update_image_content_size_system(
mut previous_combined_scale_factor: Local<f32>,
windows: Query<&Window, With<PrimaryWindow>>,
ui_scale: Res<UiScale>,
textures: Res<Assets<Image>>,
atlases: Res<Assets<TextureAtlasLayout>>,
mut query: Query<
(
&mut ContentSize,
&UiImage,
&mut UiImageSize,
Option<&TextureAtlas>,
),
UpdateImageFilter,
>,
) {
let combined_scale_factor = windows
.get_single()
.map(|window| window.resolution.scale_factor())
.unwrap_or(1.)
* ui_scale.0;
for (mut content_size, image, mut image_size, atlas_image) in &mut query {
if let Some(size) = match atlas_image {
Some(atlas) => atlas.texture_rect(&atlases).map(|t| t.size()),
None => textures.get(&image.texture).map(|t| t.size_f32()),
} {
if size != image_size.size
|| combined_scale_factor != *previous_combined_scale_factor
|| content_size.is_added()
{
image_size.size = size;
content_size.set(ImageMeasure {
size: size * combined_scale_factor,
});
}
}
}
*previous_combined_scale_factor = combined_scale_factor;
}