-
-
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
Multiple TextWrapped + SameLine #2313
Comments
Hello @Unit2Ed and thanks for the details. I understand the problem. For a similar issue discussed in the past (not on the github) I had this noted as a shy I think it is probable that we can eventually add this parameter in The reason is - I'm currently accumulating list of TODO related to text/font functions and I expect to do larger refactor of them at some point. There's maybe a dozen of desirable text/font changes and it would be saner to tackle them together and maybe redesign the API of those low-level functions instead of adding more parameters. Underline? (Some of my recent not-published work on performance measurement are partly ground work to allow me to do this refactor backed by metrics about performance regression - namely because functions like Juliette and Doug who are making the game Avoyd have made a Markdown renderer for dear imgui and stumbled on the same problem as you did. They may have a workaround or might be tempted to share their code as-is. There's a work-around in the form of calling CalcWordWrapPositionA yourself and only submitting the text until the end of the line, but modifying the function as you did is a better approach. I'll keep this in mind and will see if I can tackle a similar feature (perhaps adding a Markdown function in the imgui_club repository would be nice). For future reference: same test case with simple compilation fix (color was missing from the Segment constructor + using ImU32 and IM_COL32, and // And this is my test case
if (ImGui::Begin("Text Test", nullptr, ImGuiWindowFlags_NoTitleBar))
{
struct Segment
{
Segment(const char* text, ImU32 col = 0, bool underline = false)
: textStart(text)
, textEnd(text + strlen(text))
, colour(col)
, underline(underline)
{}
const char* textStart;
const char* textEnd;
ImU32 colour;
bool underline;
};
Segment segs[] =
{
Segment("this is a really super duper long segment that should wrap all on its own "),
Segment("http://google.com", IM_COL32(127,127,255,255), true),
Segment(" Short text "),
Segment("http://github.com", IM_COL32(127,127,255,255), true)
};
ImGui::TextColored(ImColor(0, 255, 0, 255), "Half-manual wrapping");
const float wrapWidth = ImGui::GetWindowContentRegionWidth();
for (int i = 0; i < IM_ARRAYSIZE(segs); ++i)
{
const char* textStart = segs[i].textStart;
const char* textEnd = segs[i].textEnd ? segs[i].textEnd : textStart + strlen(textStart);
ImFont* Font = ImGui::GetFont();
do
{
float widthRemaining = ImGui::CalcWrapWidthForPos(ImGui::GetCursorScreenPos(), 0.0f);
const char* drawEnd = Font->CalcWordWrapPositionA(1.0f, textStart, textEnd, wrapWidth, wrapWidth - widthRemaining);
if (textStart == drawEnd)
{
ImGui::NewLine();
drawEnd = Font->CalcWordWrapPositionA(1.0f, textStart, textEnd, wrapWidth, wrapWidth - widthRemaining);
}
if (segs[i].colour)
ImGui::PushStyleColor(ImGuiCol_Text, segs[i].colour);
ImGui::TextUnformatted(textStart, textStart == drawEnd ? nullptr : drawEnd);
if (segs[i].colour)
ImGui::PopStyleColor();
if (segs[i].underline)
{
ImVec2 lineEnd = ImGui::GetItemRectMax();
ImVec2 lineStart = lineEnd;
lineStart.x = ImGui::GetItemRectMin().x;
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, segs[i].colour);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly))
ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput);
}
if (textStart == drawEnd || drawEnd == textEnd)
{
ImGui::SameLine(0.0f, 0.0f);
break;
}
textStart = drawEnd;
while (textStart < textEnd)
{
const char c = *textStart;
if (ImCharIsBlankA(c)) { textStart++; }
else if (c == '\n') { textStart++; break; }
else { break; }
}
} while (true);
}
ImGui::NewLine();
ImGui::Separator();
ImGui::TextColored(ImColor(0, 255, 0, 255), "Broken native wrapping");
ImGui::PushTextWrapPos(ImGui::GetContentRegionAvailWidth());
for (int i = 0; i < sizeof(segs) / sizeof(segs[0]); ++i)
{
ImGui::TextUnformatted(segs[i].textStart, segs[i].textEnd);
ImGui::SameLine();
}
ImGui::PopTextWrapPos();
}
ImGui::End(); |
Our workaround for markdown is in this gist: https://gist.github.com/dougbinks/65d125e0c11fba81c5e78c546dcfe7af We plan to remove the internal code dependencies and make this available at some point but have been a bit saturated with work, but hopefully it's understandable. The bulk of the work you would need is in the RenderTextWrapped function. |
Links to this in action: https://twitter.com/dougbinks/status/1005779748407119872 We'll try and open source this properly this week. |
We've updated the gist to remove dependencies, and will open source this properly later. |
Thank you for the detailed response @ocornut (the missing colour constructor param was because I'd considered removing that feature from the snippet to make it more concise, but decided against it and forgot I'd already started removing it - sorry about that!). I believe that in the short term I'll do as you suggest - maintain & extend the sample I showed to add support for the formatting features I need (as it already mostly works). On the side I'll experiment locally with what a native solution might look like; I believe changing TextWrapPosStack to a start/end pair (with PushTextWrapPos defaulting the start to the current CursorX), and then tweaking how CalcWrapWidthForPos/CalcTextSize are used, would do the trick. Multiple calls to TextWrapped would produce the same results as they do now, but manual Push/PopTextWrapPos sandwiching regular Text calls would produce a nice flow of text. Thank you for the gist @dougbinks; markdown support is something I've been considering too, so this sample will be useful. |
Following up on @dougbinks' comment we've open-sourced imgui_markdown. |
On the off chance that this hasn't been suggested before, may I suggest a This is the OP's example with this imagined API. ImGui::BeginText("TextID", ImGuiTextFlagsWrap|ImGuiTextFlagsSameLine);
ImGui::Text("this is a really super duper long segment that should wrap all on its own ");
ImGui::SimpleButton("http://google.com"); // style it to look like a hyperlink if you want
ImGui::Text(" Short text ");
ImGui::SimpleButton("http://github.com");
ImGui::EndText(); |
@ocornut I currently have the exact issue in my code with textwrapping occuring very wierdly at the edge of the window-width. Is there any news to this how to make text-spans properly wrap for next lines ? Any help on this is much appreciated. |
Version/Branch of Dear ImGui:
Version: 1.60
Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_dx11cpp
My Issue/Question:
I'm attempting to change formatting in the middle of a block of text, to support hyperlinks, emoji, colouring etc.
Rather than rely on a built-in markup system (eg #902) I determine the formatting externally and issue multiple ImGui commands to produce the text I need. This is fine when you don't want the text to wrap, but it becomes tricky if you use SameLine with wrapping because each subsequent command attempts to squeeze into the remaining space at the edge of the window, which grows smaller and smaller.
So far I've got it working by using CalcWrapWidthForPos/CalcWordWrapPositionA/TextUnformatted, and it works quite well. I've made a slight modification to CalcWordWrapPositionA - passing in a line_start parameter that sets the line_width local for the start position of only the first line (eg start the first line at 500, and wrap at 600, causing the second line to start back at 0). The screenshot below shows this in action, and what an equivalent sequence of PushWrapPos+TextUnformatted+SameLine commands looks like at the moment.
The code I've written to do this is quite verbose; it would be possible to wrap it up, but I think there's the possibility of integrating something like this line_start parameter deeper into ImGui so that it can do it natively.
Do you think integrating this concept deeper into ImGui is a good idea?
Do you have a better idea of how to accomplish this complex text formatting?
I'd appreciate any input you've got on this. Thank you!
Screenshots/Video
Standalone, minimal, complete and verifiable example: (see #2261)
The text was updated successfully, but these errors were encountered: