TextLayoutInfo::size should hold the drawn size of the text, and not a scaled value. (#7794)
# Objective `TextLayoutInfo::size` isn't the drawn size of the text, but a scaled value. This is fragile, counter-intuitive and makes it awkward to retrieve the correct value. ## Solution Multiply `TextLayoutInfo::size` by the reciprocal of the window's scale factor after generating the text layout in `update_text2d_layout` and `bevy_ui::widget::text_system`. --- fixes: #7787 ## Changelog * Multiply `TextLayoutInfo::size` by the reciprocal of the scale factor after text computation to reflect the actual size of the text as drawn. * Reorder the operations in `extract_text2d_sprite` to apply the alignment offset before the scale factor scaling. ## Migration Guide The `size` value of `TextLayoutInfo` is stored in logical pixels and has been renamed to `logical_size`. There is no longer any need to divide by the window's scale factor to get the logical size.
This commit is contained in:
parent
f3ab38a802
commit
9d9750b928
@ -25,7 +25,7 @@ pub struct TextPipeline {
|
|||||||
#[derive(Component, Clone, Default, Debug)]
|
#[derive(Component, Clone, Default, Debug)]
|
||||||
pub struct TextLayoutInfo {
|
pub struct TextLayoutInfo {
|
||||||
pub glyphs: Vec<PositionedGlyph>,
|
pub glyphs: Vec<PositionedGlyph>,
|
||||||
pub size: Vec2,
|
pub logical_size: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextPipeline {
|
impl TextPipeline {
|
||||||
@ -97,7 +97,10 @@ impl TextPipeline {
|
|||||||
y_axis_orientation,
|
y_axis_orientation,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(TextLayoutInfo { glyphs, size })
|
Ok(TextLayoutInfo {
|
||||||
|
glyphs,
|
||||||
|
logical_size: size,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged};
|
|||||||
#[derive(Component, Copy, Clone, Debug, Reflect)]
|
#[derive(Component, Copy, Clone, Debug, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct Text2dBounds {
|
pub struct Text2dBounds {
|
||||||
|
/// The maximum width and height of text in logical pixels.
|
||||||
pub size: Vec2,
|
pub size: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,10 +106,10 @@ pub fn extract_text2d_sprite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let text_anchor = -(anchor.as_vec() + 0.5);
|
let text_anchor = -(anchor.as_vec() + 0.5);
|
||||||
let alignment_translation = text_layout_info.size * text_anchor;
|
let alignment_translation = text_layout_info.logical_size * text_anchor;
|
||||||
let transform = *global_transform
|
let transform = *global_transform
|
||||||
* scaling
|
* GlobalTransform::from_translation(alignment_translation.extend(0.))
|
||||||
* GlobalTransform::from_translation(alignment_translation.extend(0.));
|
* scaling;
|
||||||
let mut color = Color::WHITE;
|
let mut color = Color::WHITE;
|
||||||
let mut current_section = usize::MAX;
|
let mut current_section = usize::MAX;
|
||||||
for PositionedGlyph {
|
for PositionedGlyph {
|
||||||
@ -172,6 +173,8 @@ pub fn update_text2d_layout(
|
|||||||
.map(|window| window.resolution.scale_factor())
|
.map(|window| window.resolution.scale_factor())
|
||||||
.unwrap_or(1.0);
|
.unwrap_or(1.0);
|
||||||
|
|
||||||
|
let inverse_scale_factor = scale_factor.recip();
|
||||||
|
|
||||||
for (entity, text, bounds, mut text_layout_info) in &mut text_query {
|
for (entity, text, bounds, mut text_layout_info) in &mut text_query {
|
||||||
if factor_changed || text.is_changed() || bounds.is_changed() || queue.remove(&entity) {
|
if factor_changed || text.is_changed() || bounds.is_changed() || queue.remove(&entity) {
|
||||||
let text_bounds = Vec2::new(
|
let text_bounds = Vec2::new(
|
||||||
@ -182,7 +185,6 @@ pub fn update_text2d_layout(
|
|||||||
},
|
},
|
||||||
scale_value(bounds.size.y, scale_factor),
|
scale_value(bounds.size.y, scale_factor),
|
||||||
);
|
);
|
||||||
|
|
||||||
match text_pipeline.queue_text(
|
match text_pipeline.queue_text(
|
||||||
&fonts,
|
&fonts,
|
||||||
&text.sections,
|
&text.sections,
|
||||||
@ -205,7 +207,11 @@ pub fn update_text2d_layout(
|
|||||||
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
||||||
panic!("Fatal error when processing text: {e}.");
|
panic!("Fatal error when processing text: {e}.");
|
||||||
}
|
}
|
||||||
Ok(info) => *text_layout_info = info,
|
Ok(mut info) => {
|
||||||
|
info.logical_size.x = scale_value(info.logical_size.x, inverse_scale_factor);
|
||||||
|
info.logical_size.y = scale_value(info.logical_size.y, inverse_scale_factor);
|
||||||
|
*text_layout_info = info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,8 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
|||||||
use bevy_render::texture::Image;
|
use bevy_render::texture::Image;
|
||||||
use bevy_sprite::TextureAtlas;
|
use bevy_sprite::TextureAtlas;
|
||||||
use bevy_text::{
|
use bevy_text::{
|
||||||
BreakLineOn, Font, FontAtlasSets, FontAtlasWarning, Text, TextError, TextLayoutInfo,
|
scale_value, BreakLineOn, Font, FontAtlasSets, FontAtlasWarning, Text, TextError,
|
||||||
TextMeasureInfo, TextPipeline, TextSettings, YAxisOrientation,
|
TextLayoutInfo, TextMeasureInfo, TextPipeline, TextSettings, YAxisOrientation,
|
||||||
};
|
};
|
||||||
use bevy_window::{PrimaryWindow, Window};
|
use bevy_window::{PrimaryWindow, Window};
|
||||||
use taffy::style::AvailableSpace;
|
use taffy::style::AvailableSpace;
|
||||||
@ -153,6 +153,7 @@ fn queue_text(
|
|||||||
textures: &mut Assets<Image>,
|
textures: &mut Assets<Image>,
|
||||||
text_settings: &TextSettings,
|
text_settings: &TextSettings,
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
|
inverse_scale_factor: f64,
|
||||||
text: &Text,
|
text: &Text,
|
||||||
node: Ref<Node>,
|
node: Ref<Node>,
|
||||||
mut text_flags: Mut<TextFlags>,
|
mut text_flags: Mut<TextFlags>,
|
||||||
@ -189,7 +190,9 @@ fn queue_text(
|
|||||||
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
||||||
panic!("Fatal error when processing text: {e}.");
|
panic!("Fatal error when processing text: {e}.");
|
||||||
}
|
}
|
||||||
Ok(info) => {
|
Ok(mut info) => {
|
||||||
|
info.logical_size.x = scale_value(info.logical_size.x, inverse_scale_factor);
|
||||||
|
info.logical_size.y = scale_value(info.logical_size.y, inverse_scale_factor);
|
||||||
*text_layout_info = info;
|
*text_layout_info = info;
|
||||||
text_flags.needs_recompute = false;
|
text_flags.needs_recompute = false;
|
||||||
}
|
}
|
||||||
@ -226,7 +229,7 @@ pub fn text_system(
|
|||||||
.unwrap_or(1.);
|
.unwrap_or(1.);
|
||||||
|
|
||||||
let scale_factor = ui_scale.0 * window_scale_factor;
|
let scale_factor = ui_scale.0 * window_scale_factor;
|
||||||
|
let inverse_scale_factor = scale_factor.recip();
|
||||||
if *last_scale_factor == scale_factor {
|
if *last_scale_factor == scale_factor {
|
||||||
// Scale factor unchanged, only recompute text for modified text nodes
|
// Scale factor unchanged, only recompute text for modified text nodes
|
||||||
for (node, text, text_layout_info, text_flags) in text_query.iter_mut() {
|
for (node, text, text_layout_info, text_flags) in text_query.iter_mut() {
|
||||||
@ -240,6 +243,7 @@ pub fn text_system(
|
|||||||
&mut textures,
|
&mut textures,
|
||||||
&text_settings,
|
&text_settings,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
|
inverse_scale_factor,
|
||||||
text,
|
text,
|
||||||
node,
|
node,
|
||||||
text_flags,
|
text_flags,
|
||||||
@ -261,6 +265,7 @@ pub fn text_system(
|
|||||||
&mut textures,
|
&mut textures,
|
||||||
&text_settings,
|
&text_settings,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
|
inverse_scale_factor,
|
||||||
text,
|
text,
|
||||||
node,
|
node,
|
||||||
text_flags,
|
text_flags,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user