Skip to content

add coloring per text section in gizmos#23120

Open
nuts-rice wants to merge 4 commits intobevyengine:mainfrom
nuts-rice:main
Open

add coloring per text section in gizmos#23120
nuts-rice wants to merge 4 commits intobevyengine:mainfrom
nuts-rice:main

Conversation

@nuts-rice
Copy link

@nuts-rice nuts-rice commented Feb 23, 2026

Objective

Solution

  • Add StrokeTextLayout::render_with_color_fn() to return polyline and color pairing
  • Add text_sections() to build concat string consisting of sections of character-coloring pair
  • Associated helper fn for yielding tuple of (char, Color)
  • replace text field in StrokeTextLayout with sections that is an iterable &'a [(&'a str, Color)]

Testing

  • Ran cargo test for gizmos
  • Prolly could use an example

Showcase

Example Usage:

gizmos.text_sections(iso, [
      ("Hello ", Color::WHITE),
      ("World!", Color::srgb(1., 0., 0.)),
  ], 25., Vec2::ZERO);

@github-actions
Copy link
Contributor

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Gizmos Visual editor and debug gizmos A-Text Rendering and layout for characters S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 23, 2026
@alice-i-cecile alice-i-cecile added this to the 0.19 milestone Feb 23, 2026
Copy link
Contributor

@ickshonpe ickshonpe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is pretty good, the only problem is the extra allocations, which should be avoidable if StrokeTextLayout's text: &str field is replaced with a slice or iterator. Then make a function, something like:

fn colored_chars(s: &[(&str, Color)]) -> impl Iterator<Item = (char, Color)> {
    s.into_iter()
        .map(|(t, color)| t.chars().map(|c| (c, *color)))
        .flatten()
}

that maps the sections to an iterator that yields the individual chars and their colors for rendering.

Comment on lines 357 to 373

/// Builds a parallel per-character color array.
fn build_sections<S: AsRef<str>, C: Into<Color>>(
sections: impl IntoIterator<Item = (S, C)>,
) -> (String, Vec<Color>) {
let mut full_text = String::new();
let mut char_colors: Vec<Color> = Vec::new();
for (text, color) in sections {
let text = text.as_ref();
let color: Color = color.into();
full_text.push_str(text);
for _ in text.chars() {
char_colors.push(color);
}
}
(full_text, char_colors)
}
Copy link
Contributor

@ickshonpe ickshonpe Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything else is fine, but we don't want the extra allocations from this function. Instead of this, you could just replace the Chars iterator that is created at the start of the render function with an iterator that yields (char, Color) tuples.

where
F: Fn(usize) -> Color + 'a,
{
let mut chars = self.text.chars();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of StrokeTextLayout's text field being an &str, it could be a Clone + IntoIterator<Item = (&'a str, Color)> or just an (&'str, Color) slice. Then it just needs another function that takes an (&'a str, Color) iterator and yields a sequence of (char, Color)s. So this line would become something like:

Suggested change
let mut chars = self.text.chars();
let mut colored_chars = self.colored_chars();

Comment on lines 161 to 162
let c = chars.next()?;
let char_color = color_fn(char_idx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then here, the iterator yields the char and color together:

Suggested change
let c = chars.next()?;
let char_color = color_fn(char_idx);
let (c, char_color) = colored_chars.next()?;

and everything else should work?

@ickshonpe
Copy link
Contributor

Sorry was really tired last night and my review comments were kind of rambling, hopefully you get the idea though.

@nuts-rice
Copy link
Author

you're alright, gonna resolve them soon

@ickshonpe ickshonpe added the M-Release-Note Work that should be called out in the blog due to impact label Feb 24, 2026
@github-actions
Copy link
Contributor

It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note.

Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes.

Copy link
Contributor

@ickshonpe ickshonpe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now, everything seems to work:

success

Just needs the text_gizmos.md release note to be updated to include these changes, and I think the uncolored render function should be removed as not useful.


/// Returns an iterator over the font strokes for this text layout, grouped into polylines
/// of `Vec2` points, each paired with its color from the text sections.
pub fn render_colored(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn render_colored(
pub fn render(

Comment on lines 112 to 116
/// Returns an iterator over the font strokes for this text layout,
/// grouped into polylines of `Vec2` points.
pub fn render(&'a self) -> impl Iterator<Item = impl Iterator<Item = Vec2>> + 'a {
let mut chars = self.text.chars();
let mut x = 0.0;
self.render_colored().map(|(_, stroke)| stroke)
}
Copy link
Contributor

@ickshonpe ickshonpe Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't seem like this function is useful anymore, should just delete it and rename the other one back to render I think.

@@ -4,11 +4,12 @@ authors: ["@ickshonpe"]
pull_requests: [22732]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pull_requests: [22732]
pull_requests: [22732, 23120]

@@ -4,11 +4,12 @@ authors: ["@ickshonpe"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got to add yourself 😄

@nuts-rice nuts-rice force-pushed the main branch 2 times, most recently from ccf1541 to ed05f64 Compare February 24, 2026 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Gizmos Visual editor and debug gizmos A-Text Rendering and layout for characters C-Feature A new feature, making something new possible M-Release-Note Work that should be called out in the blog due to impact S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bevy_gizmos: Multicolored text support.

3 participants