 cef56a0d47
			
		
	
	
		cef56a0d47
		
	
	
	
	
		
			
			# Objective Currently, Text always uses the default linebreaking behaviour in glyph_brush_layout `BuiltInLineBreaker::Unicode` which breaks lines at word boundaries. However, glyph_brush_layout also supports breaking lines at any character by setting the linebreaker to `BuiltInLineBreaker::AnyChar`. Having text wrap character-by-character instead of at word boundaries is desirable in some cases - consider that consoles/terminals usually wrap this way. As a side note, the default Unicode linebreaker does not seem to handle emergency cases, where there is no word boundary on a line to break at. In that case, the text runs out of bounds. Issue #1867 shows an example of this. ## Solution Basically just copies how TextAlignment is exposed, but for a new enum TextLineBreakBehaviour. This PR exposes glyph_brush_layout's two simple linebreaking options (Unicode, AnyChar) to users of Text via the enum TextLineBreakBehaviour (which just translates those 2 aforementioned options), plus a method 'with_linebreak_behaviour' on Text and TextBundle. ## Changelog Added `Text::with_linebreak_behaviour` Added `TextBundle::with_linebreak_behaviour` `TextPipeline::queue_text` and `GlyphBrush::compute_glyphs` now need a TextLineBreakBehaviour argument, in order to pass through the new field. Modified the `text2d` example to show both linebreaking behaviours. ## Example Here's what the modified example looks like 
		
			
				
	
	
		
			118 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use ab_glyph::{PxScale, ScaleFont};
 | |
| use bevy_asset::{Assets, Handle, HandleId};
 | |
| use bevy_ecs::component::Component;
 | |
| use bevy_ecs::system::Resource;
 | |
| use bevy_math::Vec2;
 | |
| use bevy_render::texture::Image;
 | |
| use bevy_sprite::TextureAtlas;
 | |
| use bevy_utils::HashMap;
 | |
| 
 | |
| use glyph_brush_layout::{FontId, SectionText};
 | |
| 
 | |
| use crate::{
 | |
|     error::TextError, glyph_brush::GlyphBrush, scale_value, BreakLineOn, Font, FontAtlasSet,
 | |
|     FontAtlasWarning, PositionedGlyph, TextAlignment, TextSection, TextSettings, YAxisOrientation,
 | |
| };
 | |
| 
 | |
| #[derive(Default, Resource)]
 | |
| pub struct TextPipeline {
 | |
|     brush: GlyphBrush,
 | |
|     map_font_id: HashMap<HandleId, FontId>,
 | |
| }
 | |
| 
 | |
| /// Render information for a corresponding [`Text`](crate::Text) component.
 | |
| ///
 | |
| ///  Contains scaled glyphs and their size. Generated via [`TextPipeline::queue_text`].
 | |
| #[derive(Component, Clone, Default, Debug)]
 | |
| pub struct TextLayoutInfo {
 | |
|     pub glyphs: Vec<PositionedGlyph>,
 | |
|     pub size: Vec2,
 | |
| }
 | |
| 
 | |
| impl TextPipeline {
 | |
|     pub fn get_or_insert_font_id(&mut self, handle: &Handle<Font>, font: &Font) -> FontId {
 | |
|         let brush = &mut self.brush;
 | |
|         *self
 | |
|             .map_font_id
 | |
|             .entry(handle.id())
 | |
|             .or_insert_with(|| brush.add_font(handle.clone(), font.font.clone()))
 | |
|     }
 | |
| 
 | |
|     #[allow(clippy::too_many_arguments)]
 | |
|     pub fn queue_text(
 | |
|         &mut self,
 | |
|         fonts: &Assets<Font>,
 | |
|         sections: &[TextSection],
 | |
|         scale_factor: f64,
 | |
|         text_alignment: TextAlignment,
 | |
|         linebreak_behaviour: BreakLineOn,
 | |
|         bounds: Vec2,
 | |
|         font_atlas_set_storage: &mut Assets<FontAtlasSet>,
 | |
|         texture_atlases: &mut Assets<TextureAtlas>,
 | |
|         textures: &mut Assets<Image>,
 | |
|         text_settings: &TextSettings,
 | |
|         font_atlas_warning: &mut FontAtlasWarning,
 | |
|         y_axis_orientation: YAxisOrientation,
 | |
|     ) -> Result<TextLayoutInfo, TextError> {
 | |
|         let mut scaled_fonts = Vec::new();
 | |
|         let sections = sections
 | |
|             .iter()
 | |
|             .map(|section| {
 | |
|                 let font = fonts
 | |
|                     .get(§ion.style.font)
 | |
|                     .ok_or(TextError::NoSuchFont)?;
 | |
|                 let font_id = self.get_or_insert_font_id(§ion.style.font, font);
 | |
|                 let font_size = scale_value(section.style.font_size, scale_factor);
 | |
| 
 | |
|                 scaled_fonts.push(ab_glyph::Font::as_scaled(&font.font, font_size));
 | |
| 
 | |
|                 let section = SectionText {
 | |
|                     font_id,
 | |
|                     scale: PxScale::from(font_size),
 | |
|                     text: §ion.value,
 | |
|                 };
 | |
| 
 | |
|                 Ok(section)
 | |
|             })
 | |
|             .collect::<Result<Vec<_>, _>>()?;
 | |
| 
 | |
|         let section_glyphs =
 | |
|             self.brush
 | |
|                 .compute_glyphs(§ions, bounds, text_alignment, linebreak_behaviour)?;
 | |
| 
 | |
|         if section_glyphs.is_empty() {
 | |
|             return Ok(TextLayoutInfo::default());
 | |
|         }
 | |
| 
 | |
|         let mut min_x: f32 = std::f32::MAX;
 | |
|         let mut min_y: f32 = std::f32::MAX;
 | |
|         let mut max_x: f32 = std::f32::MIN;
 | |
|         let mut max_y: f32 = std::f32::MIN;
 | |
| 
 | |
|         for sg in §ion_glyphs {
 | |
|             let scaled_font = scaled_fonts[sg.section_index];
 | |
|             let glyph = &sg.glyph;
 | |
|             min_x = min_x.min(glyph.position.x);
 | |
|             min_y = min_y.min(glyph.position.y - scaled_font.ascent());
 | |
|             max_x = max_x.max(glyph.position.x + scaled_font.h_advance(glyph.id));
 | |
|             max_y = max_y.max(glyph.position.y - scaled_font.descent());
 | |
|         }
 | |
| 
 | |
|         let size = Vec2::new(max_x - min_x, max_y - min_y);
 | |
| 
 | |
|         let glyphs = self.brush.process_glyphs(
 | |
|             section_glyphs,
 | |
|             §ions,
 | |
|             font_atlas_set_storage,
 | |
|             fonts,
 | |
|             texture_atlases,
 | |
|             textures,
 | |
|             text_settings,
 | |
|             font_atlas_warning,
 | |
|             y_axis_orientation,
 | |
|         )?;
 | |
| 
 | |
|         Ok(TextLayoutInfo { glyphs, size })
 | |
|     }
 | |
| }
 |