From ccfae7ebe7aaa6e448db9e7080b4cccb97475dea Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Fri, 14 Jun 2024 20:14:42 +0100 Subject: [PATCH] fix non-exact text h-alignment (#13846) # Objective when a parent container is auto-sized, text alignments `Center` and `Right` don't align to the center and right properly. fix it ## Solution ab_glyph positions return +/- values from an anchor point. we currently transform them to positive values from the min-x of the glyphs, and then offset from the left of the bounds. instead, we can keep the negative values as ab_glyph intended and offset from the left/middle/right of the bounds as appropriate. ## Testing texts with align left, center, right, all contained in the purple boxes: before (0.14.0-rc.2): ![Screenshot 2024-06-14 165456](https://github.com/bevyengine/bevy/assets/50659922/90fb73b0-d8bd-4ae8-abf3-7106eafc93ba) after: ![Screenshot 2024-06-14 164449](https://github.com/bevyengine/bevy/assets/50659922/0a75ff09-b51d-4fbe-a491-b655a145c08b) code: ```rs use bevy::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); for (left, justify) in [ (100.0, JustifyText::Left), (500.0, JustifyText::Center), (900.0, JustifyText::Right), ] { commands // container .spawn(NodeBundle { style: Style { flex_direction: FlexDirection::Column, position_type: PositionType::Absolute, left: Val::Px(left), top: Val::Px(100.0), width: Val::Px(300.0), ..Default::default() }, ..Default::default() }) .with_children(|commands| { commands.spawn(NodeBundle{ style: Style { flex_direction: FlexDirection::Row, height: Val::Px(75.0), ..Default::default() }, background_color: Color::srgb(1.0, 0.0, 1.0).into(), ..Default::default() }).with_children(|commands| { // a div that reduces the available size commands.spawn(NodeBundle { style: Style { width: Val::Px(75.0), ..Default::default() }, background_color: Color::srgb(0.0, 1.0, 0.0).into(), ..Default::default() }); // text with width=auto, but actual size will not be what it expcets due to the sibling div above commands.spawn(TextBundle { text: Text::from_section("Some text that wraps onto a second line", Default::default()).with_justify(justify), style: Style { align_self: AlignSelf::Center, ..Default::default() }, ..Default::default() }); }); }); } } ``` --- crates/bevy_text/src/glyph_brush.rs | 3 ++- crates/bevy_text/src/pipeline.rs | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/bevy_text/src/glyph_brush.rs b/crates/bevy_text/src/glyph_brush.rs index 1287cd097be81..d7dc1045d403f 100644 --- a/crates/bevy_text/src/glyph_brush.rs +++ b/crates/bevy_text/src/glyph_brush.rs @@ -64,6 +64,7 @@ impl GlyphBrush { textures: &mut Assets, text_settings: &TextSettings, y_axis_orientation: YAxisOrientation, + h_anchor: f32, ) -> Result, TextError> { if glyphs.is_empty() { return Ok(Vec::new()); @@ -124,7 +125,7 @@ impl GlyphBrush { let glyph_rect = texture_atlas.textures[atlas_info.glyph_index]; let size = glyph_rect.size().as_vec2(); - let x = bounds.min.x + size.x / 2.0 - text_bounds.min.x; + let x = bounds.min.x + size.x / 2.0 + h_anchor; let y = match y_axis_orientation { YAxisOrientation::BottomToTop => { diff --git a/crates/bevy_text/src/pipeline.rs b/crates/bevy_text/src/pipeline.rs index 26c547466e05f..e6d945a7a9b84 100644 --- a/crates/bevy_text/src/pipeline.rs +++ b/crates/bevy_text/src/pipeline.rs @@ -87,6 +87,13 @@ impl TextPipeline { let size = compute_text_bounds(§ion_glyphs, |index| scaled_fonts[index]).size(); + let h_anchor = match text_alignment { + JustifyText::Left => 0.0, + JustifyText::Center => bounds.x * 0.5, + JustifyText::Right => bounds.x * 1.0, + } + .floor(); + let glyphs = self.brush.process_glyphs( section_glyphs, §ions, @@ -96,6 +103,7 @@ impl TextPipeline { textures, text_settings, y_axis_orientation, + h_anchor, )?; Ok(TextLayoutInfo {