Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply scale factor to ImageMeasure sizes #8545

Merged
merged 12 commits into from
Jun 23, 2023
65 changes: 48 additions & 17 deletions crates/bevy_ui/src/widget/image.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@
use crate::{
measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiTextureAtlasImage,
measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiScale, 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},
system::{Local, 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;
use bevy_window::{PrimaryWindow, Window};

/// The size of the image in physical pixels
/// The size of the image's texture
///
/// This field is set automatically by `update_image_calculated_size_system`
/// This component is updated automatically by `update_image_calculated_size_system`
ickshonpe marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Component, Debug, Copy, Clone, Default, Reflect, FromReflect)]
#[reflect(Component, Default, FromReflect)]
pub struct UiImageSize {
/// The size of the image's texture
///
/// This field is updated automatically by `update_image_calculated_size_system`
size: Vec2,
}

impl UiImageSize {
/// The size of the image's texture
pub fn size(&self) -> Vec2 {
self.size
}
}

#[derive(Clone)]
/// Used to calculate the size of UI image nodes
pub struct ImageMeasure {
// target size of the image
size: Vec2,
/// The size of the image's texture
pub size: Vec2,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want this to be editable by the user? Or should this be pub(crate)?

Copy link
Contributor Author

@ickshonpe ickshonpe Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's intended to be pub. That way someone can use ImageMeasure for their own custom widget if they want.

Otherwise, it doesn't matter that it's pub as measure funcs can't be accessed by users once they've been added to the layout tree.

}

impl Measure for ImageMeasure {
Expand Down Expand Up @@ -68,6 +75,9 @@ impl Measure for ImageMeasure {

/// Updates content size of the node based on the image provided
pub fn update_image_content_size_system(
mut previous_combined_scale_factor: Local<f64>,
windows: Query<&Window, With<PrimaryWindow>>,
ui_scale: Res<UiScale>,
textures: Res<Assets<Image>>,
#[cfg(feature = "bevy_text")] mut query: Query<
(&mut ContentSize, &UiImage, &mut UiImageSize),
Expand All @@ -78,23 +88,37 @@ pub fn update_image_content_size_system(
With<Node>,
>,
) {
let combined_scale_factor = windows
.get_single()
.map(|window| window.resolution.scale_factor())
.unwrap_or(1.)
* ui_scale.scale;

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 {
// Update only if size or scale factor has changed to avoid needless layout calculations
if size != image_size.size || combined_scale_factor != *previous_combined_scale_factor {
image_size.size = size;
content_size.set(ImageMeasure { size });
content_size.set(ImageMeasure {
// multiply the image size by the scale factor to get the physical size
size: size * combined_scale_factor as f32,
});
}
}
}

*previous_combined_scale_factor = combined_scale_factor;
}

/// Updates content size of the node based on the texture atlas sprite
pub fn update_atlas_content_size_system(
mut previous_combined_scale_factor: Local<f64>,
windows: Query<&Window, With<PrimaryWindow>>,
ui_scale: Res<UiScale>,
atlases: Res<Assets<TextureAtlas>>,
#[cfg(feature = "bevy_text")] mut atlas_query: Query<
(
Expand All @@ -115,18 +139,25 @@ pub fn update_atlas_content_size_system(
(With<Node>, Without<UiImage>),
>,
) {
let combined_scale_factor = windows
.get_single()
.map(|window| window.resolution.scale_factor())
.unwrap_or(1.)
* ui_scale.scale;

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 {
let size = atlas.textures[atlas_image.index].size();
// Update only if size or scale factor has changed to avoid needless layout calculations
if size != image_size.size || combined_scale_factor != *previous_combined_scale_factor {
image_size.size = size;
content_size.set(ImageMeasure { size });
content_size.set(ImageMeasure {
// multiply the image size by the scale factor to get the physical size
size: size * combined_scale_factor as f32,
});
}
}
}

*previous_combined_scale_factor = combined_scale_factor;
}