ImStrv: various tweaks and fixes. removed ImGuiTextRange from ImGuiTextFilter, fix test engine hooks, removed constructor only used twice.

This commit is contained in:
ocornut 2020-11-27 15:39:15 +01:00
parent 4e894ae1d9
commit 194bf63863
5 changed files with 127 additions and 131 deletions

View File

@ -2327,41 +2327,39 @@ bool ImGuiTextFilter::Draw(ImStrv label, float width)
return value_changed;
}
void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
static void ImStrplit(ImStrv in, char separator, ImVector<ImStrv>* out)
{
out->resize(0);
const char* wb = b;
const char* wb = in.Begin;
const char* we = wb;
while (we < e)
while (we < in.End)
{
if (*we == separator)
{
out->push_back(ImGuiTextRange(wb, we));
out->push_back(ImStrv(wb, we));
wb = we + 1;
}
we++;
}
if (wb != we)
out->push_back(ImGuiTextRange(wb, we));
out->push_back(ImStrv(wb, we));
}
void ImGuiTextFilter::Build()
{
Filters.resize(0);
ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
input_range.split(',', &Filters);
ImStrplit(ImStrv(InputBuf, InputBuf + strlen(InputBuf)), ',', &Filters);
CountGrep = 0;
for (int i = 0; i != Filters.Size; i++)
{
ImGuiTextRange& f = Filters[i];
while (f.b < f.e && ImCharIsBlankA(f.b[0]))
f.b++;
while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
f.e--;
ImStrv& f = Filters[i];
while (f.Begin < f.End && ImCharIsBlankA(f.Begin[0]))
f.Begin++;
while (f.End > f.Begin && ImCharIsBlankA(f.End[-1]))
f.End--;
if (f.empty())
continue;
if (Filters[i].b[0] != '-')
if (Filters[i].Begin[0] != '-')
CountGrep += 1;
}
}
@ -2372,23 +2370,23 @@ bool ImGuiTextFilter::PassFilter(ImStrv text) const
return true;
if (!text)
text.Begin = text.End = "";
text = "";
for (int i = 0; i != Filters.Size; i++)
{
const ImGuiTextRange& f = Filters[i];
const ImStrv& f = Filters[i];
if (f.empty())
continue;
if (f.b[0] == '-')
if (f.Begin[0] == '-')
{
// Subtract
if (ImStristr(text.Begin, text.End, f.b + 1, f.e) != NULL)
if (ImStristr(text.Begin, text.End, f.Begin + 1, f.End) != NULL)
return false;
}
else
{
// Grep
if (ImStristr(text.Begin, text.End, f.b, f.e) != NULL)
if (ImStristr(text.Begin, text.End, f.Begin, f.End) != NULL)
return true;
}
}
@ -2419,6 +2417,8 @@ char ImGuiTextBuffer::EmptyString[1] = { 0 };
void ImGuiTextBuffer::append(ImStrv str)
{
int len = (int)str.length();
if (len == 0)
return;
// Add zero-terminator the first time
const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
@ -2430,7 +2430,6 @@ void ImGuiTextBuffer::append(ImStrv str)
}
Buf.resize(needed_sz);
if (len > 0)
memcpy(&Buf[write_off - 1], str.Begin, (size_t)len);
Buf[write_off - 1 + len] = 0;
}
@ -3023,10 +3022,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
const char* ImGui::FindRenderedTextEnd(ImStrv text)
{
const char* text_display_end = text.Begin;
if (!text.End)
text.End = (const char*)-1;
while (text_display_end < text.End && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
while (text_display_end < text.End && (text_display_end[0] != '#' || text_display_end[1] != '#'))
text_display_end++;
return text_display_end;
}
@ -3039,17 +3035,14 @@ void ImGui::RenderText(ImVec2 pos, ImStrv text, bool hide_text_after_hash)
ImGuiWindow* window = g.CurrentWindow;
// Hide anything after a '##' string
const char* text_display_end;
if (hide_text_after_hash)
text_display_end = FindRenderedTextEnd(text);
else
text_display_end = text.End;
text.End = FindRenderedTextEnd(text);
if (text.Begin != text_display_end)
if (text.Begin != text.End)
{
window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), ImStrv(text.Begin, text_display_end));
window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text);
if (g.LogEnabled)
LogRenderedText(&pos, ImStrv(text.Begin, text_display_end));
LogRenderedText(&pos, text);
}
}
@ -3099,16 +3092,16 @@ void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, co
void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, ImStrv text, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
{
// Hide anything after a '##' string
const char* text_display_end = FindRenderedTextEnd(text);
const int text_len = (int)(text_display_end - text.Begin);
if (text_len == 0)
// FIXME-IMSTR: This is not new but should be moved out of there.
text.End = FindRenderedTextEnd(text);
if (text.Begin == text.End)
return;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
RenderTextClippedEx(window->DrawList, pos_min, pos_max, ImStrv(text.Begin, text_display_end), text_size_if_known, align, clip_rect);
RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_size_if_known, align, clip_rect);
if (g.LogEnabled)
LogRenderedText(&pos_min, ImStrv(text.Begin, text_display_end));
LogRenderedText(&pos_min, text);
}
// Another overly complex function until we reorganize everything into a nice all-in-one helper.
@ -3117,8 +3110,6 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, ImSt
void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, ImStrv text, const ImVec2* text_size_if_known)
{
ImGuiContext& g = *GImGui;
if (text.End == NULL)
text.End = FindRenderedTextEnd(text);
const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, false, 0.0f);
//draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));
@ -6039,7 +6030,7 @@ bool ImGui::Begin(ImStrv name, bool* p_open, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
IM_ASSERT(name.Begin != NULL); // Window name required
IM_ASSERT(name.Begin != name.End); // Window name required
IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame()
IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
@ -11179,7 +11170,7 @@ bool ImGui::SetDragDropPayload(ImStrv type, const void* data, size_t data_size,
if (cond == 0)
cond = ImGuiCond_Always;
IM_ASSERT(type.Begin != NULL && "Payload type can not be empty");
IM_ASSERT(type.End - type.Begin > 0 && "Payload type can not be empty");
IM_ASSERT(type.End - type.Begin < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
@ -11704,12 +11695,12 @@ void ImGui::LoadIniSettingsFromDisk(ImStrv ini_filename)
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
LoadIniSettingsFromMemory(ImStrv(file_data, file_data + file_data_size));
IM_FREE(file_data);
}
// Zero-tolerance, no error reporting, cheap .ini parsing
void ImGui::LoadIniSettingsFromMemory(ImStrv ini_data, size_t ini_size)
void ImGui::LoadIniSettingsFromMemory(ImStrv ini_data)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.Initialized);
@ -11718,8 +11709,7 @@ void ImGui::LoadIniSettingsFromMemory(ImStrv ini_data, size_t ini_size)
// For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = ini_data.length();
const int ini_size = (int)ini_data.length();
g.SettingsIniData.Buf.resize((int)ini_size + 1);
char* const buf = g.SettingsIniData.Buf.Data;
char* const buf_end = buf + ini_size;

22
imgui.h
View File

@ -278,13 +278,14 @@ struct ImStrv
ImStrv() { Begin = End = NULL; }
ImStrv(const char* b) { Begin = b; End = b ? b + strlen(b) : NULL; }
ImStrv(const char* b, const char* e){ Begin = b; End = e ? e : b + strlen(b); }
ImStrv(const char* b, size_t size) { Begin = b; End = b + size; }
inline size_t length() const { return (size_t)(End - Begin); }
inline bool empty() const { return Begin == End; } // == "" or == NULL
inline operator bool() const { return Begin != NULL; } // != NULL
#ifdef IM_IMSTR_CLASS_EXTRA
IM_IMSTR_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your string types and ImStrv.
#endif
// private: bool operator==(ImStrv) { return false; } // [DEBUG] Uncomment to catch undesirable uses of operators
// private: bool operator!=(ImStrv) { return false; }
};
IM_MSVC_RUNTIME_CHECKS_RESTORE
@ -939,7 +940,7 @@ namespace ImGui
// - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.
// - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables).
IMGUI_API void LoadIniSettingsFromDisk(ImStrv ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).
IMGUI_API void LoadIniSettingsFromMemory(ImStrv ini_data, size_t ini_size= 0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
IMGUI_API void LoadIniSettingsFromMemory(ImStrv ini_data); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
IMGUI_API void SaveIniSettingsToDisk(ImStrv ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext).
IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings.
@ -2103,7 +2104,7 @@ struct ImGuiInputTextCallbackData
ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0;
ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History]
char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer!
int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: IM_IMSTR_LENGTH(string)
int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length()
int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1
bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always]
int CursorPos; // // Read-write // [Completion,History,Always]
@ -2148,7 +2149,7 @@ struct ImGuiPayload
ImGuiPayload() { Clear(); }
void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; }
bool IsDataType(ImStrv type) const { return DataFrameCount != -1 && type == ImStrv(DataType); }
bool IsDataType(ImStrv type) const { size_t len = type.length(); return DataFrameCount != -1 && memcmp(DataType, type.Begin, len) == 0 && DataType[len] == 0; }
bool IsPreview() const { return Preview; }
bool IsDelivery() const { return Delivery; }
};
@ -2209,19 +2210,8 @@ struct ImGuiTextFilter
void Clear() { InputBuf[0] = 0; Build(); }
bool IsActive() const { return !Filters.empty(); }
// [Internal] FIXME-IMSTR: replace this with ImStrv, remove split as an internal function
struct ImGuiTextRange
{
const char* b;
const char* e;
ImGuiTextRange() { b = e = NULL; }
ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; }
bool empty() const { return b == e; }
IMGUI_API void split(char separator, ImVector<ImGuiTextRange>* out) const;
};
char InputBuf[256];
ImVector<ImGuiTextRange>Filters;
ImVector<ImStrv> Filters;
int CountGrep;
};

