Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.76

Other Changes:

- Switched to use ImStr and ImWStr string span in public API.
- Drag and Drop, Nav: Disabling navigation arrow keys when drag and drop is active. In the docking
branch pressing arrow keys while dragging a window from a tab could trigger an assert. (#3025)
- BeginMenu: Using same ID multiple times appends content to a menu. (#1207) [@rokups]
Expand Down
364 changes: 214 additions & 150 deletions imgui.cpp

Large diffs are not rendered by default.

348 changes: 200 additions & 148 deletions imgui.h

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2918,7 +2918,7 @@ static void ShowDemoWindowLayout()
"(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)");
ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, 0.0f, &clip_rect);
break;
}
ImGui::EndGroup();
Expand Down Expand Up @@ -3726,7 +3726,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
// Here we use the simplified Combo() api that packs items into a single literal string.
// Useful for quick combo boxes where the choices are known locally.
bool ImGui::ShowStyleSelector(const char* label)
bool ImGui::ShowStyleSelector(ImStr label)
{
static int style_idx = -1;
if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
Expand All @@ -3744,7 +3744,7 @@ bool ImGui::ShowStyleSelector(const char* label)

// Demo helper function to select among loaded fonts.
// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one.
void ImGui::ShowFontSelector(const char* label)
void ImGui::ShowFontSelector(ImStr label)
{
ImGuiIO& io = ImGui::GetIO();
ImFont* font_current = ImGui::GetFont();
Expand Down Expand Up @@ -4516,7 +4516,7 @@ struct ExampleAppConsole
if (match_len > 0)
{
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
data->InsertChars(data->CursorPos, ImStr(candidates[0], (size_t)match_len));
}

// List matches
Expand Down Expand Up @@ -4650,8 +4650,8 @@ struct ExampleAppLog
{
const char* line_start = buf + LineOffsets[line_no];
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
if (Filter.PassFilter(line_start, line_end))
ImGui::TextUnformatted(line_start, line_end);
if (Filter.PassFilter(ImStr(line_start, line_end)))
ImGui::TextUnformatted(ImStr(line_start, line_end));
}
}
else
Expand All @@ -4677,7 +4677,7 @@ struct ExampleAppLog
{
const char* line_start = buf + LineOffsets[line_no];
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
ImGui::TextUnformatted(line_start, line_end);
ImGui::TextUnformatted(ImStr(line_start, line_end));
}
}
clipper.End();
Expand Down Expand Up @@ -4900,7 +4900,7 @@ static void ShowExampleAppLongText(bool* p_open)
{
case 0:
// Single call to TextUnformatted() with a big buffer
ImGui::TextUnformatted(log.begin(), log.end());
ImGui::TextUnformatted(ImStr(log.begin(), log.end()));
break;
case 1:
{
Expand Down
103 changes: 51 additions & 52 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1312,14 +1312,13 @@ void ImDrawList::AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2
PathStroke(col, false, thickness);
}

void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, ImStr text, float wrap_width, const ImVec4* cpu_fine_clip_rect)
{
if ((col & IM_COL32_A_MASK) == 0)
return;

if (text_end == NULL)
text_end = text_begin + strlen(text_begin);
if (text_begin == text_end)
IM_IMSTR_ENSURE_HAS_END(text);
if (text.Empty())
return;

// Pull default font/size from the shared ImDrawListSharedData instance
Expand All @@ -1338,12 +1337,12 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
}
font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
font->RenderText(this, font_size, pos, col, clip_rect, text, wrap_width, cpu_fine_clip_rect != NULL);
}

void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
void ImDrawList::AddText(const ImVec2& pos, ImU32 col, ImStr text)
{
AddText(NULL, 0.0f, pos, col, text_begin, text_end);
AddText(NULL, 0.0f, pos, col, text);
}

