ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.55k stars 10.15k 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.

ocornut commented 7 years ago

You'd need to write a custom function that does some sort of mark-down-ish parsing and render as it goes. We don't have one, when we have one it'll most probably be a separate function.

ocornut commented 7 years ago

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. ui_richtext.h.txt ui_richtext.cpp.txt

pdoane commented 7 years ago

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.

ocornut commented 7 years ago

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?

ocornut commented 7 years ago

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). That probably means the system would need to accommodate for optional features.

ratchetfreak commented 7 years ago

About text size calc maybe worth doing some caching. Most of the strings being rendered will be fixed and be rendered again every frame.

ocornut commented 7 years ago

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.

ocornut commented 7 years ago

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.

pdoane commented 7 years ago

What sort of feature would you want to use and in what sort of context?

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.

ocornut commented 7 years ago

Possible features:

And what would be the syntax? Feels like using [] would collide too much with normal strings and lead to parsing problems, so \ would be a better start and we can have a push/pop system to enable/disable escaping.

pdoane commented 7 years ago

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.

JLFSL commented 7 years ago

Having something similar to BBCode would be amazing.

pdoane commented 7 years ago

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.

ratzlaff commented 7 years ago

since I am familiar with ANSI escape codes, that one gets my vote https://conemu.github.io/en/AnsiEscapeCodes.html#SGR_Select_Graphic_Rendition_parameters

vivienneanthony commented 7 years ago

I am curious. Is there any update about this topic?

ocornut commented 7 years ago

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.

ocornut commented 7 years ago

Note that https://github.com/ocornut/imgui/issues/986 is suggesting using a similar feature during text edition.

i just need word coloring in the text multi line control.

I hope i can have a string with information about word start, word end, and word color to pass to the multi-line control. like that maybe "start : end : color" => "10:22:#99ccff"

So before the multi-line control i imagine analyse the text and format a special string for it in the ImGuiTextEditCallback

Finally i imagine pass this buffer to a modified version of ImFont::RenderText.

Do you think i may be heavy , maybe you have another way ?

Thanks for your help

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.

aiekick commented 7 years ago

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.

struct ImGuiStyle { ImVec4 SyntaxColors[255]; }

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'

ImGuiStyle& style = ImGui::GetStyle();

ImU32 defaultCol = col;

    while (s < text_end)
    {
        if (syncol != 0)
        {
            col = defaultCol;
            char c = *(syncol + (s - text_begin));
            if (c != '\0')
                col = ImColor(style.SyntaxColors[c]);
        }

It work like a charm. so now i need to write a good syntax coloring func for my needs :)

screenhunter_284

David20321 commented 7 years ago

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.

bluebear94 commented 7 years ago

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.

ocornut commented 7 years ago

@David20321

In Overgrowth

Your game looks amazing! Would be nice if you could post some shots showcasing your use of imgui in the screenshots threads sometime.

@bluebear94

Perhaps along with embedding icons inside text, but I doubt that would ever be added.

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 #define for the various icons.

bluebear94 commented 7 years ago

@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.

ocornut commented 7 years ago

@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.

chadlyb commented 7 years ago

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:

void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
{
    const ImU32 originalCol = col;

    ...
            if (c == '\r')
                    continue;
    }

    if (c >= 0x100000 && c <= 0x10FFFD )
    {
        if ( c == 0x108000 )
        {
            col = originalCol;
        }
        else
        {
            col =   0xFF000000
                  + ((c >> 8) & 0x0F) * 0x00000011
                  + ((c >> 4) & 0x0F) * 0x00001100
                  + ((c     ) & 0x0F) * 0x00110000;
        }
        continue;
    }

    float char_width = 0.0f;
    if (const Glyph* glyph = FindGlyph((unsigned short)c))
    {
    ...

Then, use Unicode 0x100rgb to represent your color (0x108000 resets to default color.) Seems to work well enough for read-only buffers, including cursor navigation and selection, for my purposes.

ldecarufel commented 7 years ago

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 ImGui::Text() and ImGui::SameLine(0,0) to print the accumulated text, I push the new color using ImGui::PushStyleColor(), and I start to accumulate text again. I also use ImGui::PopStyleColor() before pushing a new color if one was pushed before.

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:

const float colPos = 220.0f;
ImGui::TextWithColors( "{77ff77}(A)" ); ImGui::SameLine( colPos ); ImGui::Text( "Press buttons, toggle items" );
ImGui::TextWithColors( "{77ff77}(A){} + DPad Left/Right" ); ImGui::SameLine( colPos ); ImGui::Text( "Manipulate items" );
ImGui::TextWithColors( "{ff7777}(B)" ); ImGui::SameLine( colPos ); ImGui::Text( "Close popups, go to parent, clear focus" );
ImGui::TextWithColors( "{7777ff}(X)" ); ImGui::SameLine( colPos ); ImGui::Text( "Access menus" );

That's a pretty simple solution that works only for regular text, but that's all we really needed for now.

styves commented 7 years ago

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.

void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
{
    const ImU32 alpha = (col >> 24);
    const ImU32 color_codes[9] =
    {
        col,                           // default 0
        ImColor(255,   0,   0, alpha), // red     1
        ImColor(  0, 255,   0, alpha), // green   2
        ImColor(255, 255,   0, alpha), // yellow  3
        ImColor(  0,   0, 255, alpha), // blue    4
        ImColor(  0, 255, 255, alpha), // cyan    5
        ImColor(255,   0, 255, alpha), // magenta 6
        ImColor(255, 255, 255, alpha), // white   7
        ImColor(  0,   0,   0, alpha), // black   8
    };
    ...
    while (s < text_end)
    {
        if (*s == '^' && *(s + 1) && *(s + 1) != '^')
        {
            col = color_codes[(*(s + 1) - '0') % 8];
            s += 2;
            continue;
        }

        if (word_wrap_enabled)
        {
        ...
                y += line_height;
                col = color_codes[0]; // reset color code on new line

                if (y > clip_rect.w)
                ...

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.

static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
{
...
        if (c == '\r')
            continue;
        if (c == '^' && *(s) && *(s) != '^')
        {
            ++s;
            continue;
        }
        const float char_width = font->GetCharAdvance((unsigned short)c) * scale;
        ...
ocornut commented 7 years ago

I don't know if people are getting notification for those, but it looks like my rebase+force pushes on a separate fork spammed this thread with links. Sorry!

FYI This is the solution @mikesart used, which is yet another variation on the ideas above: https://github.com/mikesart/imgui/commit/43471705cfddb941469cf268b18b4ccda49636dc

// ESC + RGBA bytes
if (c == '\033' && s[1] && s[2] && s[3] && s[4])
{
    const unsigned char *us = (const unsigned char *)s;
    col = IM_COL32( us[1], us[2], us[3], us[4] );
    s += 5;
    continue;
}

It has the limitation that individual components cannot be exactly 0 (his emitting function clamps them to 1), but I don't imagine it matters much (or we could treat 1 as 0 in the decoder too). edit and it is less UTF-8 friendly?

Since many of the solutions here share a similar approach, I could possibly allow for 2 macros to be defined to handle that decoding encoding. As long as the escape code only modify the color (and not size/font) the macros will at least minimize conflicts until/if we decide to go for an official solution.

ocornut commented 7 years ago

Here's a proposal for a short-term hacky solution, basically just adding those two blocks:

In CalcWordWrapPositionA() and CalcTextSizeA()

#ifdef IMGUI_TEXT_ESCAPE_SKIP
        IMGUI_TEXT_ESCAPE_SKIP();
#endif

In RenderText():

#ifdef IMGUI_TEXT_ESCAPE_RENDER
        IMGUI_TEXT_ESCAPE_RENDER();
#endif

And we keep it "undocumented" considering is it temporary solution to reducing forks/conflicts.

@styves: I can't imagine your solution working inside an interactive InputText though. I'll keep coloring in mind but when InputText gets rewritten but I think it is a very different problem than discussed here.

styves commented 7 years ago

@ocornut Yeah, I don't expect it to be useful outside of a specific use case (Quake/Steam style username color codes). Something more general or flexible would be much better.

It actually does work just fine in a dynamic InputText, at least with respect to the behavior I was aiming for. A user can write the key combination sequence and change the color of their own text at will, which is exactly the behavior expected from the Quake/Steam approach. However I don't believe such behavior is what you'd want for a general text color solution, where the characters should probably be displayed as normal.

Actually, the whole reason I implemented this particular approach was specifically to support color codes used in Steam usernames.

ocornut commented 6 years ago

I'm hijacking this old open topic just to post the information that BalazsJako created a fairly full-featured code editor widget a few months ago: https://github.com/BalazsJako/ImGuiColorTextEdit

imguitextedit

While this doesn't directly solve the question discussed here (which is still valid), I believe that some users here (including @aiekick) were looking into text coloring this for the purpose of creating a text editor, so this may be useful info.

aiekick commented 6 years ago

great tool. thanks

kavika13 commented 6 years ago

@ocornut not sure if you merged the color hack or not yet, but I commented on the commit, because I believe there's a bug in it for strings that aren't null terminated.

I prefer a \033FF00FFFF (hex for the color components) representation :) Seems more user friendly, especially in my case, where we're exposing dear imgui to modders, and I think it avoids the not-quite-black problem. Of course maybe that's just "wishing for faster horses instead of a car". I'm guessing you might still be interested in that whole custom escape thing instead.

ocornut commented 6 years ago

FYI @kavika13 The commit you commented on is part of gpuvis, it wasn't committed to imgui https://github.com/mikesart/imgui/commit/43471705cfddb941469cf268b18b4ccda49636dc#commitcomment-27016628

I am still interested in this but haven't had time to focus on this.

ddovod commented 5 years ago

https://gist.github.com/ddovod/be210315f285becc6b0e455b775286e1 Here's a gist with ImGui::TextAnsiColored function. Kinda dirty, but it works fine for me. The main part is in the ParseColor and ImFont_RenderAnsiText functions. Actually most of the code is copy-pasted from the original imgui code, just to not touch it. It supports only foreground colors (since there's no easy way to draw background color and bold/reversed/etc ansi formats). Based on this gist https://gist.github.com/David20321/9e349d197b19e4919614652e4c0d175b

Looks like this ansicolors

ocornut commented 5 years ago

While this doesn't cancel/replace the need for a low-level, general mechanism to colorize text, I should mention that @juliettef today released an imgui_markdown helper which would probably satisfy the related need of showing less bland chunk of information:

https://github.com/juliettef/imgui_markdown

imgui_markdown_demo_live_editing

I added it to the wiki and this is also a reminder that however humble there is a wiki gathering links.

Also from this specific tool, I would like to later expose new text colors in ImGuiStyle, namely to denote "highlight/bold" or "link" colors. This is so whatever color changing mechanism we expose should be able to use generic semantic such as "highlight/bold" instead of refering to hardcoded RGB colors. (Of course hardcoded RGB should still be possible, but we want to maximize the style-portability of common uses).

fungos commented 5 years ago

I did a very simple extension implementation for a callback based custom tags processing here (there is more than rich text): https://github.com/ocornut/imgui/compare/docking...fungos:richtitlebar?expand=1 or here with an older but cleaner diff: https://github.com/fungos/imgui/commit/62fe0cfba824b758258c7c38cd643d238a7a51f0

With this, one call like:

if (ImGui::BeginTitleMenuBar("{icon.png} App Main Window Custom Title Bar - {healthbar} - "))

results in this:

sample

This requires two callbacks to be implemented by the user, one wich calculates the area to be drawn for some tag, and another that do the drawing itself. The implementation from this sample is here.

connorjak commented 4 years ago

https://gist.github.com/ddovod/be210315f285becc6b0e455b775286e1 Here's a gist with ImGui::TextAnsiColored function. Kinda dirty, but it works fine for me. The main part is in the ParseColor and ImFont_RenderAnsiText functions. Actually most of the code is copy-pasted from the original imgui code, just to not touch it. It supports only foreground colors (since there's no easy way to draw background color and bold/reversed/etc ansi formats). Based on this gist https://gist.github.com/David20321/9e349d197b19e4919614652e4c0d175b

Looks like this ansicolors

@ddovod I have made a port of this functionality on a fork of pyimgui: https://github.com/connorjak/pyimgui/tree/AnsiText

TYSON-Alii commented 2 years ago

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}
});

image another ss unknown

Souce Code

using 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 });
};
ForrestFeng commented 2 years ago

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.

image

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.

IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL, bool wrapped = false, bool disabled = false, const ImTextCustomization *customization = NULL);

       IMGUI_DEMO_MARKER("Widgets/Text/Text Customization");
        if (ImGui::TreeNode("Text Customization Simple"))
        {
            ImColor red(255, 0, 0, 255);
            ImColor green(0, 255, 0, 255);
            ImColor blue(0, 0, 255, 255);
            ImColor yellow(255, 255, 0, 255); 
            ImColor brown(187, 126, 0, 255);
            ImColor cyan(0, 255, 255, 255);
            ImColor magenta(255, 0, 255, 125);

            const char* text = "The quick red fox jumps over the green box.";
            ImTextCustomization tc;

            ImGui::NewLine();
            ImGui::Text("Color the whole text");            
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Range(text).TextColor(green));

            ImGui::NewLine();
            ImGui::Text("Color the sustring of the text");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text + 14, text + 17).TextColor(red).Range(text + 39, text + 42).TextColor(green));

            ImGui::NewLine();
            ImGui::Text("Underline");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text).Unerline());

            ImGui::NewLine();
            ImGui::Text("Underline with color");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text).Unerline(blue));

            ImGui::NewLine();
            ImGui::Text("Strikethrough");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text).Strkethrough());

            ImGui::NewLine();
            ImGui::Text("Strikethrough with color");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text).Strkethrough(red));

            ImGui::NewLine();
            ImGui::Text("Hilight the text with brown");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text).Highlight(brown));

            ImGui::NewLine();
            ImGui::Text("Mask the text so it is not readable");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text+10, text+17).Mask());

            ImGui::NewLine();
            ImGui::Text("Mask the text with color");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text+10, text+17).Mask(cyan));

            ImGui::NewLine();
            ImGui::Text("Mask the text with semitransparent color");
            ImGui::TextUnformatted(text, NULL, true, false, &tc.Clear().Range(text+10, text+28).Mask(magenta));
            ImGui::NewLine();

            ImGui::TreePop();
        }

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.

image

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.

ForrestFeng commented 2 years ago

Add one more video for this feature.

https://user-images.githubusercontent.com/5875631/166628247-5165460d-cf3d-493b-9ead-e6132b179704.mp4

S-A-Martin commented 1 year ago

Still seems to be a lot of interest in this. Has support for this been pulled into the official ImGui yet?

ocornut commented 1 year ago

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).

codecat commented 1 year ago

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 \$f00Red Text\$zNormal text, but that's very different from what's suggested in this issue.

Additionally, I also implemented text shadow using the \$s syntax, so I wonder how extensible such a system would be.

ocornut commented 1 year ago

I don't have answer for this yet

A few things that are certain:

Uncertain but obviously desirable:

ajh123 commented 1 year ago

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.

pheonixfirewingz commented 1 month ago

has there been any progress on this? not to be rude but how has it taken almost 8 years to add escape code colour support to render coloured text for stuff like syntax highlighting for people who know the code base assume it would be an easy fix? again not trying to be rude just confused.

GamingMinds-DanielC commented 1 month ago

again not trying to be rude just confused.

This read might clear up some of the confusion: https://github.com/ocornut/imgui/issues/7892

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.

ocornut commented 1 month ago

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.

marcakafoddex commented 2 weeks ago

A while ago I ended up implementing a new TextAttr function:

// 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 TextEx and passes a new ImGuiTextFlags_ParseColors flag I added:

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 CalcTextSize related functions (that ignore the color markup), and some very basic parsing in RenderTextWrapped (all only in case the new flag is set), and i can have colored text super easily:

image

ImGui is awesome, it's super trivial to extend. Also made a skin system for it using nine-slices, epically simple. Kudos to @ocornut !

aiekick commented 2 weeks ago

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