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
37 changes: 29 additions & 8 deletions crates/bevy_sprite_render/src/text2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use bevy_render::sync_world::TemporaryRenderEntity;
use bevy_render::Extract;
use bevy_sprite::{Anchor, Text2dShadow};
use bevy_text::{
ComputedTextBlock, PositionedGlyph, Strikethrough, TextBackgroundColor, TextBounds, TextColor,
TextLayoutInfo, Underline,
ComputedTextBlock, PositionedGlyph, Strikethrough, StrikethroughColor, TextBackgroundColor,
TextBounds, TextColor, TextLayoutInfo, Underline, UnderlineColor,
};
use bevy_transform::prelude::GlobalTransform;

Expand All @@ -41,7 +41,15 @@ pub fn extract_text2d_sprite(
>,
text_colors: Extract<Query<&TextColor>>,
text_background_colors_query: Extract<Query<&TextBackgroundColor>>,
decoration_query: Extract<Query<(&TextColor, Has<Strikethrough>, Has<Underline>)>>,
decoration_query: Extract<
Query<(
&TextColor,
Has<Strikethrough>,
Has<Underline>,
Option<&StrikethroughColor>,
Option<&UnderlineColor>,
)>,
>,
) {
let mut start = extracted_slices.slices.len();
let mut end = start + 1;
Expand Down Expand Up @@ -153,7 +161,7 @@ pub fn extract_text2d_sprite(
text_layout_info.section_geometry.iter()
{
let section_entity = computed_block.entities()[section_index].entity;
let Ok((_, has_strikethrough, has_underline)) =
let Ok((_, has_strikethrough, has_underline, _, _)) =
decoration_query.get(section_entity)
else {
continue;
Expand Down Expand Up @@ -270,12 +278,21 @@ pub fn extract_text2d_sprite(
text_layout_info.section_geometry.iter()
{
let section_entity = computed_block.entities()[section_index].entity;
let Ok((text_color, has_strike_through, has_underline)) =
decoration_query.get(section_entity)
let Ok((
text_color,
has_strike_through,
has_underline,
maybe_strikethrough_color,
maybe_underline_color,
)) = decoration_query.get(section_entity)
else {
continue;
};
if has_strike_through {
let color = maybe_strikethrough_color
.map(|c| c.0)
.unwrap_or(text_color.0)
.to_linear();
let render_entity = commands.spawn(TemporaryRenderEntity).id();
let offset = Vec2::new(rect.center().x, -strikethrough_y - 0.5 * stroke);
let transform = *global_transform
Expand All @@ -286,7 +303,7 @@ pub fn extract_text2d_sprite(
main_entity,
render_entity,
transform,
color: text_color.0.into(),
color,
image_handle_id: AssetId::default(),
flip_x: false,
flip_y: false,
Expand All @@ -300,6 +317,10 @@ pub fn extract_text2d_sprite(
}

if has_underline {
let color = maybe_underline_color
.map(|c| c.0)
.unwrap_or(text_color.0)
.to_linear();
let render_entity = commands.spawn(TemporaryRenderEntity).id();
let offset = Vec2::new(rect.center().x, -underline_y - 0.5 * stroke);
let transform = *global_transform
Expand All @@ -310,7 +331,7 @@ pub fn extract_text2d_sprite(
main_entity,
render_entity,
transform,
color: text_color.0.into(),
color,
image_handle_id: AssetId::default(),
flip_x: false,
flip_y: false,
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_text/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ pub use text_access::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
Font, Justify, LineBreak, Strikethrough, TextColor, TextError, TextFont, TextLayout,
TextSpan, Underline,
Font, Justify, LineBreak, Strikethrough, StrikethroughColor, TextColor, TextError,
TextFont, TextLayout, TextSpan, Underline, UnderlineColor,
};
}

Expand Down
34 changes: 34 additions & 0 deletions crates/bevy_text/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,11 +430,45 @@ pub enum LineBreak {
#[reflect(Serialize, Deserialize, Clone, Default)]
pub struct Strikethrough;

/// Color for the text's strikethrough. If this component is not present, its `TextColor` will be used.
#[derive(Component, Copy, Clone, Debug, Deref, DerefMut, Reflect, PartialEq)]
#[reflect(Component, Default, Debug, PartialEq, Clone)]
pub struct StrikethroughColor(pub Color);

impl Default for StrikethroughColor {
fn default() -> Self {
Self(Color::WHITE)
}
}

impl<T: Into<Color>> From<T> for StrikethroughColor {
fn from(color: T) -> Self {
Self(color.into())
}
}

/// Add to a text entity to draw its text with underline.
#[derive(Component, Copy, Clone, Debug, Reflect, Default, Serialize, Deserialize)]
#[reflect(Serialize, Deserialize, Clone, Default)]
pub struct Underline;

/// Color for the text's underline. If this component is not present, its `TextColor` will be used.
#[derive(Component, Copy, Clone, Debug, Deref, DerefMut, Reflect, PartialEq)]
#[reflect(Component, Default, Debug, PartialEq, Clone)]
pub struct UnderlineColor(pub Color);

impl Default for UnderlineColor {
fn default() -> Self {
Self(Color::WHITE)
}
}

impl<T: Into<Color>> From<T> for UnderlineColor {
fn from(color: T) -> Self {
Self(color.into())
}
}

/// Determines which antialiasing method to use when rendering text. By default, text is
/// rendered with grayscale antialiasing, but this can be changed to achieve a pixelated look.
///
Expand Down
28 changes: 22 additions & 6 deletions crates/bevy_ui_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ use gradient::GradientPlugin;

use bevy_platform::collections::{HashMap, HashSet};
use bevy_text::{
ComputedTextBlock, PositionedGlyph, Strikethrough, TextBackgroundColor, TextColor,
TextLayoutInfo, Underline,
ComputedTextBlock, PositionedGlyph, Strikethrough, StrikethroughColor, TextBackgroundColor,
TextColor, TextLayoutInfo, Underline, UnderlineColor,
};
use bevy_transform::components::GlobalTransform;
use box_shadow::BoxShadowPlugin;
Expand Down Expand Up @@ -1183,6 +1183,8 @@ pub fn extract_text_decorations(
Query<(
AnyOf<(&TextBackgroundColor, &Strikethrough, &Underline)>,
&TextColor,
Option<&StrikethroughColor>,
Option<&UnderlineColor>,
)>,
>,
camera_map: Extract<UiCameraMap>,
Expand Down Expand Up @@ -1215,8 +1217,12 @@ pub fn extract_text_decorations(
text_layout_info.section_geometry.iter()
{
let section_entity = computed_block.entities()[section_index].entity;
let Ok(((text_background_color, maybe_strikethrough, maybe_underline), text_color)) =
text_background_colors_query.get(section_entity)
let Ok((
(text_background_color, maybe_strikethrough, maybe_underline),
text_color,
maybe_strikethrough_color,
maybe_underline_color,
)) = text_background_colors_query.get(section_entity)
else {
continue;
};
Expand Down Expand Up @@ -1247,6 +1253,11 @@ pub fn extract_text_decorations(
}

if maybe_strikethrough.is_some() {
let color = maybe_strikethrough_color
.map(|sc| sc.0)
.unwrap_or(text_color.0)
.to_linear();

extracted_uinodes.uinodes.push(ExtractedUiNode {
z_order: uinode.stack_index as f32 + stack_z_offsets::TEXT_STRIKETHROUGH,
render_entity: commands.spawn(TemporaryRenderEntity).id(),
Expand All @@ -1259,7 +1270,7 @@ pub fn extract_text_decorations(
strikethrough_y + 0.5 * stroke,
)),
item: ExtractedUiItem::Node {
color: text_color.0.to_linear(),
color,
rect: Rect {
min: Vec2::ZERO,
max: Vec2::new(rect.size().x, stroke),
Expand All @@ -1276,6 +1287,11 @@ pub fn extract_text_decorations(
}

if maybe_underline.is_some() {
let color = maybe_underline_color
.map(|uc| uc.0)
.unwrap_or(text_color.0)
.to_linear();

extracted_uinodes.uinodes.push(ExtractedUiNode {
z_order: uinode.stack_index as f32 + stack_z_offsets::TEXT_STRIKETHROUGH,
render_entity: commands.spawn(TemporaryRenderEntity).id(),
Expand All @@ -1288,7 +1304,7 @@ pub fn extract_text_decorations(
underline_y + 0.5 * stroke,
)),
item: ExtractedUiItem::Node {
color: text_color.0.to_linear(),
color,
rect: Rect {
min: Vec2::ZERO,
max: Vec2::new(rect.size().x, stroke),
Expand Down
8 changes: 6 additions & 2 deletions examples/ui/strikethrough.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This example illustrates UI text with strikethrough

use bevy::{
color::palettes::css::{GREEN, NAVY, RED},
color::palettes::css::{GREEN, NAVY, RED, YELLOW},
prelude::*,
};

Expand Down Expand Up @@ -46,6 +46,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
(
Text::new("struck\nstruckstruck\nstruckstuckstruck"),
Strikethrough,
StrikethroughColor(RED.into()),
TextBackgroundColor(GREEN.into()),
),
(Text::new("underline"), Underline),
Expand Down Expand Up @@ -92,6 +93,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
(
TextSpan::new("\nunderline"),
Underline,
UnderlineColor(YELLOW.into()),
TextFont {
font_size: 30.,
..default()
Expand All @@ -118,7 +120,9 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
Strikethrough,
Underline,
TextColor(RED.into()),
TextBackgroundColor(NAVY.into())
TextBackgroundColor(NAVY.into()),
StrikethroughColor(Color::WHITE),
UnderlineColor(Color::WHITE),
)
]
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ authors: ["@ickshonpe"]
pull_requests: [21555, 21559]
---

`bevy_text` now supports strikethrough and underline. To display text with strikethrough or underline, just add the `Strikethrough` or `Underline` components to any `Text`, `Text2d`, or `TextSpan` entity.
`bevy_text` now supports strikethrough and underline. To display text with strikethrough or underline, just add the `Strikethrough` or `Underline` components to any `Text`, `Text2d`, or `TextSpan` entity. You can set colors for strikethrough and underline using the `StrikethroughColor` and `UnderlineColor` components, respectively.