16constexpr int kMaxChar = 10000;
17std::array<char, kMaxChar> char_buf;
18std::array<ImU32, kMaxChar> col_buf;
19std::array<bool, kMaxChar> char_skip;
27std::vector<std::string> split(
const std::string& str,
const std::string& delim =
" ")
29 std::vector<std::string> res;
30 std::size_t previous = 0;
31 std::size_t current = str.find(delim);
32 while (current != std::string::npos)
34 res.push_back(str.substr(previous, current - previous));
35 previous = current + delim.length();
36 current = str.find(delim, previous);
38 res.push_back(str.substr(previous, current - previous));
50bool ParseColor(
const char* s, ImU32* col,
int* skipChars)
52 if (s[0] !=
'\033' || s[1] !=
'[')
59 *col = ImGui::ColorConvertFloat4ToU32(ImGui::GetStyleColorVec4(ImGuiCol_Text));
64 if (s[2] ==
'0' && s[3] ==
'm')
66 *col = ImGui::ColorConvertFloat4ToU32(ImGui::GetStyleColorVec4(ImGuiCol_Text));
71 const char* seqEnd = &s[2];
72 while (*seqEnd !=
'm')
77 std::string seq{ &s[2], seqEnd };
79 for (
const auto& el : jet::split(seq,
";"))
81 if (el[0] ==
'3' && el.size() == 2)
88 if (!colorStr.empty())
121 *skipChars =
static_cast<int>(seqEnd - s + 1);
125void ImFont_RenderAnsiText(
const ImFont* font,
126 ImDrawList* draw_list,
130 const ImVec4& clip_rect,
131 const char* text_begin,
132 const char* text_end,
133 float wrap_width = 0.0F,
134 bool cpu_fine_clip =
false)
140 text_end = text_begin + strlen(text_begin);
145 pos.x = IM_FLOOR(pos.x);
146 pos.y = IM_FLOOR(pos.y);
154 const float scale = size / font->FontSize;
155 const float line_height = font->FontSize * scale;
156 const bool word_wrap_enabled = (wrap_width > 0.0F);
157 const char* word_wrap_eol =
nullptr;
160 const char* s = text_begin;
161 if (y + line_height < clip_rect.y && !word_wrap_enabled)
163 while (y + line_height < clip_rect.y && s < text_end)
165 s =
static_cast<const char*
>(memchr(s,
'\n',
static_cast<size_t>(text_end - s)));
166 s = s ? s + 1 : text_end;
174 if (text_end - s > 10000 && !word_wrap_enabled)
176 const char* s_end = s;
178 while (y_end < clip_rect.w && s_end < text_end)
180 s_end =
static_cast<const char*
>(memchr(s_end,
'\n',
static_cast<size_t>(text_end - s_end)));
181 s = s ? s + 1 : text_end;
182 y_end += line_height;
192 const int vtx_count_max =
static_cast<int>(text_end - s) * 4;
193 const int idx_count_max =
static_cast<int>(text_end - s) * 6;
194 const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
195 draw_list->PrimReserve(idx_count_max, vtx_count_max);
197 ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
198 ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
199 unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
202 for (
size_t i = 0; i < static_cast<size_t>(text_end - text_begin); i++)
204 char_skip.at(i) =
false;
208 const char* sLocal = s;
209 ImU32 temp_col = col;
210 while (sLocal < text_end)
212 if (sLocal < text_end - 4 && ParseColor(sLocal, &temp_col, &skipChars))
215 for (
size_t i = 0; i < static_cast<size_t>(skipChars); i++)
217 char_skip.at(index + i) =
true;
219 index +=
static_cast<size_t>(skipChars);
223 char_buf.at(index) = *sLocal;
224 col_buf.at(index) = temp_col;
225 char_skip.at(index) =
false;
235 if (char_skip.at(
static_cast<size_t>(s - s1)))
240 if (word_wrap_enabled)
246 word_wrap_eol = font->CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
247 if (word_wrap_eol == s)
253 if (s >= word_wrap_eol)
257 word_wrap_eol =
nullptr;
263 if (ImCharIsBlankA(c))
282 auto c =
static_cast<unsigned int>(
static_cast<unsigned char>(*s));
289 s += ImTextCharFromUtf8(&c, s, text_end);
314 float char_width = 0.0F;
315 if (
const ImFontGlyph* glyph = font->FindGlyph(
static_cast<ImWchar
>(c)))
317 char_width = glyph->AdvanceX * scale;
320 if (c !=
' ' && c !=
'\t')
324 float x1 = x + glyph->X0 * scale;
325 float x2 = x + glyph->X1 * scale;
326 float y1 = y + glyph->Y0 * scale;
327 float y2 = y + glyph->Y1 * scale;
328 if (x1 <= clip_rect.z && x2 >= clip_rect.x)
331 float u1 = glyph->U0;
332 float v1 = glyph->V0;
333 float u2 = glyph->U1;
334 float v2 = glyph->V1;
340 if (x1 < clip_rect.x)
342 u1 = u1 + (1.0F - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
345 if (y1 < clip_rect.y)
347 v1 = v1 + (1.0F - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
350 if (x2 > clip_rect.z)
352 u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
355 if (y2 > clip_rect.w)
357 v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
369 ImU32 temp_col = col_buf.at(
static_cast<size_t>(s - text_begin - 1));
371 idx_write[0] = vtx_current_idx;
372 idx_write[1] = vtx_current_idx + 1;
373 idx_write[2] = vtx_current_idx + 2;
374 idx_write[3] = vtx_current_idx;
375 idx_write[4] = vtx_current_idx + 2;
376 idx_write[5] = vtx_current_idx + 3;
377 vtx_write[0].pos.x = x1;
378 vtx_write[0].pos.y = y1;
379 vtx_write[0].col = temp_col;
380 vtx_write[0].uv.x = u1;
381 vtx_write[0].uv.y = v1;
382 vtx_write[1].pos.x = x2;
383 vtx_write[1].pos.y = y1;
384 vtx_write[1].col = temp_col;
385 vtx_write[1].uv.x = u2;
386 vtx_write[1].uv.y = v1;
387 vtx_write[2].pos.x = x2;
388 vtx_write[2].pos.y = y2;
389 vtx_write[2].col = temp_col;
390 vtx_write[2].uv.x = u2;
391 vtx_write[2].uv.y = v2;
392 vtx_write[3].pos.x = x1;
393 vtx_write[3].pos.y = y2;
394 vtx_write[3].col = temp_col;
395 vtx_write[3].uv.x = u1;
396 vtx_write[3].uv.y = v2;
398 vtx_current_idx += 4;
409 draw_list->VtxBuffer.resize(
static_cast<int>(vtx_write - draw_list->VtxBuffer.Data));
410 draw_list->IdxBuffer.resize(
static_cast<int>(idx_write - draw_list->IdxBuffer.Data));
411 draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -=
static_cast<unsigned int>(idx_expected_size - draw_list->IdxBuffer.Size);
412 draw_list->_VtxWritePtr = vtx_write;
413 draw_list->_IdxWritePtr = idx_write;
414 draw_list->_VtxCurrentIdx =
static_cast<unsigned int>(draw_list->VtxBuffer.Size);
417void ImDrawList_AddAnsiText(ImDrawList* drawList,
422 const char* text_begin,
423 const char* text_end =
nullptr,
424 float wrap_width = 0.0F,
425 const ImVec4* cpu_fine_clip_rect =
nullptr)
427 if ((col & IM_COL32_A_MASK) == 0)
432 if (text_end ==
nullptr)
434 text_end = text_begin + strlen(text_begin);
436 if (text_begin == text_end)
444 font = drawList->_Data->Font;
446 if (font_size == 0.0F)
448 font_size = drawList->_Data->FontSize;
451 IM_ASSERT(font->ContainerAtlas->TexID == drawList->_TextureIdStack.back());
456 ImVec4 clip_rect = drawList->_ClipRectStack.back();
457 if (cpu_fine_clip_rect)
459 clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
460 clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
461 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
462 clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
464 ImFont_RenderAnsiText(font,
473 cpu_fine_clip_rect !=
nullptr);
476void RenderAnsiText(ImVec2 pos,
const char* text,
const char* text_end,
bool hide_text_after_hash)
478 ImGuiContext&
g = *GImGui;
479 ImGuiWindow* window =
g.CurrentWindow;
482 const char* text_display_end =
nullptr;
483 if (hide_text_after_hash)
485 text_display_end = FindRenderedTextEnd(text, text_end);
491 text_end = text + strlen(text);
493 text_display_end = text_end;
496 if (text != text_display_end)
498 ImDrawList_AddAnsiText(window->DrawList,
g.Font,
g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
501 LogRenderedText(&pos, text, text_display_end);
506void RenderAnsiTextWrapped(ImVec2 pos,
const char* text,
const char* text_end,
float wrap_width)
508 ImGuiContext&
g = *GImGui;
509 ImGuiWindow* window =
g.CurrentWindow;
513 text_end = text + strlen(text);
516 if (text != text_end)
518 ImDrawList_AddAnsiText(window->DrawList,
g.Font,
g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
521 LogRenderedText(&pos, text, text_end);
531 ImGuiWindow* window = GetCurrentWindow();
532 if (window->SkipItems)
537 ImGuiContext& g = *GImGui;
538 IM_ASSERT(text !=
nullptr);
539 const char* text_begin = text;
540 if (text_end ==
nullptr)
542 text_end = text + strlen(text);
545 const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
546 const float wrap_pos_x = window->DC.TextWrapPos;
547 const bool wrap_enabled = wrap_pos_x >= 0.0F;
548 if (text_end - text > 2000 && !wrap_enabled)
558 const char* line = text;
559 const float line_height = GetTextLineHeight();
560 const ImRect clip_rect = window->ClipRect;
561 ImVec2 text_size(0, 0);
563 if (text_pos.y <= clip_rect.Max.y)
565 ImVec2 pos = text_pos;
570 int lines_skippable =
static_cast<int>((clip_rect.Min.y - text_pos.y) / line_height);
571 if (lines_skippable > 0)
573 int lines_skipped = 0;
574 while (line < text_end && lines_skipped < lines_skippable)
576 const char* line_end =
static_cast<const char*
>(memchr(line,
'\n',
static_cast<size_t>(text_end - line)));
584 pos.y +=
static_cast<float>(lines_skipped) * line_height;
591 ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
592 while (line < text_end)
594 if (IsClippedEx(line_rect, 0))
599 const char* line_end =
static_cast<const char*
>(memchr(line,
'\n',
static_cast<size_t>(text_end - line)));
604 const ImVec2 line_size = CalcTextSize(line, line_end,
false);
605 text_size.x = ImMax(text_size.x, line_size.x);
606 RenderAnsiText(pos, line, line_end,
false);
608 line_rect.Min.y += line_height;
609 line_rect.Max.y += line_height;
610 pos.y += line_height;
614 int lines_skipped = 0;
615 while (line < text_end)
617 const char* line_end =
static_cast<const char*
>(memchr(line,
'\n',
static_cast<size_t>(text_end - line)));
625 pos.y +=
static_cast<float>(lines_skipped) * line_height;
628 text_size.y += (pos - text_pos).y;
631 ImRect bb(text_pos, text_pos + text_size);
637 const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0F;
638 const ImVec2 text_size = CalcTextSize(text_begin, text_end,
false, wrap_width);
641 ImRect bb(text_pos, text_pos + text_size);
649 RenderAnsiTextWrapped(bb.Min, text_begin, text_end, wrap_width);
655 ImGuiWindow* window = GetCurrentWindow();
656 if (window->SkipItems)
661 ImGuiContext& g = *GImGui;
662#if defined(__GNUC__) || defined(__clang__)
663 #pragma GCC diagnostic push
664 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
666 const char* text_end = g.TempBuffer.Data + ImFormatStringV(g.TempBuffer.Data, strlen(g.TempBuffer.Data), fmt, args);
667#if defined(__GNUC__) || defined(__clang__)
668 #pragma GCC diagnostic pop
675 PushStyleColor(ImGuiCol_Text, col);
Text which can be colored by Ansi codes.
void TextAnsiColored(const ImVec4 &col, const char *fmt,...)
Displays an ansi text with format string.
void TextAnsiColoredV(const ImVec4 &col, const char *fmt, va_list args)
Displays an ansi text with format string.
void TextAnsiUnformatted(const char *text, const char *text_end=nullptr)
Displays an unformatted ansi text.
void TextAnsiV(const char *fmt, va_list args)
Displays an ansi text with format string.