Skip to content

Commit

Permalink
Refactor CalcWordWrapPositionA() to take on the responsability of min…
Browse files Browse the repository at this point in the history
…imum character display. Add CalcWordWrapNextLineStartA(), simplify caller code.

Should be no-op but incrementing IMGUI_VERSION_NUM just in case.
Preparing for ocornut#5720
  • Loading branch information
ocornut committed Sep 28, 2022
1 parent 5c4426c commit 4d4889b
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 28 deletions.
2 changes: 1 addition & 1 deletion imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
#define IMGUI_VERSION "1.89 WIP"
#define IMGUI_VERSION_NUM 18823
#define IMGUI_VERSION_NUM 18824
#define IMGUI_HAS_TABLE

/*
Expand Down
47 changes: 20 additions & 27 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3333,11 +3333,21 @@ 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
// Wrapping skips upcoming blanks
static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end)
{
// 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.)
while (text < text_end && ImCharIsBlankA(*text))
text++;
if (*text == '\n')
text++;
return text;
}

// Simple word-wrapping for English, not full-featured. Please submit failing cases!
// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
// 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.)
const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
{
// For references, possible wrap point marked with ^
// "aaa bbb, ccc,ddd. eee fff. ggg!"
// ^ ^ ^ ^ ^__ ^ ^
Expand All @@ -3349,7 +3359,6 @@ 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"

float line_width = 0.0f;
float word_width = 0.0f;
float blank_width = 0.0f;
Expand Down Expand Up @@ -3429,6 +3438,10 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
s = next_s;
}

// Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
// +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).
if (s == text && text < text_end)
return s + 1;
return s;
}

Expand All @@ -3453,11 +3466,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
{
// 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);
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
}

if (s >= word_wrap_eol)
{
Expand All @@ -3466,13 +3475,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
text_size.y += line_height;
line_width = 0.0f;
word_wrap_eol = NULL;

// Wrapping skips upcoming blanks
while (s < text_end)
{
const char c = *s;
if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
}
s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
continue;
}
}
Expand Down Expand Up @@ -3557,7 +3560,6 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
const float scale = size / FontSize;
const float line_height = FontSize * scale;
const bool word_wrap_enabled = (wrap_width > 0.0f);
const char* word_wrap_eol = NULL;

// Fast-forward to first visible line
const char* s = text_begin;
Expand Down Expand Up @@ -3597,31 +3599,22 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;

const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
const char* word_wrap_eol = NULL;

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 - start_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
}

if (s >= word_wrap_eol)
{
x = start_x;
y += line_height;
word_wrap_eol = NULL;

// Wrapping skips upcoming blanks
while (s < text_end)
{
const char c = *s;
if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
}
s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
continue;
}
}
Expand Down

0 comments on commit 4d4889b

Please sign in to comment.