mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 12:51:42 +00:00
add support for zero width line break hints
This commit is contained in:
parent
5ad4dbcc39
commit
d556bc1a81
3 changed files with 139 additions and 1 deletions
|
|
@ -247,6 +247,19 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
||||||
u1 / packer.width,
|
u1 / packer.width,
|
||||||
v0 / packer.height,
|
v0 / packer.height,
|
||||||
advance);
|
advance);
|
||||||
|
|
||||||
|
config.DstFont->AddGlyph(
|
||||||
|
&config,
|
||||||
|
0x200B,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
config.DstFont->BuildLookupTable();
|
config.DstFont->BuildLookupTable();
|
||||||
|
|
|
||||||
|
|
@ -464,17 +464,39 @@ std::vector<std::string> Split(const char* strStart, const ImFont* font, float f
|
||||||
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
||||||
const char *wordWrapEOL = nullptr;
|
const char *wordWrapEOL = nullptr;
|
||||||
|
|
||||||
|
auto IsKanji = [](const char* str, const char* strEnd)
|
||||||
|
{
|
||||||
|
const char* tempStr = str;
|
||||||
|
unsigned int c = (unsigned int)*tempStr;
|
||||||
|
if (c < 0x80)
|
||||||
|
tempStr += 1;
|
||||||
|
else
|
||||||
|
tempStr += ImTextCharFromUtf8(&c, tempStr, strEnd);
|
||||||
|
|
||||||
|
// Basic CJK and CJK Extension A
|
||||||
|
return (c >= 0x4E00 && c <= 0x9FBF) || (c >= 0x3400 && c <= 0x4DBF);
|
||||||
|
};
|
||||||
|
|
||||||
while (*str != 0)
|
while (*str != 0)
|
||||||
{
|
{
|
||||||
if (wordWrapEnabled)
|
if (wordWrapEnabled)
|
||||||
{
|
{
|
||||||
if (wordWrapEOL == nullptr)
|
if (wordWrapEOL == nullptr)
|
||||||
{
|
{
|
||||||
wordWrapEOL = font->CalcWordWrapPositionA(scale, str, strEnd, maxWidth - lineWidth);
|
wordWrapEOL = CalcWordWrapPositionA(font, scale, str, strEnd, maxWidth - lineWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str >= wordWrapEOL)
|
if (str >= wordWrapEOL)
|
||||||
{
|
{
|
||||||
|
if (IsKanji(str, strEnd))
|
||||||
|
{
|
||||||
|
// If the current character is Kanji, move back to prevent splitting Kanji
|
||||||
|
while (str > lineStart && IsKanji(str - 3, strEnd))
|
||||||
|
{
|
||||||
|
str -= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (textWidth < lineWidth)
|
if (textWidth < lineWidth)
|
||||||
textWidth = lineWidth;
|
textWidth = lineWidth;
|
||||||
|
|
||||||
|
|
@ -826,3 +848,105 @@ void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
|
||||||
drawList->AddImage(g_texLight.get(), min, max, GET_UV_COORDS(lightOffUVs), lightCol);
|
drawList->AddImage(g_texLight.get(), min, max, GET_UV_COORDS(lightOffUVs), lightCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taken from ImGui because we need to modify to break for '\u200B\ too
|
||||||
|
// 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* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width)
|
||||||
|
{
|
||||||
|
// For references, possible wrap point marked with ^
|
||||||
|
// "aaa bbb, ccc,ddd. eee fff. ggg!"
|
||||||
|
// ^ ^ ^ ^ ^__ ^ ^
|
||||||
|
|
||||||
|
// List of hardcoded separators: .,;!?'"
|
||||||
|
|
||||||
|
// Skip extra blanks after a line returns (that includes not counting them in width computation)
|
||||||
|
// e.g. "Hello world" --> "Hello" "World"
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
|
||||||
|
|
||||||
|
const char* word_end = text;
|
||||||
|
const char* prev_word_end = NULL;
|
||||||
|
bool inside_word = true;
|
||||||
|
|
||||||
|
const char* s = text;
|
||||||
|
IM_ASSERT(text_end != NULL);
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (c < 32)
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
line_width = word_width = blank_width = 0.0f;
|
||||||
|
inside_word = true;
|
||||||
|
s = next_s;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\r')
|
||||||
|
{
|
||||||
|
s = next_s;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX);
|
||||||
|
if (ImCharIsBlankW(c) || c == 0x200B)
|
||||||
|
{
|
||||||
|
if (inside_word)
|
||||||
|
{
|
||||||
|
line_width += blank_width;
|
||||||
|
blank_width = 0.0f;
|
||||||
|
word_end = s;
|
||||||
|
}
|
||||||
|
blank_width += char_width;
|
||||||
|
inside_word = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
word_width += char_width;
|
||||||
|
if (inside_word)
|
||||||
|
{
|
||||||
|
word_end = next_s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev_word_end = word_end;
|
||||||
|
line_width += word_width + blank_width;
|
||||||
|
word_width = blank_width = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow wrapping after punctuation.
|
||||||
|
inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// We ignore blank width at the end of the line (they can be skipped)
|
||||||
|
if (line_width + word_width > wrap_width)
|
||||||
|
{
|
||||||
|
// Words that cannot possibly fit within an entire line will be cut anywhere.
|
||||||
|
if (word_width < wrap_width)
|
||||||
|
s = prev_word_end ? prev_word_end : word_end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,3 +81,4 @@ ImU32 ColourLerp(ImU32 c0, ImU32 c1, float t);
|
||||||
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
|
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
|
||||||
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
|
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
|
||||||
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha = 1.0f);
|
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha = 1.0f);
|
||||||
|
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue