use crate::{ measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiTextureAtlasImage, }; use bevy_asset::{Assets, Handle}; #[cfg(feature = "bevy_text")] use bevy_ecs::query::Without; use bevy_ecs::{ prelude::Component, query::With, reflect::ReflectComponent, system::{Query, Res}, }; use bevy_math::Vec2; use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect, ReflectFromReflect}; use bevy_render::texture::Image; use bevy_sprite::TextureAtlas; #[cfg(feature = "bevy_text")] use bevy_text::Text; /// The size of the image in physical pixels /// /// This field is set automatically by `update_image_calculated_size_system` #[derive(Component, Debug, Copy, Clone, Default, Reflect, FromReflect)] #[reflect(Component, Default, FromReflect)] pub struct UiImageSize { size: Vec2, } impl UiImageSize { pub fn size(&self) -> Vec2 { self.size } } #[derive(Clone)] pub struct ImageMeasure { // target size of the image size: Vec2, } impl Measure for ImageMeasure { fn measure( &self, width: Option, height: Option, _: 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 } } /// Updates content size of the node based on the image provided pub fn update_image_content_size_system( textures: Res>, #[cfg(feature = "bevy_text")] mut query: Query< (&mut ContentSize, &UiImage, &mut UiImageSize), (With, Without), >, #[cfg(not(feature = "bevy_text"))] mut query: Query< (&mut ContentSize, &UiImage, &mut UiImageSize), With, >, ) { for (mut content_size, image, mut image_size) in &mut query { if let Some(texture) = textures.get(&image.texture) { let size = Vec2::new( texture.texture_descriptor.size.width as f32, texture.texture_descriptor.size.height as f32, ); // Update only if size has changed to avoid needless layout calculations if size != image_size.size { image_size.size = size; content_size.set(ImageMeasure { size }); } } } } /// Updates content size of the node based on the texture atlas sprite pub fn update_atlas_content_size_system( atlases: Res>, #[cfg(feature = "bevy_text")] mut atlas_query: Query< ( &mut ContentSize, &Handle, &UiTextureAtlasImage, &mut UiImageSize, ), (With, Without, Without), >, #[cfg(not(feature = "bevy_text"))] mut atlas_query: Query< ( &mut ContentSize, &Handle, &UiTextureAtlasImage, &mut UiImageSize, ), (With, Without), >, ) { for (mut content_size, atlas, atlas_image, mut image_size) in &mut atlas_query { if let Some(atlas) = atlases.get(atlas) { let texture_rect = atlas.textures[atlas_image.index]; let size = Vec2::new( texture_rect.max.x - texture_rect.min.x, texture_rect.max.y - texture_rect.min.y, ); // Update only if size has changed to avoid needless layout calculations if size != image_size.size { image_size.size = size; content_size.set(ImageMeasure { size }); } } } }