Rename TextAlignment to JustifyText. (#10854)

# Objective

The name `TextAlignment` is really deceptive and almost every new user
gets confused about the differences between aligning text with
`TextAlignment`, aligning text with `Style` and aligning text with
anchor (when using `Text2d`).

## Solution

* Rename `TextAlignment` to `JustifyText`. The associated helper methods
are also renamed.
* Improve the doc comments for text explaining explicitly how the
`JustifyText` component affects the arrangement of text.
* Add some extra cases to the `text_debug` example that demonstate the
differences between alignment using `JustifyText` and alignment using
`Style`.
<img width="757" alt="text_debug_2"
src="https://github.com/bevyengine/bevy/assets/27962798/9d53e647-93f9-4bc7-8a20-0d9f783304d2">

---

## Changelog
* `TextAlignment` has been renamed to `JustifyText`
* `TextBundle::with_text_alignment` has been renamed to
`TextBundle::with_text_justify`
* `Text::with_alignment` has been renamed to `Text::with_justify`
* The `text_alignment` field of `TextMeasureInfo` has been renamed to
`justification`

## Migration Guide
* `TextAlignment` has been renamed to `JustifyText`
* `TextBundle::with_text_alignment` has been renamed to
`TextBundle::with_text_justify`
* `Text::with_alignment` has been renamed to `Text::with_justify`
* The `text_alignment` field of `TextMeasureInfo` has been renamed to
`justification`
This commit is contained in:
ickshonpe 2023-12-05 03:00:41 +00:00 committed by GitHub
parent 72adf2ae2a
commit 166686e0f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 205 additions and 145 deletions

View file

@ -12,7 +12,7 @@ use glyph_brush_layout::{
use crate::{
error::TextError, BreakLineOn, Font, FontAtlasSet, FontAtlasSets, FontAtlasWarning,
GlyphAtlasInfo, TextAlignment, TextSettings, YAxisOrientation,
GlyphAtlasInfo, JustifyText, TextSettings, YAxisOrientation,
};
pub struct GlyphBrush {
@ -36,7 +36,7 @@ impl GlyphBrush {
&self,
sections: &[S],
bounds: Vec2,
text_alignment: TextAlignment,
text_alignment: JustifyText,
linebreak_behavior: BreakLineOn,
) -> Result<Vec<SectionGlyph>, TextError> {
let geom = SectionGeometry {

View file

@ -20,7 +20,7 @@ pub use text2d::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{Font, Text, Text2dBundle, TextAlignment, TextError, TextSection, TextStyle};
pub use crate::{Font, JustifyText, Text, Text2dBundle, TextError, TextSection, TextStyle};
}
use bevy_app::prelude::*;
@ -83,7 +83,7 @@ impl Plugin for TextPlugin {
.register_type::<TextSection>()
.register_type::<Vec<TextSection>>()
.register_type::<TextStyle>()
.register_type::<TextAlignment>()
.register_type::<JustifyText>()
.register_type::<BreakLineOn>()
.init_asset_loader::<FontLoader>()
.init_resource::<TextSettings>()

View file

@ -1,7 +1,7 @@
use crate::{
compute_text_bounds, error::TextError, glyph_brush::GlyphBrush, scale_value, BreakLineOn, Font,
FontAtlasSets, FontAtlasWarning, PositionedGlyph, Text, TextAlignment, TextSection,
TextSettings, YAxisOrientation,
FontAtlasSets, FontAtlasWarning, JustifyText, PositionedGlyph, Text, TextSection, TextSettings,
YAxisOrientation,
};
use ab_glyph::PxScale;
use bevy_asset::{AssetId, Assets, Handle};
@ -47,7 +47,7 @@ impl TextPipeline {
fonts: &Assets<Font>,
sections: &[TextSection],
scale_factor: f64,
text_alignment: TextAlignment,
text_alignment: JustifyText,
linebreak_behavior: BreakLineOn,
bounds: Vec2,
font_atlas_sets: &mut FontAtlasSets,
@ -119,7 +119,7 @@ pub struct TextMeasureSection {
pub struct TextMeasureInfo {
pub fonts: Box<[ab_glyph::FontArc]>,
pub sections: Box<[TextMeasureSection]>,
pub text_alignment: TextAlignment,
pub justification: JustifyText,
pub linebreak_behavior: glyph_brush_layout::BuiltInLineBreaker,
pub min: Vec2,
pub max: Vec2,
@ -158,20 +158,20 @@ impl TextMeasureInfo {
Ok(Self::new(
auto_fonts,
sections,
text.alignment,
text.justify,
text.linebreak_behavior.into(),
))
}
fn new(
fonts: Vec<ab_glyph::FontArc>,
sections: Vec<TextMeasureSection>,
text_alignment: TextAlignment,
justification: JustifyText,
linebreak_behavior: glyph_brush_layout::BuiltInLineBreaker,
) -> Self {
let mut info = Self {
fonts: fonts.into_boxed_slice(),
sections: sections.into_boxed_slice(),
text_alignment,
justification,
linebreak_behavior,
min: Vec2::ZERO,
max: Vec2::ZERO,
@ -191,7 +191,7 @@ impl TextMeasureInfo {
..Default::default()
};
let section_glyphs = glyph_brush_layout::Layout::default()
.h_align(self.text_alignment.into())
.h_align(self.justification.into())
.line_breaker(self.linebreak_behavior)
.calculate_glyphs(&self.fonts, &geom, sections);

View file

@ -13,7 +13,7 @@ pub struct Text {
pub sections: Vec<TextSection>,
/// The text's internal alignment.
/// Should not affect its position within a container.
pub alignment: TextAlignment,
pub justify: JustifyText,
/// How the text should linebreak when running out of the bounds determined by max_size
pub linebreak_behavior: BreakLineOn,
}
@ -22,7 +22,7 @@ impl Default for Text {
fn default() -> Self {
Self {
sections: Default::default(),
alignment: TextAlignment::Left,
justify: JustifyText::Left,
linebreak_behavior: BreakLineOn::WordBoundary,
}
}
@ -34,7 +34,7 @@ impl Text {
/// ```
/// # use bevy_asset::Handle;
/// # use bevy_render::color::Color;
/// # use bevy_text::{Font, Text, TextStyle, TextAlignment};
/// # use bevy_text::{Font, Text, TextStyle, JustifyText};
/// #
/// # let font_handle: Handle<Font> = Default::default();
/// #
@ -50,14 +50,14 @@ impl Text {
/// );
///
/// let hello_bevy = Text::from_section(
/// "hello bevy!",
/// "hello world\nand bevy!",
/// TextStyle {
/// font: font_handle,
/// font_size: 60.0,
/// color: Color::WHITE,
/// },
/// ) // You can still add an alignment.
/// .with_alignment(TextAlignment::Center);
/// ) // You can still add text justifaction.
/// .with_justify(JustifyText::Center);
/// ```
pub fn from_section(value: impl Into<String>, style: TextStyle) -> Self {
Self {
@ -101,9 +101,9 @@ impl Text {
}
}
/// Returns this [`Text`] with a new [`TextAlignment`].
pub const fn with_alignment(mut self, alignment: TextAlignment) -> Self {
self.alignment = alignment;
/// Returns this [`Text`] with a new [`JustifyText`].
pub const fn with_justify(mut self, justify: JustifyText) -> Self {
self.justify = justify;
self
}
@ -159,28 +159,32 @@ impl From<String> for TextSection {
}
}
/// Describes horizontal alignment preference for positioning & bounds.
/// Describes the horizontal alignment of multiple lines of text relative to each other.
/// This only affects the internal positioning of the lines of text within a text entity and
/// does not affect the text entity's position.
///
/// _Has no affect on a single line text entity._
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
#[reflect(Serialize, Deserialize)]
pub enum TextAlignment {
/// Leftmost character is immediately to the right of the render position.<br/>
pub enum JustifyText {
/// Leftmost character is immediately to the right of the render position.
/// Bounds start from the render position and advance rightwards.
#[default]
Left,
/// Leftmost & rightmost characters are equidistant to the render position.<br/>
/// Leftmost & rightmost characters are equidistant to the render position.
/// Bounds start from the render position and advance equally left & right.
Center,
/// Rightmost character is immediately to the left of the render position.<br/>
/// Rightmost character is immediately to the left of the render position.
/// Bounds start from the render position and advance leftwards.
Right,
}
impl From<TextAlignment> for glyph_brush_layout::HorizontalAlign {
fn from(val: TextAlignment) -> Self {
impl From<JustifyText> for glyph_brush_layout::HorizontalAlign {
fn from(val: JustifyText) -> Self {
match val {
TextAlignment::Left => glyph_brush_layout::HorizontalAlign::Left,
TextAlignment::Center => glyph_brush_layout::HorizontalAlign::Center,
TextAlignment::Right => glyph_brush_layout::HorizontalAlign::Right,
JustifyText::Left => glyph_brush_layout::HorizontalAlign::Left,
JustifyText::Center => glyph_brush_layout::HorizontalAlign::Center,
JustifyText::Right => glyph_brush_layout::HorizontalAlign::Right,
}
}
}

View file

@ -28,7 +28,7 @@ use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged};
/// The maximum width and height of text. The text will wrap according to the specified size.
/// Characters out of the bounds after wrapping will be truncated. Text is aligned according to the
/// specified [`TextAlignment`](crate::text::TextAlignment).
/// specified [`JustifyText`](crate::text::JustifyText).
///
/// Note: only characters that are completely out of the bounds will be truncated, so this is not a
/// reliable limit if it is necessary to contain the text strictly in the bounds. Currently this
@ -196,7 +196,7 @@ pub fn update_text2d_layout(
&fonts,
&text.sections,
scale_factor,
text.alignment,
text.justify,
text.linebreak_behavior,
text_bounds,
&mut font_atlas_sets,

View file

@ -15,7 +15,7 @@ use bevy_render::{
};
use bevy_sprite::TextureAtlas;
#[cfg(feature = "bevy_text")]
use bevy_text::{BreakLineOn, Text, TextAlignment, TextLayoutInfo, TextSection, TextStyle};
use bevy_text::{BreakLineOn, JustifyText, Text, TextLayoutInfo, TextSection, TextStyle};
use bevy_transform::prelude::{GlobalTransform, Transform};
/// The basic UI node
@ -245,9 +245,9 @@ impl TextBundle {
}
}
/// Returns this [`TextBundle`] with a new [`TextAlignment`] on [`Text`].
pub const fn with_text_alignment(mut self, alignment: TextAlignment) -> Self {
self.text.alignment = alignment;
/// Returns this [`TextBundle`] with a new [`JustifyText`] on [`Text`].
pub const fn with_text_justify(mut self, justify: JustifyText) -> Self {
self.text.justify = justify;
self
}

View file

@ -182,7 +182,7 @@ fn queue_text(
fonts,
&text.sections,
scale_factor,
text.alignment,
text.justify,
text.linebreak_behavior,
physical_node_size,
font_atlas_sets,

View file

@ -38,14 +38,14 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 60.0,
color: Color::WHITE,
};
let text_alignment = TextAlignment::Center;
let text_justification = JustifyText::Center;
// 2d camera
commands.spawn(Camera2dBundle::default());
// Demonstrate changing translation
commands.spawn((
Text2dBundle {
text: Text::from_section("translation", text_style.clone())
.with_alignment(text_alignment),
.with_justify(text_justification),
..default()
},
AnimateTranslation,
@ -53,7 +53,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Demonstrate changing rotation
commands.spawn((
Text2dBundle {
text: Text::from_section("rotation", text_style.clone()).with_alignment(text_alignment),
text: Text::from_section("rotation", text_style.clone())
.with_justify(text_justification),
..default()
},
AnimateRotation,
@ -61,7 +62,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Demonstrate changing scale
commands.spawn((
Text2dBundle {
text: Text::from_section("scale", text_style).with_alignment(text_alignment),
text: Text::from_section("scale", text_style).with_justify(text_justification),
..default()
},
AnimateScale,
@ -91,7 +92,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
"this text wraps in the box\n(Unicode linebreaks)",
slightly_smaller_text_style.clone(),
)],
alignment: TextAlignment::Left,
justify: JustifyText::Left,
linebreak_behavior: BreakLineOn::WordBoundary,
},
text_2d_bounds: Text2dBounds {
@ -123,7 +124,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
"this text wraps in the box\n(AnyCharacter linebreaks)",
slightly_smaller_text_style.clone(),
)],
alignment: TextAlignment::Left,
justify: JustifyText::Left,
linebreak_behavior: BreakLineOn::AnyCharacter,
},
text_2d_bounds: Text2dBounds {

View file

@ -277,7 +277,7 @@ fn setup_image_viewer_scene(
..default()
},
)
.with_text_alignment(TextAlignment::Center)
.with_text_justify(JustifyText::Center)
.with_style(Style {
align_self: AlignSelf::Center,
margin: UiRect::all(Val::Auto),

View file

@ -60,7 +60,7 @@ fn spawn_text(mut commands: Commands, mut reader: EventReader<StreamEvent>) {
for (per_frame, event) in reader.read().enumerate() {
commands.spawn(Text2dBundle {
text: Text::from_section(event.0.to_string(), text_style.clone())
.with_alignment(TextAlignment::Center),
.with_justify(JustifyText::Center),
transform: Transform::from_xyz(per_frame as f32 * 100.0, 300.0, 0.0),
..default()
});

View file

@ -129,7 +129,7 @@ fn setup_scene(
..default()
},
)
.with_text_alignment(TextAlignment::Center),
.with_text_justify(JustifyText::Center),
);
});
}

View file

@ -47,7 +47,7 @@ fn setup(mut commands: Commands) {
..default()
},
}],
alignment: TextAlignment::Left,
justify: JustifyText::Left,
linebreak_behavior: BreakLineOn::AnyCharacter,
};

View file

@ -58,7 +58,7 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Text2dBundle {
text: Text {
sections,
alignment: TextAlignment::Center,
justify: JustifyText::Center,
linebreak_behavior: BreakLineOn::AnyCharacter,
},
..Default::default()

View file

@ -118,7 +118,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut time: ResMu
..default()
},
)
.with_text_alignment(TextAlignment::Center),
.with_text_justify(JustifyText::Center),
);
// virtual time info
@ -131,7 +131,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut time: ResMu
..default()
},
)
.with_text_alignment(TextAlignment::Right),
.with_text_justify(JustifyText::Right),
VirtualTime,
));
});

View file

@ -96,7 +96,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
text: Text::from_section(
"Use the panel on the right to change the Display and Visibility properties for the respective nodes of the panel on the left",
text_style.clone(),
).with_alignment(TextAlignment::Center),
).with_justify(JustifyText::Center),
style: Style {
margin: UiRect::bottom(Val::Px(10.)),
..Default::default()
@ -158,14 +158,14 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
text: Text::from_section(
"Display::None\nVisibility::Hidden\nVisibility::Inherited",
TextStyle { color: HIDDEN_COLOR, ..text_style.clone() }
).with_alignment(TextAlignment::Center),
).with_justify(JustifyText::Center),
..Default::default()
});
builder.spawn(TextBundle {
text: Text::from_section(
"-\n-\n-",
TextStyle { color: Color::DARK_GRAY, ..text_style.clone() }
).with_alignment(TextAlignment::Center),
).with_justify(JustifyText::Center),
..Default::default()
});
builder.spawn(TextBundle::from_section(
@ -425,7 +425,7 @@ where
format!("{}::{:?}", Target::<T>::NAME, T::default()),
text_style,
)
.with_text_alignment(TextAlignment::Center),
.with_text_justify(JustifyText::Center),
);
});
}

View file

@ -287,7 +287,7 @@ fn spawn_button(
..text_style
},
)
.with_alignment(TextAlignment::Center),
.with_justify(JustifyText::Center),
..Default::default()
});
});

View file

@ -39,8 +39,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 100.0,
..default()
},
) // Set the alignment of the Text
.with_text_alignment(TextAlignment::Center)
) // Set the justification of the Text
.with_text_justify(JustifyText::Center)
// Set the style of the TextBundle itself.
.with_style(Style {
position_type: PositionType::Absolute,

View file

@ -29,110 +29,165 @@ struct TextChanges;
fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
commands.spawn(Camera2dBundle::default());
commands.spawn(
TextBundle::from_section(
"This is\ntext with\nline breaks\nin the top left",
TextStyle {
font: font.clone(),
font_size: 50.0,
let root_uinode = commands
.spawn(NodeBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
justify_content: JustifyContent::SpaceBetween,
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(5.0),
left: Val::Px(15.0),
..default()
}),
);
commands.spawn(TextBundle::from_section(
"This text is very long, has a limited width, is centered, is positioned in the top right and is also colored pink.",
TextStyle {
font: font.clone(),
font_size: 50.0,
color: Color::rgb(0.8, 0.2, 0.7),
},
)
.with_text_alignment(TextAlignment::Center)
.with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(5.0),
right: Val::Px(15.0),
max_width: Val::Px(400.),
..default()
})
);
commands.spawn((
TextBundle::from_sections([
TextSection::new(
"This text changes in the bottom right",
.id();
let left_column = commands.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::SpaceBetween,
align_items: AlignItems::Start,
flex_grow: 1.,
margin: UiRect::axes(Val::Px(15.), Val::Px(5.)),
..default()
},
..default()
}).with_children(|builder| {
builder.spawn(
TextBundle::from_section(
"This is\ntext with\nline breaks\nin the top left.",
TextStyle {
font: font.clone(),
font_size: 30.0,
..default()
},
)
);
builder.spawn(TextBundle::from_section(
"This text is right-justified. The `JustifyText` component controls the horizontal alignment of the lines of multi-line text relative to each other, and does not affect the text node's position in the UI layout.", TextStyle {
font: font.clone(),
font_size: 30.0,
color: Color::YELLOW,
},
)
.with_text_justify(JustifyText::Right)
.with_style(Style {
max_width: Val::Px(300.),
..default()
})
);
builder.spawn(
TextBundle::from_section(
"This\ntext has\nline breaks and also a set width in the bottom left.",
TextStyle {
font: font.clone(),
font_size: 30.0,
color: Color::WHITE,
},
),
TextSection::new(
"\nThis text changes in the bottom right - ",
)
.with_style(Style {
max_width: Val::Px(300.),
..default()
})
);
}).id();
let right_column = commands.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::SpaceBetween,
align_items: AlignItems::End,
flex_grow: 1.,
margin: UiRect::axes(Val::Px(15.), Val::Px(5.)),
..default()
},
..default()
}).with_children(|builder| {
builder.spawn(TextBundle::from_section(
"This text is very long, has a limited width, is center-justified, is positioned in the top right and is also colored pink.",
TextStyle {
font: font.clone(),
font_size: 30.0,
color: Color::RED,
font_size: 40.0,
color: Color::rgb(0.8, 0.2, 0.7),
},
),
TextSection::from_style(TextStyle {
font: font.clone(),
font_size: 30.0,
color: Color::ORANGE_RED,
}),
TextSection::new(
" fps, ",
)
.with_text_justify(JustifyText::Center)
.with_style(Style {
max_width: Val::Px(400.),
..default()
})
);
builder.spawn(
TextBundle::from_section(
"This text is left-justified and is vertically positioned to distribute the empty space equally above and below it.",
TextStyle {
font: font.clone(),
font_size: 30.0,
font_size: 35.0,
color: Color::YELLOW,
},
),
TextSection::from_style(TextStyle {
font: font.clone(),
font_size: 30.0,
color: Color::GREEN,
)
.with_text_justify(JustifyText::Left)
.with_style(Style {
max_width: Val::Px(300.),
..default()
}),
TextSection::new(
" ms/frame",
TextStyle {
);
builder.spawn((
TextBundle::from_sections([
TextSection::new(
"This text changes in the bottom right",
TextStyle {
font: font.clone(),
font_size: 25.0,
color: Color::WHITE,
},
),
TextSection::new(
"\nThis text changes in the bottom right - ",
TextStyle {
font: font.clone(),
font_size: 25.0,
color: Color::RED,
},
),
TextSection::from_style(TextStyle {
font: font.clone(),
font_size: 30.0,
color: Color::BLUE,
},
),
])
.with_style(Style {
position_type: PositionType::Absolute,
bottom: Val::Px(5.0),
right: Val::Px(15.0),
..default()
}),
TextChanges,
));
commands.spawn(
TextBundle::from_section(
"This\ntext has\nline breaks and also a set width in the bottom left",
TextStyle {
font,
font_size: 50.0,
color: Color::WHITE,
},
)
.with_style(Style {
align_self: AlignSelf::FlexEnd,
position_type: PositionType::Absolute,
bottom: Val::Px(5.0),
left: Val::Px(15.0),
width: Val::Px(200.0),
..default()
}),
);
font_size: 25.0,
color: Color::ORANGE_RED,
}),
TextSection::new(
" fps, ",
TextStyle {
font: font.clone(),
font_size: 25.0,
color: Color::YELLOW,
},
),
TextSection::from_style(TextStyle {
font: font.clone(),
font_size: 25.0,
color: Color::GREEN,
}),
TextSection::new(
" ms/frame",
TextStyle {
font: font.clone(),
font_size: 25.0,
color: Color::BLUE,
},
),
]),
TextChanges,
));
})
.id();
commands
.entity(root_uinode)
.push_children(&[left_column, right_column]);
}
fn change_text_system(

View file

@ -120,7 +120,7 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
value: message.clone(),
style: text_style.clone(),
}],
alignment: TextAlignment::Left,
justify: JustifyText::Left,
linebreak_behavior,
};
let text_id = commands