void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
Expand Down Expand Up @@ -1866,13 +1865,13 @@ static unsigned int stb_decompress_length(const unsigned char* input);
static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);
static const char* GetDefaultCompressedFontDataTTFBase85();
static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; }
static void Decode85(const unsigned char* src, unsigned char* dst)
static void Decode85(ImStr src, unsigned char* dst)
{
while (*src)
while (!src.Empty())
{
unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness.
src += 5;
src.Begin += 5;
dst += 4;
}
}
Expand All @@ -1899,7 +1898,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
return font;
}

ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
ImFont* ImFontAtlas::AddFontFromFileTTF(ImStr filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
size_t data_size = 0;
Expand All @@ -1914,8 +1913,9 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
{
// Store a short copy of filename into into the font name for convenience
const char* p;
for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
for (p = filename.Begin + IM_IMSTR_LENGTH(filename); p > filename.Begin && p[-1] != '/' && p[-1] != '\\'; p--) {}
filename.Begin = p;
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%.*s, %.0fpx", (int)IM_IMSTR_LENGTH(filename), filename.Begin, size_pixels);
}
return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
}
Expand Down Expand Up @@ -1946,11 +1946,11 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_d
return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
}

ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(ImStr compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
{
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
int compressed_ttf_size = (((int)IM_IMSTR_LENGTH(compressed_ttf_data_base85) + 4) / 5) * 4;
void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
Decode85(compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
IM_FREE(compressed_ttf);
return font;
Expand Down Expand Up @@ -2724,13 +2724,13 @@ const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese()
// [SECTION] ImFontGlyphRangesBuilder
//-----------------------------------------------------------------------------

void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
void ImFontGlyphRangesBuilder::AddText(ImStr text)
{
while (text_end ? (text < text_end) : *text)
while (!text.Empty())
{
unsigned int c = 0;
int c_len = ImTextCharFromUtf8(&c, text, text_end);
text += c_len;
int c_len = ImTextCharFromUtf8(&c, text.Begin, text.End);
text.Begin += c_len;
if (c_len == 0)
break;
AddChar((ImWchar)c);
Expand Down Expand Up @@ -2963,7 +2963,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
return &Glyphs.Data[i];
}

const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
const char* ImFont::CalcWordWrapPositionA(float scale, ImStr text, float wrap_width) const
{
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
Expand All @@ -2979,25 +2979,26 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c

// Cut words that cannot possibly fit within one line.
// e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
IM_IMSTR_ENSURE_HAS_END(text);

float line_width = 0.0f;
float word_width = 0.0f;
float blank_width = 0.0f;
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters

const char* word_end = text;
const char* word_end = text.Begin;
const char* prev_word_end = NULL;
bool inside_word = true;

const char* s = text;
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;

Expand Down Expand Up @@ -3062,10 +3063,9 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
return s;
}

ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, ImStr text, const char** remaining) const
{
if (!text_end)
text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
IM_IMSTR_ENSURE_HAS_END(text);

const float line_height = size;
const float scale = size / FontSize;
Expand All @@ -3076,15 +3076,15 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
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, s, text_end, wrap_width - line_width);
word_wrap_eol = CalcWordWrapPositionA(scale, ImStr(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
}
Expand All @@ -3098,7 +3098,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
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; }
Expand All @@ -3116,7 +3116,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
}
else
{
s += ImTextCharFromUtf8(&c, s, text_end);
s += ImTextCharFromUtf8(&c, s, text.End);
if (c == 0) // Malformed UTF-8?
break;
}
Expand Down Expand Up @@ -3168,10 +3168,9 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
}

void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, ImStr text, float wrap_width, bool cpu_fine_clip) const
{
if (!text_end)
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
IM_IMSTR_ENSURE_HAS_END(text); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.

// Align to be pixel perfect
pos.x = IM_FLOOR(pos.x);
Expand All @@ -3187,50 +3186,50 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
const char* word_wrap_eol = NULL;

// Fast-forward to first visible line
const char* s = text_begin;
const char* s = text.Begin;
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);

ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;

while (s < text_end)
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, s, text_end, wrap_width - (x - pos.x));
word_wrap_eol = CalcWordWrapPositionA(scale, ImStr(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
}
Expand All @@ -3242,7 +3241,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; }
Expand All @@ -3259,7 +3258,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;
}
Expand Down
Loading