Feature request: support calculating longest string prefix within a wrap-box?
Version/Branch of Dear ImGui:
Version 1.91
Back-ends:
Any
Compiler, OS:
Any
Full config/build information:
No response
Details:
It would be nice if there is a function to calculate the longest string prefix (that fits within wrap area). The API would be like:
const char* CalcTextMaxPrefixWithin(ImVec2 max_size, const char* text, const char* text_end = 0)
(Or const char* CalcTextMaxPrefixWithin(int max_line, float wrap_width, const char* text, const char* text_end = 0);; maybe max-line makes more sense than max-height.)
vvv A barely-working impl for the first version (the time-complexity is unacceptable, and it's not dealing with utf-8). The example code is based on this.
namespace ImGui {
const char* CalcTextMaxPrefixWithin(const ImVec2 max_size, const char* text, const char* text_end = 0) {
const int max_len = text_end ? text_end - text : strlen(text);
for (int len = max_len; len > 0; --len) {
// ?? Un-comment `size.x <= max_size.x &&`, and run `example` (resize window width and see how 'Prefix' changes):
// ?? it seems the result of `CalcTextSize(...).x` can be larger than wrap-width sometimes?
const ImVec2 size = CalcTextSize(text, text + len, false, max_size.x);
if (/*size.x <= max_size.x &&*/ size.y <= max_size.y) {
return text + len;
}
}
return text;
}
} // namespace ImGui
Basically, a correct impl just adds additional comparisions during CalcTextSize (in one pass), but that's not easy to emulate outside of the library.
(Real use case: I defined a tooltip-like widget, and during construction wanted to store the string prefix based on predefined wrap size and line limit.)
Screenshots/Video:
Minimal, Complete and Verifiable Example code:
void example() {
if (ImGui::Begin("Example")) {
static int prefix = 0;
ImGui::Text("Prefix:%d", prefix);
const char* text =
"1111111111\n"
"222222222222222222222222222222222222222222222222\n"
"33\n"
"4444444444444444444444444444444444";
ImGui::InvisibleButton("Canvas", ImMax(ImVec2(1, 1), ImGui::GetContentRegionAvail()));
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const ImVec2 size = ImGui::GetItemRectSize();
ImDrawList* drawlist = ImGui::GetWindowDrawList();
const char* text_end = ImGui::CalcTextMaxPrefixWithin(size, text);
drawlist->AddText(0, 0, min, IM_COL32_WHITE, text, text_end, size.x);
drawlist->AddRect(min, max, IM_COL32_WHITE);
prefix = text_end - text;
}
ImGui::End();
}