| 148 | //------------------------------------------------------------------------- |
| 149 | |
| 150 | void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) |
| 151 | { |
| 152 | ImGuiWindow* window = GetCurrentWindow(); |
| 153 | if (window->SkipItems) |
| 154 | return; |
| 155 | ImGuiContext& g = *GImGui; |
| 156 | |
| 157 | // Accept null ranges |
| 158 | if (text == text_end) |
| 159 | text = text_end = ""; |
| 160 | |
| 161 | // Calculate length |
| 162 | const char* text_begin = text; |
| 163 | if (text_end == NULL) |
| 164 | text_end = text + strlen(text); // FIXME-OPT |
| 165 | |
| 166 | const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); |
| 167 | const float wrap_pos_x = window->DC.TextWrapPos; |
| 168 | const bool wrap_enabled = (wrap_pos_x >= 0.0f); |
| 169 | if (text_end - text <= 2000 || wrap_enabled) |
| 170 | { |
| 171 | // Common case |
| 172 | const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; |
| 173 | const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); |
| 174 | |
| 175 | ImRect bb(text_pos, text_pos + text_size); |
| 176 | ItemSize(text_size, 0.0f); |
| 177 | if (!ItemAdd(bb, 0)) |
| 178 | return; |
| 179 | |
| 180 | // Render (we don't hide text after ## in this end-user function) |
| 181 | RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); |
| 182 | } |
| 183 | else |
| 184 | { |
| 185 | // Long text! |
| 186 | // Perform manual coarse clipping to optimize for long multi-line text |
| 187 | // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. |
| 188 | // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. |
| 189 | // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. |
| 190 | const char* line = text; |
| 191 | const float line_height = GetTextLineHeight(); |
| 192 | ImVec2 text_size(0, 0); |
| 193 | |
| 194 | // Lines to skip (can't skip when logging text) |
| 195 | ImVec2 pos = text_pos; |
| 196 | if (!g.LogEnabled) |
| 197 | { |
| 198 | int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height); |
| 199 | if (lines_skippable > 0) |
| 200 | { |
| 201 | int lines_skipped = 0; |
| 202 | while (line < text_end && lines_skipped < lines_skippable) |
| 203 | { |
| 204 | const char* line_end = (const char*)memchr(line, '\n', text_end - line); |
| 205 | if (!line_end) |
| 206 | line_end = text_end; |
| 207 | if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) |
nothing calls this directly
no test coverage detected