-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change color within text / colored text #902
Comments
You'd need to write a custom function that does some sort of mark-down-ish parsing and render as it goes. |
I have a simple one I made for my own use on a project but it's not really fit for use elsewhere. You can grab here but it'd need fixing/reworking/finishing if you want to use it in your own project. |
The difficulty with it as a separate top-level function is that many ImGui functions take text as an argument (e.g. buttons, trees). I think that ImGui needs some kind of standard escape mechanism even if the particulars are left up to the application to interpret the content. |
That's a good point, we could have an escape mecanism for simple stuff (such as color change?), maybe with the possibility of enabling/disabling/setting a custom one. What sort of feature would you want to use and in what sort of context? |
Also worth reminding that text size calculation can be a noticeable bottleneck for large UI and therefore this has to be handled properly to not affect perfs too much. If the marking/escaping mechanism is optional it gives more flexibility there (because we aren't concerned by performances as much anymore). Related because closely related: the shortcut system (#456) will also needs a way to render underscore, probably tagged Windows-style where "&File" will render an underscore under the F, potentially optional (for regular buttons, modern Windows tends to hide the underscore using ALT is held). |
About text size calc maybe worth doing some caching. Most of the strings being rendered will be fixed and be rendered again every frame. |
Would be worth it.
So that's some work and a different feature that discussed here. Something to keep in mind. For now implementing the marking/escaping would go first. |
Note that current text size computation is already fairly lightweight (inner loop pulling from a hot-only dense array of XAdvance values), so replacing it with Hash + Lookup isn't going to be trivial massive win. |
The main one I want has been highlighting a search substring in lists/trees. The escape mechanism feels like it fits in the best with ImGui design because so many entrypoints take strings as parameters. |
Possible features:
And what would be the syntax? Feels like using |
ANSI escape codes cover that feature set so that's one possibility. If some other syntax is used, I'd prefer some non-printable character so that all existing strings continue to work without change. |
Having something similar to BBCode would be amazing. |
Are you suggesting you would want it applied pervasively or as a separate entrypoint? I'd be concerned if something like BBCode/Markdown/HTML were applied at the lowest level of string formatting as escaping source data is a lot more annoying/expensive with an immediate mode API. |
since I am familiar with ANSI escape codes, that one gets my vote |
I am curious. Is there any update about this topic? |
None. Someone may want to get ahead toward a proof of concept. I know it'll take me too much time (several full days) to do it totally properly and with perf/options I'm happy with, so I'm not looking into it at all now. |
Note that #986 is suggesting using a similar feature during text edition.
I don't think the suggested solution would be appropriate, but we can keep in mind and consider how coloring might work in text edition in the future. |
Finally for the moment i use a special buffer who have the same length as the buffer of the text multi line control. and each char corresponding to a color settings in an array in ImGuiStyle.
So i have 254 possibility of coloration. My function analyse the buffer by the callback when i edit some things and format the color of words in the special buffer passed to the multi-line control. and in void ImFont::RenderText, i do that : the buffer is a 'const char* syncol'
It work like a charm. so now i need to write a good syntax coloring func for my needs :) |
In Overgrowth I added the ##FFFFFFFF style coloring like this: https://gist.github.com/David20321/9e349d197b19e4919614652e4c0d175b Doesn't work for editable text, just for display. |
Actually, I was going to implement this myself with my own copy. ;) Perhaps along with embedding icons inside text, but I doubt that would ever be added. |
Your game looks amazing! Would be nice if you could post some shots showcasing your use of imgui in the screenshots threads sometime.
Merging an icon font such as FontAwesome into the main font is very easy and very very useful. Read the documentation in extra_font. I am using https://github.com/juliettef/IconFontCppHeaders as a helper to get |
@ocornut That's possible, but then you can't have icons using multiple colours, can you? But then, I'm not sure why anyone would want full-colour icons outside of development tools. |
@bluebear94 You can't indeed. Give it a try someday, using FontAwesome merged within ImGui default font, it's really super convenient. Considering adding it to the demo app. |
I have a bit of a hack I'm using that works alright for my purposes (a read-only multiline buffer.) Not industrial-grade, but here goes:
Then, use Unicode 0x100rgb to represent your color (0x108000 resets to default color.) |
Hi there! I just wanted to share my simple solution to embed colors in ImGui text. I basically parse the string while accumulating characters and looking for inline color blocks. When found I extract the color, then I simply use The code supports 6-char colors (RGB), and 8-char colors (ARGB). Using an empty color block simply returns to the default color. You can find the code here on PasteBin. Here's how it's used, using "{" and "}" to mark colors:
That's a pretty simple solution that works only for regular text, but that's all we really needed for now. |
I made a simple edit to RenderText to support Quake style color codes. It's rather simple, ^ is used as an escape followed by an index into the color code list.
There's unfortunately some cursor funkiness in my input fields, I'll update the comment when I get around to fixing it. Edit: Here we go, changing InputTextCalcTextSizeW seems to have worked out. If anyone thinks there's a better way I'm all ears.
|
@ddovod I have made a port of this functionality on a fork of |
I wish we could have inline color commands to make the type darker, but that doesn't exist (yet) without custom solutions ocornut/imgui#902
Colorful text. Type the character you have specified for the color you want after the $ sign. Example: static const auto& code = R"($r#include $y<iostream>
$busing namespace $wstd$l; $d// for easy
$bauto $wmain$l() -> $bint $l{
$pif $l($o2 $l+ $o2 $l== $o4$l)
$wcout $l<< $f"Hello, World." $l<< $m'\n'$l;
$preturn $o0$l;
};
)";
static const ImVec4&
white = { 1,1,1,1 },
blue = { 0.000f, 0.703f, 0.917f,1 },
red = { 0.976f, 0.117f, 0.265f ,1 },
grey = { 0.230f, 0.226f, 0.289f,1 },
lgrey = { 0.630f, 0.626f, 0.689f,1 },
green = { 0.000f, 0.386f, 0.265f,1 },
lime = { 0.55f, 0.90f, 0.06f,1 },
yellow = { 0.91f, 1.00f, 0.21f,1 },
purple = { 1,0,1,1 },
orange = { 1.00f, 0.36f, 0.09f,1 };
ColorfulText(code, {
{'w', white},
{'b', blue},
{'d', grey},
{'l', lgrey},
{'f', green},
{'m', lime},
{'y', yellow},
{'p', purple},
{'r', red},
{'o', orange}
}); Souce Codeusing str = std::string;
template <typename T>
using list = std::pmr::vector<T>;
namespace im = ImGui;
void ColorfulText(const str& text, const list<pair<char, ImVec4>>& colors = {}) {
auto p = im::GetCursorScreenPos();
const auto first_px = p.x, first_py = p.y;
auto im_colors = ImGui::GetStyle().Colors;
const auto default_color = im_colors[ImGuiCol_Text];
str temp_str;
struct text_t {
ImVec4 color;
str text;
};
list<text_t> texts;
bool color_time = false;
ImVec4 last_color = default_color;
for (const auto& i : text) {
if (color_time) {
const auto& f = std::find_if(colors.begin(), colors.end(), [i](const auto& v) { return v.first == i; });
if (f != colors.end())
last_color = f->second;
else
temp_str += i;
color_time = false;
continue;
};
switch (i) {
case '$':
color_time = true;
if (!temp_str.empty()) {
texts.push_back({ last_color, temp_str });
temp_str.clear();
};
break;
default:
temp_str += i;
};
};
if (!temp_str.empty()) {
texts.push_back({ last_color, temp_str });
temp_str.clear();
};
float max_x = p.x;
for (const auto& i : texts) {
im_colors[ImGuiCol_Text] = i.color;
list<str> lines;
temp_str.clear();
for (const auto& lc : i.text) {
if (lc == '\n') {
lines.push_back(temp_str += lc);
temp_str.clear();
}
else
temp_str += lc;
};
bool last_is_line = false;
if (!temp_str.empty())
lines.push_back(temp_str);
else
last_is_line = true;
float last_px = 0.f;
for (const auto& j : lines) {
im::RenderText(p, j.c_str());
p.y += 15.f;
last_px = p.x;
max_x = (max_x < last_px) ? last_px : max_x;
p.x = first_px;
};
const auto& last = lines.back();
if (last.back() != '\n')
p.x = last_px;
else
p.x = first_px;
if (!last_is_line)
p.y -= 15.f;
if (i.text.back() != '\n')
p.x += im::CalcTextSize(last.c_str()).x;
};
im_colors[ImGuiCol_Text] = default_color;
im::Dummy({ max_x - p.x, p.y - first_py });
}; |
Change color within text / colored text I have enhanced the ImGui::TextUnformated() method to make it support arbitrary text color, underline, strikethrough, highlight, mask I aslo add one demo for this feature. The code for the demo is shown below. The new TextUnformatted signature was changed to support this feature. The wrapped, disabled, and customization are newly added args with default values. So it should be compatible with existing code.
Those text styles are all with a text and can be combined as needed. Here is another demo. It allows the user to adjust the ranges to apply a style and see the result. The code is on Text Customization Branch Any comments please let me know. If it is possible I will create a pull request when ready. Thanks. |
Add one more video for this feature. ImGui.Text.Customization.Video_2022-05-04_132237.mp4 |
This currently maps to coloring the text red. When ImGui's ticket ocornut/imgui#902 is resolved, one can look into supporting additional markup. For now, this should be sufficient.
Still seems to be a lot of interest in this. Has support for this been pulled into the official ImGui yet? |
I'm a little puzzled why many people are writing messages on an open pull-request or issues asking if the PR/issue has been solved :) no it hasn't. But I have been recently working on new low-level text functions and I am confident we can make interesting progress on this in the coming quarters (borrowing some ideas from #3130 and #5288 but with a different implementation). |
That's awesome! Personally, I hope that any official support for this can be customized; many people already seem to have this "hacked in" with their own syntax. For example, in my case this would be Additionally, I also implemented text shadow using the |
I don't have answer for this yet A few things that are certain:
Uncertain but obviously desirable:
|
Example of ANSI text rendering:
Maybe use these as an idea for text colours. They are a bit old, so they might be incompatible with recent ImGui versions. |
has there been any progress on this? |
This read might clear up some of the confusion: If you consider the impact on performance, general usability (instead of just a single use case) and API simplicity, something as complex as syntax highlighting is not an easy fix at all. To do it correctly, some internal stuff has to be rewritten. If you look at the linked thread, you will see "Better Text Functions" (item 6.2), that would be a prerequisite and one of its goals is to allow for color markup. But even if it would take just a week to implement correctly, it would still have to compete for time and attention with tons of other "small things". And all of those things have to compete with activities like eating and sleeping as well. |
It's not a feature that we can do half-right because it would be very hard to go backward and perform incremental updates after people start using it. I am hoping to make progress on it within the next 12 months. |
A while ago I ended up implementing a new // this takes e.g. #f00 (RGB, alpha 255) or e.g #fff8 (for RGBA), and the double precision versions
ImGui::TextAttr("{#fff}Row {#f00}%d {#fff}is {#0000ff}%s {#fff}and {#ff880088}orange transparent", 2, "blue"); which calls void ImGui::TextAttr(const char* fmt, ...) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
va_list args;
va_start(args, fmt);
const char *text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
TextEx(text, text_end, ImGuiTextFlags_ParseColors);
va_end(args);
} A few changes to ImGui is awesome, it's super trivial to extend. Also made a skin system for it using nine-slices, epically simple. Kudos to @ocornut ! |
@marcakafoddex nice, and can you show your modification of TextEx ? |
Sure, check the commit in the fork i just made a few notes:
|
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: 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: <color_yellow>1.00</color> L Weight: <color_yellow>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 #2313 (comment). 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 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! |
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.
The text was updated successfully, but these errors were encountered: