imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Text customization to support disable, underline, strikethrough, hili…

Open ForrestFeng opened this issue 2 years ago • 15 comments

Change color within text / colored text

Enhanced the ImGui::TextUnformated() method to make it support arbitrary text color, underline, strikethrough, highlight, mask. This makes the imgui text more expressive.

Please check the demo/result

ForrestFeng avatar May 05 '22 04:05 ForrestFeng

Hello! Thanks for the PR. Could you post the demo/result and images here too simply?

ocornut avatar May 05 '22 07:05 ocornut

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 substring 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 within 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 avatar May 05 '22 08:05 ForrestFeng

Add one more video for this feature.

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

ForrestFeng avatar May 05 '22 08:05 ForrestFeng

Hello! Thanks for the PR. Could you post the demo/result and images here too simply?

The demo/result and images are copied here. Hope it be useful for others who need this feature.

I may mistakenly close this PR. I do not know how to open it again.

ForrestFeng avatar May 05 '22 08:05 ForrestFeng

Seems there are some warnings are treated as errors. Should I fix them and update the PR again?

ForrestFeng avatar May 05 '22 09:05 ForrestFeng

Awesome work! (btw I only skimmed through it, it's not a full review)

Just a question, do you have any idea about the performance impact when the PR's features are not used? Does it change anything?

Namek avatar Sep 17 '22 10:09 Namek

May I ask (cause I am in the process of making use quite bit of the TextColoring mechanisms) if this entire topic is still WIP or safely useable? thanks.

CodingMadness avatar Oct 27 '22 22:10 CodingMadness

May I ask (cause I am in the process of making use quite bit of the TextColoring mechanisms) if this entire topic is still WIP or safely useable? thanks.

It is still WIP. Not merged to master branch yet.

ForrestFeng avatar Nov 23 '22 02:11 ForrestFeng

Awesome work! (btw I only skimmed through it, it's not a full review)

Just a question, do you have any idea about the performance impact when the PR's features are not used? Does it change anything?

Thanks for reviewing. For the performance impacts:

  1. There is no performace impact if no customization is applied to the text.
  2. If the text customization is applied, the cost is just some line segments (underlines, strikethroughs) and some filled rectangles(highlight, masks) depends on how many customization applied. The performance should be not a issue in my opinion.

ForrestFeng avatar Nov 23 '22 06:11 ForrestFeng

@ForrestFeng I have a question about this feature: how does it interact with TreeNode? In #728 it shows that it's possible to colour the text by pushing a style: great, but it doesn't work if one wants to have more fancy colouring in the label.

Fuuzetsu avatar Nov 28 '22 02:11 Fuuzetsu

@ForrestFeng I have a question about this feature: how does it interact with TreeNode? In #728 it shows that it's possible to colour the text by pushing a style: great, but it doesn't work if one wants to have more fancy colouring in the label.

Just to be super clear on what I mean, here's what we can do today just be setting styles and calling Text without spacing in between:

vvv

The question is whether this PR will let us do anything about those uncoloured nodes that are currently TreeNode labels.

Fuuzetsu avatar Nov 28 '22 02:11 Fuuzetsu

@ForrestFeng I have a question about this feature: how does it interact with TreeNode? In #728 it shows that it's possible to colour the text by pushing a style: great, but it doesn't work if one wants to have more fancy colouring in the label.

Just to be super clear on what I mean, here's what we can do today just be setting styles and calling Text without spacing in between:

vvv

The question is whether this PR will let us do anything about those uncoloured nodes that are currently TreeNode labels.


@Fuuzetsu to avoid misunderstanding can you provide a sample code for what you did on the TreeNode labels? So that I can try to recreate it in my way.

Thanks for your comments.

ForrestFeng avatar Nov 28 '22 05:11 ForrestFeng

@Fuuzetsu to avoid misunderstanding can you provide a sample code for what you did on the TreeNode labels? So that I can try to recreate it in my way.

Actually, I had a look at some of the existing applications linked in imgui README and saw that they are doing exactly what I want.

I'm using rust bindings so I apologise but it seems I can do something like this:

                    let node = TreeNode::new(&ident)
                        .label::<&str, &str>(&lbl)
                        // Don't render arrow unless we're aggregating orders.
                        .leaf(!is_aggregate);

                    let open = node.push(ui);
                    draw_ctx.ui.same_line_with_spacing(0.0, 0.0);
                    draw_ctx.ui.text_colored(
                        imgui_utils::srgb_f32!(#7e77c8).as_imcolor32f(),
                        "XXXXXXXXXXXX",
                    );

to produce "fancy" partially style labels. So feel free to ignore me, I answered my own question and I think the work here doesn't need to worry about TreeNode at all: one would just use your TextUnformatted as normal and it'll just work. Sorry for the noise.

col

Fuuzetsu avatar Nov 29 '22 00:11 Fuuzetsu

The newly released imgui_test_engine/ repo in the test suite include performance comparaison tools. In Test Engine UI check the “Perfs” tabs. You can compare multiple branches and use the perf tool to visualize the results of all runs.

Performance should be compared for both optimized and non-optimized builds.

ocornut avatar Dec 13 '22 05:12 ocornut

I will be spending a little time evaluating some of the ideas from #5288 (here) and #3130 (and #902), they are similar in essence and both PR are giving a good amount of ideas and starting points.

I think we need to standardize a set of modifiers while being able to:

  • specify them inline (e.g. within a literal string)
  • specify them as external modifiers (driven by code and/or data). this has been the approach of both PR but whereas it is a definitive requirement for formatting external data (think InputText() syntax highlight), many typical use cases would likely be best embedded inline in strings.
  • and as with what I mentioned in https://github.com/ocornut/imgui/pull/4251#issuecomment-1377418580 it is essential we tick all the boxes of flexibility, maintainability, ease of use, performances.

Thanks for this!

ocornut avatar Jan 10 '23 15:01 ocornut