ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
61.03k stars 10.29k forks source link

Change color within text / colored text #902

Open JLFSL opened 7 years ago

JLFSL commented 7 years ago

Hi there, I was wondering if there was any way to change from color while still using the ::Text function, e.g: ImGui::Text("Please fill in your #FF0000 to #0000FFlogin.");

Thanks.

marcakafoddex commented 2 months ago

@marcakafoddex nice, and can you show your modification of TextEx ?

Sure, check the commit in the fork i just made

a few notes:

db48x commented 1 month ago

I’ve been spending some free time working on a venerable game project. It started out (14 years ago) running in the terminal, using ncurses. Later it started using SDL, with a built‐in ncurses translation layer. Eventually the ncurses compatibility layer was hacked to draw graphical tiles in certain curses windows instead of text. Thus the game has graphics, but only within the narrow confines two specific curses windows, one for the character’s view of the world, and another for the world map. Aside from those two windows, the game is still limited to character cells with a foreground and a background color chosen from a palette of 16 colors. Now I’m troweling some ImGui on over the top, for fun.

Here's a little screenshot of me examining an item (an atomic lamp) from my inventory: Screenshot from 2024-07-22 16-10-15

Only the central menu of actions that I can take is rendered using ImGui, in this screenshot.

As you can see, a major design aesthetic of the game is colorful text. Text which wraps pretty nicely to adapt to different screen sizes. Much of this text is stored in JSON files, where color tags are used. These look a little like HTML: “Volume: 1.00<\/color> L Weight: 3.17<\/color> lbs”, and they can name any combination of the 16 colors as foreground and background. The game also has a lot of ASCII art that is stored in strings using these color codes. A lot of text with color tags is generated at run‐time as well. Obviously to display this text in ImGui I need something like what everyone is talking about in this feature request.

I’ve only started experimenting with my own variation on this theme, but I want to put in my 2¢ anyway. I’ve seen a lot of suggestions for ways to embed styles in text. Markdown, ANSI color codes, etc. Obviously I prefer that whatever text system ImGui gets is something that I can extend to support the huge amount of text that I already have. I can’t just convert it all to markdown!

But more than that, I don't want to be forced to generate strings with embedded codes at run‐time if I don’t have to. I’d prefer an API that allowed me to get the same results without allocating anything.

To that end, I started with the code that @ocornut wrote in https://github.com/ocornut/imgui/issues/2313#issuecomment-458084296. This code defines a struct representing a colored span of text. It runs down a list of these spans, rendering them inline and wrapping to new lines as needed. It works pretty well for what I need, because I can parse strings into spans very easily. I can even store the list of spans to reuse in future frames. Here’s a simple example:

Paragraph stuff = cata_imgui::parse_colored_text( "Some long text that will wrap around nicely. <color_red>Some red text in the middle.</color> Some long text that will wrap around nicely.", c_white );
cata_imgui::TextStyled( stuff );

But it still requires allocation, so I’ve also written a slightly modified version that doesn’t require it. Here’s what that looks like:

cata_imgui::TextParagraph( "Some long text that will wrap around nicely.", c_white );
cata_imgui::TextParagraph( " Some red text in the middle.", c_red );
cata_imgui::TextParagraph( " Some long text that will wrap around nicely.", c_white );

These render and wrap identically.

I’ve posted my code to a gist; please feel free to use it however you want. It includes a demo.

Of course it’s not perfect. The first word of any span wraps differently than the other words, due to a particular choice deep in the text rendering. When less than a whole word fits, it renders as many characters as it can before going to the next line. In this case that’s the wrong choice. As you can see above, spaces between successive spans require some thought; for now I make the user put them in where they are needed but it might be nice if there were a Space() function that advanced by the width of a single space. I also haven't written any Formatted versions of these, but I'll need them to insert numbers where appropriate. There are probably other defects that I’ve completely forgotten or haven’t noticed yet. Speaking of which, I just realized that I put the color argument in the opposite position compared to ImGui::TextColored. I’ll definitely have to fix that before I make a PR.

So those are my requests to add to the list (if they aren’t already there): whatever else you do, let us parse things ourselves and don't forget about the allocation‐free API that we all love.

Thanks!