Skip to content

Commit

Permalink
add line height to TextFont (#16614)
Browse files Browse the repository at this point in the history
# Objective

- Allow users to customize the line height of text.
- Implements #16085

## Solution

- Add a `line_height` field to `TextFont` to feed into `cosmic_text`'s
`Metrics`.

## Testing

- Tested on my own game, and worked exactly as I wanted.
- My game is only 2D, so I only tested `Text2d`. `Text` still needs
tested, but I imagine it'll work fine.
- An example is available
[here](https://code.cartoon-aa.xyz/Cyborus/custom-line-height-example)

---

## Showcase

<details>
  <summary>Click to view showcase</summary>

With font:
```rust
TextFont {
    font: /* unimportant */,
    font_size: 16.0,
    line_height: None,
    ..default()
}
```


![image](https://github.com/user-attachments/assets/d12d8334-72ae-44b4-9b2e-993bbfd19da6)

With font:
```rust
TextFont {
    font: /* unimportant */,
    font_size: 16.0,
    line_height: Some(16.0),
    ..default()
}
```


![image](https://github.com/user-attachments/assets/6bc843b0-b633-4c30-bf77-6bbad774c1e5)

</details>

## Migration Guide

`TextFont` now has a `line_height` field. Any instantiation of
`TextFont` that doesn't have `..default()` will need to add this field.
  • Loading branch information
Cyborus04 authored Jan 6, 2025
1 parent 27802e6 commit 4ba09f3
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
1 change: 1 addition & 0 deletions crates/bevy_text/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl Plugin for TextPlugin {
app.init_asset::<Font>()
.register_type::<Text2d>()
.register_type::<TextFont>()
.register_type::<LineHeight>()
.register_type::<TextColor>()
.register_type::<TextSpan>()
.register_type::<TextBounds>()
Expand Down
11 changes: 9 additions & 2 deletions crates/bevy_text/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ impl TextPipeline {
// Collect span information into a vec. This is necessary because font loading requires mut access
// to FontSystem, which the cosmic-text Buffer also needs.
let mut font_size: f32 = 0.;
let mut line_height: f32 = 0.0;
let mut spans: Vec<(usize, &str, &TextFont, FontFaceInfo, Color)> =
core::mem::take(&mut self.spans_buffer)
.into_iter()
Expand Down Expand Up @@ -130,6 +131,7 @@ impl TextPipeline {

// Get max font size for use in cosmic Metrics.
font_size = font_size.max(text_font.font_size);
line_height = line_height.max(text_font.line_height.eval(text_font.font_size));

// Load Bevy fonts into cosmic-text's font system.
let face_info = load_font_to_fontdb(
Expand All @@ -146,7 +148,6 @@ impl TextPipeline {
spans.push((span_index, span, text_font, face_info, color));
}

let line_height = font_size * 1.2;
let mut metrics = Metrics::new(font_size, line_height).scale(scale_factor as f32);
// Metrics of 0.0 cause `Buffer::set_metrics` to panic. We hack around this by 'falling
// through' to call `Buffer::set_rich_text` with zero spans so any cached text will be cleared without
Expand Down Expand Up @@ -486,7 +487,13 @@ fn get_attrs<'a>(
.stretch(face_info.stretch)
.style(face_info.style)
.weight(face_info.weight)
.metrics(Metrics::relative(text_font.font_size, 1.2).scale(scale_factor as f32))
.metrics(
Metrics {
font_size: text_font.font_size,
line_height: text_font.line_height.eval(text_font.font_size),
}
.scale(scale_factor as f32),
)
.color(cosmic_text::Color(color.to_linear().as_u32()));
attrs
}
Expand Down
33 changes: 33 additions & 0 deletions crates/bevy_text/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ pub struct TextFont {
/// A new font atlas is generated for every combination of font handle and scaled font size
/// which can have a strong performance impact.
pub font_size: f32,
/// The vertical height of a line of text, from the top of one line to the top of the
/// next.
///
/// Defaults to `LineHeight::RelativeToFont(1.2)`
pub line_height: LineHeight,
/// The antialiasing method to use when rendering text.
pub font_smoothing: FontSmoothing,
}
Expand Down Expand Up @@ -325,11 +330,39 @@ impl Default for TextFont {
Self {
font: Default::default(),
font_size: 20.0,
line_height: LineHeight::default(),
font_smoothing: Default::default(),
}
}
}

/// Specifies the height of each line of text for `Text` and `Text2d`
///
/// Default is 1.2x the font size
#[derive(Debug, Clone, Copy, Reflect)]
#[reflect(Debug)]
pub enum LineHeight {
/// Set line height to a specific number of pixels
Px(f32),
/// Set line height to a multiple of the font size
RelativeToFont(f32),
}

impl LineHeight {
pub(crate) fn eval(self, font_size: f32) -> f32 {
match self {
LineHeight::Px(px) => px,
LineHeight::RelativeToFont(scale) => scale * font_size,
}
}
}

impl Default for LineHeight {
fn default() -> Self {
LineHeight::RelativeToFont(1.2)
}
}

/// The color of the text for this section.
#[derive(Component, Copy, Clone, Debug, Deref, DerefMut, Reflect)]
#[reflect(Component, Default, Debug)]
Expand Down
1 change: 1 addition & 0 deletions examples/dev_tools/fps_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn main() {
font: default(),
// We could also disable font smoothing,
font_smoothing: FontSmoothing::default(),
..default()
},
// We can also change color of the overlay
text_color: OverlayColor::GREEN,
Expand Down

0 comments on commit 4ba09f3

Please sign in to comment.