View File

@ -6768,7 +6768,7 @@ struct ExampleAppConsole
if (match_len > 0)
{
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
data->InsertChars(data->CursorPos, ImStrv(candidates[0], (size_t)match_len));
data->InsertChars(data->CursorPos, ImStrv(candidates[0], candidates[0] + match_len));
}
// List matches

View File

@ -1577,7 +1577,7 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
{
if ((col & IM_COL32_A_MASK) == 0)
return;
if (text.empty())
if (text.Begin == text.End)
return;
// Pull default font/size from the shared ImDrawListSharedData instance
@ -3351,19 +3351,22 @@ const char* ImFont::CalcWordWrapPositionA(float scale, ImStrv text, float wrap_w
float blank_width = 0.0f;
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
const char* word_end = text.Begin;
const char* text_begin = text.Begin;
const char* text_end = text.End;
const char* word_end = text_begin;
const char* prev_word_end = NULL;
bool inside_word = true;
const char* s = text.Begin;
while (s < text.End)
const char* s = text_begin;
while (s < text_end)
{
unsigned int c = (unsigned int)*s;
const char* next_s;
if (c < 0x80)
next_s = s + 1;
else
next_s = s + ImTextCharFromUtf8(&c, s, text.End);
next_s = s + ImTextCharFromUtf8(&c, s, text_end);
if (c == 0)
break;
@ -3436,18 +3439,21 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, ImSt
ImVec2 text_size = ImVec2(0, 0);
float line_width = 0.0f;
const char* text_begin = text.Begin;
const char* text_end = text.End;
const bool word_wrap_enabled = (wrap_width > 0.0f);
const char* word_wrap_eol = NULL;
const char* s = text.Begin;
while (s < text.End)
const char* s = text_begin;
while (s < text_end)
{
if (word_wrap_enabled)
{
// Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
if (!word_wrap_eol)
{
word_wrap_eol = CalcWordWrapPositionA(scale, ImStrv(s, text.End), wrap_width - line_width);
word_wrap_eol = CalcWordWrapPositionA(scale, ImStrv(s, text_end), wrap_width - line_width);
if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
}
@ -3461,7 +3467,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, ImSt
word_wrap_eol = NULL;
// Wrapping skips upcoming blanks
while (s < text.End)
while (s < text_end)
{
const char c = *s;
if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
@ -3479,7 +3485,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, ImSt
}
else
{
s += ImTextCharFromUtf8(&c, s, text.End);
s += ImTextCharFromUtf8(&c, s, text_end);
if (c == 0) // Malformed UTF-8?
break;
}
@ -3552,34 +3558,35 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
// Fast-forward to first visible line
const char* s = text.Begin;
const char* text_end = text.End;
if (y + line_height < clip_rect.y && !word_wrap_enabled)
while (y + line_height < clip_rect.y && s < text.End)
while (y + line_height < clip_rect.y && s < text_end)
{
s = (const char*)memchr(s, '\n', text.End - s);
s = s ? s + 1 : text.End;
s = (const char*)memchr(s, '\n', text_end - s);
s = s ? s + 1 : text_end;
y += line_height;
}
// For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
// Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm)
if (text.End - s > 10000 && !word_wrap_enabled)
if (text_end - s > 10000 && !word_wrap_enabled)
{
const char* s_end = s;
float y_end = y;
while (y_end < clip_rect.w && s_end < text.End)
while (y_end < clip_rect.w && s_end < text_end)
{
s_end = (const char*)memchr(s_end, '\n', text.End - s_end);
s_end = s_end ? s_end + 1 : text.End;
s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
s_end = s_end ? s_end + 1 : text_end;
y_end += line_height;
}
text.End = s_end;
text_end = s_end;
}
if (s == text.End)
if (s == text_end)
return;
// Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
const int vtx_count_max = (int)(text.End - s) * 4;
const int idx_count_max = (int)(text.End - s) * 6;
const int vtx_count_max = (int)(text_end - s) * 4;
const int idx_count_max = (int)(text_end - s) * 6;
const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
draw_list->PrimReserve(idx_count_max, vtx_count_max);
@ -3596,7 +3603,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
// Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
if (!word_wrap_eol)
{
word_wrap_eol = CalcWordWrapPositionA(scale, ImStrv(s, text.End), wrap_width - (x - pos.x));
word_wrap_eol = CalcWordWrapPositionA(scale, ImStrv(s, text_end), wrap_width - (x - pos.x));
if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
}
@ -3608,7 +3615,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
word_wrap_eol = NULL;
// Wrapping skips upcoming blanks
while (s < text.End)
while (s < text_end)
{
const char c = *s;
if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
@ -3625,7 +3632,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
}
else
{
s += ImTextCharFromUtf8(&c, s, text.End);
s += ImTextCharFromUtf8(&c, s, text_end);
if (c == 0) // Malformed UTF-8?
break;
}

View File

@ -155,17 +155,20 @@ void ImGui::TextEx(ImStrv text, ImGuiTextFlags flags)
return;
ImGuiContext& g = *GImGui;
const char* text_begin = text.Begin;
const char* text_end = text.End;
const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const float wrap_pos_x = window->DC.TextWrapPos;
const bool wrap_enabled = (wrap_pos_x >= 0.0f);
if (text.End - text.Begin > 2000 && !wrap_enabled)
if (text_end - text_begin > 2000 && !wrap_enabled)
{
// Long text!
// Perform manual coarse clipping to optimize for long multi-line text
// - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
// - 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.
// - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop.
const char* line = text.Begin;
const char* line = text_begin;
const float line_height = GetTextLineHeight();
ImVec2 text_size(0, 0);
@ -177,11 +180,11 @@ void ImGui::TextEx(ImStrv text, ImGuiTextFlags flags)
if (lines_skippable > 0)
{
int lines_skipped = 0;
while (line < text.End && lines_skipped < lines_skippable)
while (line < text_end && lines_skipped < lines_skippable)
{
const char* line_end = (const char*)memchr(line, '\n', text.End - line);
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
if (!line_end)
line_end = text.End;
line_end = text_end;
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);
line = line_end + 1;
@ -192,17 +195,17 @@ void ImGui::TextEx(ImStrv text, ImGuiTextFlags flags)
}
// Lines to render
if (line < text.End)
if (line < text_end)
{
ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
while (line < text.End)
while (line < text_end)
{
if (IsClippedEx(line_rect, 0))
break;
const char* line_end = (const char*)memchr(line, '\n', text.End - line);
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
if (!line_end)
line_end = text.End;
line_end = text_end;
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);
RenderText(pos, ImStrv(line, line_end), false);
line = line_end + 1;
@ -213,11 +216,11 @@ void ImGui::TextEx(ImStrv text, ImGuiTextFlags flags)
// Count remaining lines
int lines_skipped = 0;
while (line < text.End)
while (line < text_end)
{
const char* line_end = (const char*)memchr(line, '\n', text.End - line);
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
if (!line_end)
line_end = text.End;
line_end = text_end;
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);
line = line_end + 1;
@ -1618,7 +1621,7 @@ bool ImGui::BeginCombo(ImStrv label, ImStrv preview_value, ImGuiComboFlags flags
if (flags & ImGuiComboFlags_CustomPreview)
{
g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y);
IM_ASSERT(!preview_value || preview_value[0] == 0);
IM_ASSERT(!preview_value);
preview_value = NULL;
}
@ -2346,6 +2349,7 @@ bool ImGui::DragScalar(ImStrv label, ImGuiDataType data_type, void* p_data, floa
if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
return false;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
@ -2441,11 +2445,11 @@ bool ImGui::DragScalarN(ImStrv label, ImGuiDataType data_type, void* p_data, int
}
PopID();
const char* label_end = FindRenderedTextEnd(label);
if (label.Begin != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, label_end));
TextEx(label);
}
EndGroup();
@ -2498,7 +2502,8 @@ bool ImGui::DragFloatRange2(ImStrv label, float* v_current_min, float* v_current
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, FindRenderedTextEnd(label)));
label.End = FindRenderedTextEnd(label);
TextEx(label);
EndGroup();
PopID();
@ -2552,7 +2557,8 @@ bool ImGui::DragIntRange2(ImStrv label, int* v_current_min, int* v_current_max,
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, FindRenderedTextEnd(label)));
label.End = FindRenderedTextEnd(label);
TextEx(label);
EndGroup();
PopID();
@ -2969,6 +2975,7 @@ bool ImGui::SliderScalar(ImStrv label, ImGuiDataType data_type, void* p_data, co
if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
return false;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
@ -3062,11 +3069,11 @@ bool ImGui::SliderScalarN(ImStrv label, ImGuiDataType data_type, void* v, int co
}
PopID();
const char* label_end = FindRenderedTextEnd(label);
if (label.Begin != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, label_end));
TextEx(label);
}
EndGroup();
@ -3141,6 +3148,7 @@ bool ImGui::VSliderScalar(ImStrv label, const ImVec2& size, ImGuiDataType data_t
if (!ItemAdd(frame_bb, id))
return false;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
@ -3391,6 +3399,7 @@ bool ImGui::InputScalar(ImStrv label, ImGuiDataType data_type, void* p_data, con
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
@ -3439,11 +3448,11 @@ bool ImGui::InputScalar(ImStrv label, ImGuiDataType data_type, void* p_data, con
if (flags & ImGuiInputTextFlags_ReadOnly)
EndDisabled();
const char* label_end = FindRenderedTextEnd(label);
if (label.Begin != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0, style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, label_end));
TextEx(label);
}
style.FramePadding = backup_frame_padding;
@ -3485,11 +3494,11 @@ bool ImGui::InputScalarN(ImStrv label, ImGuiDataType data_type, void* p_data, in
}
PopID();
const char* label_end = FindRenderedTextEnd(label);
if (label.Begin != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0.0f, g.Style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, label_end));
TextEx(label);
}
EndGroup();
@ -4857,11 +4866,11 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
const float w_full = CalcItemWidth();
const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
const float w_inputs = w_full - w_button;
const char* label_display_end = FindRenderedTextEnd(label);
g.NextItemData.ClearFlags();
BeginGroup();
PushID(label);
label.End = FindRenderedTextEnd(label);
// If we're not showing any slider there's no point in doing any HSV conversions
const ImGuiColorEditFlags flags_untouched = flags;
@ -5001,9 +5010,9 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
if (BeginPopup("picker"))
{
picker_active_window = g.CurrentWindow;
if (label.Begin != label_display_end)
if (label.Begin != label.End)
{
TextEx(ImStrv(label.Begin, label_display_end));
TextEx(label);
Spacing();
}
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
@ -5014,10 +5023,10 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
}
}
if (label.Begin != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
if (label.Begin != label.End && !(flags & ImGuiColorEditFlags_NoLabel))
{
SameLine(0.0f, style.ItemInnerSpacing.x);
TextEx(ImStrv(label.Begin, label_display_end));
TextEx(label);
}
// Convert back
@ -5580,10 +5589,10 @@ void ImGui::ColorTooltip(ImStrv text, const float* col, ImGuiColorEditFlags flag
ImGuiContext& g = *GImGui;
BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None);
const char* text_end = text ? FindRenderedTextEnd(text) : text.Begin;
if (text_end > text.Begin)
text.End = FindRenderedTextEnd(text);
if (text.Begin != text.End)
{
TextEx(ImStrv(text.Begin, text_end));
TextEx(text);
Separator();
}
@ -5854,8 +5863,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, ImStrv label)
const ImGuiStyle& style = g.Style;
const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y));
if (!label.End)
label.End = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, false);
@ -6929,7 +6936,7 @@ bool ImGui::BeginMenuEx(ImStrv label, ImStrv icon, bool enabled)
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float icon_w = icon ? CalcTextSize(icon, NULL).x : 0.0f;
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
@ -7101,8 +7108,8 @@ bool ImGui::MenuItemEx(ImStrv label, ImStrv icon, ImStrv shortcut, bool selected
// Menu item inside a vertical menu
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.
float icon_w = (icon && icon[0]) ? CalcTextSize(icon).x : 0.0f;
float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut).x : 0.0f;
float icon_w = icon ? CalcTextSize(icon).x : 0.0f;
float shortcut_w = shortcut ? CalcTextSize(shortcut).x : 0.0f;
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
@ -7954,6 +7961,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, ImStrv label, bool* p_open, ImGui
flags |= ImGuiTabItemFlags_NoCloseButton;
// Calculate tab contents size
label.End = FindRenderedTextEnd(label);
ImVec2 size = TabItemCalcSize(label, p_open != NULL);
// Acquire tab data
@ -7982,7 +7990,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, ImStrv label, bool* p_open, ImGui
// Append name with zero-terminator
tab->NameOffset = (ImS32)tab_bar->TabsNames.size();
tab_bar->TabsNames.append(label);
tab_bar->TabsNames.append(ImStrv("\0", 1));
char zero_c = 0;
tab_bar->TabsNames.append(ImStrv(&zero_c, &zero_c + 1));
// Update selected tab
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
@ -8191,7 +8200,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, ImStrv label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped)
{
ImGuiContext& g = *GImGui;
ImVec2 label_size = CalcTextSize(label, true);
ImVec2 label_size = CalcTextSize(label);
if (out_just_closed)
*out_just_closed = false;