Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion crates/bevy_text/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ impl Text {
self.alignment = alignment;
self
}

/// Returns this [`Text`] with soft wrapping disabled.
/// Hard wrapping, where text contains an explicit linebreak such as the escape sequence `\n`, will still occur.
pub const fn with_no_wrap(mut self) -> Self {
self.linebreak_behavior = BreakLineOn::NoWrap;
self
}
}

#[derive(Debug, Default, Clone, FromReflect, Reflect)]
Expand Down Expand Up @@ -186,12 +193,19 @@ pub enum BreakLineOn {
/// This is closer to the behavior one might expect from text in a terminal.
/// However it may lead to words being broken up across linebreaks.
AnyCharacter,
/// No soft wrapping, where text is automatically broken up into separate lines when it overflows a boundary, will ever occur.
/// Hard wrapping, where text contains an explicit linebreak such as the escape sequence `\n`, is still enabled.
NoWrap,
}

impl From<BreakLineOn> for glyph_brush_layout::BuiltInLineBreaker {
fn from(val: BreakLineOn) -> Self {
match val {
BreakLineOn::WordBoundary => glyph_brush_layout::BuiltInLineBreaker::UnicodeLineBreaker,
// If `NoWrap` is set the choice of `BuiltInLineBreaker` doesn't matter as the text is given unbounded width and soft wrapping will never occur.
// But `NoWrap` does not disable hard breaks where a [`Text`] contains a newline character.
BreakLineOn::WordBoundary | BreakLineOn::NoWrap => {
glyph_brush_layout::BuiltInLineBreaker::UnicodeLineBreaker
}
BreakLineOn::AnyCharacter => glyph_brush_layout::BuiltInLineBreaker::AnyCharLineBreaker,
}
}
Expand Down
10 changes: 7 additions & 3 deletions crates/bevy_text/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use bevy_utils::HashSet;
use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged};

use crate::{
Font, FontAtlasSet, FontAtlasWarning, PositionedGlyph, Text, TextError, TextLayoutInfo,
TextPipeline, TextSettings, YAxisOrientation,
BreakLineOn, Font, FontAtlasSet, FontAtlasWarning, PositionedGlyph, Text, TextError,
TextLayoutInfo, TextPipeline, TextSettings, YAxisOrientation,
};

/// The maximum width and height of text. The text will wrap according to the specified size.
Expand Down Expand Up @@ -174,7 +174,11 @@ pub fn update_text2d_layout(
for (entity, text, bounds, mut text_layout_info) in &mut text_query {
if factor_changed || text.is_changed() || bounds.is_changed() || queue.remove(&entity) {
let text_bounds = Vec2::new(
scale_value(bounds.size.x, scale_factor),
if text.linebreak_behavior == BreakLineOn::NoWrap {
f32::INFINITY
} else {
scale_value(bounds.size.x, scale_factor)
},
scale_value(bounds.size.y, scale_factor),
);

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ui/src/measurement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub trait Measure: Send + Sync + 'static {
/// always returns the same size.
#[derive(Default, Clone)]
pub struct FixedMeasure {
size: Vec2,
pub size: Vec2,
}

impl Measure for FixedMeasure {
Expand Down
9 changes: 8 additions & 1 deletion crates/bevy_ui/src/node_bundles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use bevy_render::{
};
use bevy_sprite::TextureAtlas;
#[cfg(feature = "bevy_text")]
use bevy_text::{Text, TextAlignment, TextLayoutInfo, TextSection, TextStyle};
use bevy_text::{BreakLineOn, Text, TextAlignment, TextLayoutInfo, TextSection, TextStyle};
use bevy_transform::prelude::{GlobalTransform, Transform};

/// The basic UI node
Expand Down Expand Up @@ -256,6 +256,13 @@ impl TextBundle {
self.background_color = BackgroundColor(color);
self
}

/// Returns this [`TextBundle`] with soft wrapping disabled.
/// Hard wrapping, where text contains an explicit linebreak such as the escape sequence `\n`, will still occur.
pub const fn with_no_wrap(mut self) -> Self {
self.text.linebreak_behavior = BreakLineOn::NoWrap;
self
}
}

/// A UI node that is a button
Expand Down
21 changes: 16 additions & 5 deletions crates/bevy_ui/src/widget/text.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ContentSize, Measure, Node, UiScale};
use crate::{ContentSize, FixedMeasure, Measure, Node, UiScale};
use bevy_asset::Assets;
use bevy_ecs::{
prelude::{Component, DetectChanges},
Expand All @@ -12,8 +12,8 @@ use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect, ReflectFrom
use bevy_render::texture::Image;
use bevy_sprite::TextureAtlas;
use bevy_text::{
Font, FontAtlasSet, FontAtlasWarning, Text, TextError, TextLayoutInfo, TextMeasureInfo,
TextPipeline, TextSettings, YAxisOrientation,
BreakLineOn, Font, FontAtlasSet, FontAtlasWarning, Text, TextError, TextLayoutInfo,
TextMeasureInfo, TextPipeline, TextSettings, YAxisOrientation,
};
use bevy_window::{PrimaryWindow, Window};
use taffy::style::AvailableSpace;
Expand Down Expand Up @@ -91,7 +91,13 @@ fn create_text_measure(
text.linebreak_behavior,
) {
Ok(measure) => {
content_size.set(TextMeasure { info: measure });
if text.linebreak_behavior == BreakLineOn::NoWrap {
content_size.set(FixedMeasure {
size: measure.max_width_content_size,
});
} else {
content_size.set(TextMeasure { info: measure });
}

// Text measure func created succesfully, so set `TextFlags` to schedule a recompute
text_flags.needs_new_measure_func = false;
Expand Down Expand Up @@ -174,7 +180,12 @@ fn queue_text(
) {
// Skip the text node if it is waiting for a new measure func
if !text_flags.needs_new_measure_func {
let physical_node_size = node.physical_size(scale_factor);
let physical_node_size = if text.linebreak_behavior == BreakLineOn::NoWrap {
// With `NoWrap` set, no constraints are placed on the width of the text.
Vec2::splat(f32::INFINITY)
} else {
node.physical_size(scale_factor)
};

match text_pipeline.queue_text(
fonts,
Expand Down
8 changes: 6 additions & 2 deletions examples/ui/text_wrap_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
})
.id();

for linebreak_behavior in [BreakLineOn::AnyCharacter, BreakLineOn::WordBoundary] {
for linebreak_behavior in [
BreakLineOn::AnyCharacter,
BreakLineOn::WordBoundary,
BreakLineOn::NoWrap,
] {
let row_id = commands
.spawn(NodeBundle {
style: Style {
Expand Down Expand Up @@ -66,7 +70,7 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
flex_direction: FlexDirection::Column,
width: Val::Percent(16.),
height: Val::Percent(95.),
overflow: Overflow::clip(),
overflow: Overflow::clip_x(),
..Default::default()
},
background_color: Color::rgb(0.5, c, 1.0 - c).into(),
Expand Down