Skip to content

Commit

Permalink
Merge remote-tracking branch 'cloudwu/unicode' into master.
Browse files Browse the repository at this point in the history
 Conflicts:
	imconfig.h
	imgui.h
	imgui_draw.cpp
	imgui_widgets.cpp
  • Loading branch information
samhocevar committed Sep 29, 2019
2 parents f0f5301 + f524371 commit 853dac3
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 48 deletions.
2 changes: 1 addition & 1 deletion examples/imgui_impl_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
return 0;
case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
io.AddInputCharacter((unsigned int)wParam);
io.AddInputCharacterUTF16((unsigned short)wParam);
return 0;
case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
Expand Down
3 changes: 3 additions & 0 deletions imconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int

//---- Use 32-bit for ImWchar (default is 16-bit) to support full Unicode code points.
//#define ImWchar ImWchar32

//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
Expand Down
83 changes: 52 additions & 31 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1262,13 +1262,35 @@ void ImGuiIO::AddInputCharacter(unsigned int c)
InputQueueCharacters.push_back((ImWchar)c);
}

// UTF16 string use Surrogate to encode unicode > 0x10000, so we should save the Surrogate.
void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
{
if (c >= 0xD800 && c <= 0xDBFF)
{
Surrogate = c;
}
else
{
ImWchar cp = c;
if (c >= 0xDC00 && c <= 0xDFFF)
{
if (sizeof(ImWchar) == 2)
cp = 0xFFFD;
else
cp = ((ImWchar)(Surrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000;
Surrogate = 0;
}
InputQueueCharacters.push_back(cp);
}
}

void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{
while (*utf8_chars != 0)
{
unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
if (c > 0 && c < 0x10000)
if (c > 0)
InputQueueCharacters.push_back((ImWchar)c);
}
}
Expand Down Expand Up @@ -1564,13 +1586,13 @@ FILE* ImFileOpen(const char* filename, const char* mode)
{
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__)
// We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can)
const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
ImVector<ImWchar> buf;
const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
ImVector<wchar_t> buf;
buf.resize(filename_wsize + mode_wsize);
ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
::MultiByteToWideChar(CP_UTF8, 0, filename, -1, &buf[0], filename_wsize);
::MultiByteToWideChar(CP_UTF8, 0, mode, -1,&buf[filename_wsize], mode_wsize);
return _wfopen(&buf[0], &buf[filename_wsize]);
#else
return fopen(filename, mode);
#endif
Expand Down Expand Up @@ -1676,6 +1698,8 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char*
c += (*str++ & 0x3f);
// utf-8 encodings of values used in surrogate pairs are invalid
if ((c & 0xFFFFF800) == 0xD800) return 4;
// If ImWchar is 16bit, use replacement character U+FFFD instead
if (sizeof(ImWchar) == 2 && c >= 0x10000) c = 0xFFFD;
*out_char = c;
return 4;
}
Expand All @@ -1693,8 +1717,7 @@ int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const cha
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0)
break;
if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
*buf_out++ = (ImWchar)c;
*buf_out++ = (ImWchar)c;
}
*buf_out = 0;
if (in_text_remaining)
Expand All @@ -1711,8 +1734,7 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0)
break;
if (c < 0x10000)
char_count++;
char_count++;
}
return char_count;
}
Expand All @@ -1732,11 +1754,15 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
buf[1] = (char)(0x80 + (c & 0x3f));
return 2;
}
if (c >= 0xdc00 && c < 0xe000)
if (c < 0x10000)
{
return 0;
if (buf_size < 3) return 0;
buf[0] = (char)(0xe0 + (c >> 12));
buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
buf[2] = (char)(0x80 + ((c ) & 0x3f));
return 3;
}
if (c >= 0xd800 && c < 0xdc00)
if (c < 0x110000)
{
if (buf_size < 4) return 0;
buf[0] = (char)(0xf0 + (c >> 18));
Expand All @@ -1745,14 +1771,8 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
buf[3] = (char)(0x80 + ((c ) & 0x3f));
return 4;
}
//else if (c < 0x10000)
{
if (buf_size < 3) return 0;
buf[0] = (char)(0xe0 + (c >> 12));
buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
buf[2] = (char)(0x80 + ((c ) & 0x3f));
return 3;
}
// Invalid code point, the max unicode is 0x10FFFF
return 0;
}

// Not optimal but we very rarely use this function.
Expand All @@ -1766,8 +1786,8 @@ static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
{
if (c < 0x80) return 1;
if (c < 0x800) return 2;
if (c >= 0xdc00 && c < 0xe000) return 0;
if (c >= 0xd800 && c < 0xdc00) return 4;
if (c < 0x10000) return 3;
if (c < 0x110000) return 4;
return 3;
}

Expand Down Expand Up @@ -9621,6 +9641,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl

#ifdef _MSC_VER
#pragma comment(lib, "user32")
#pragma comment(lib, "kernel32")
#endif

// Win32 clipboard implementation
Expand All @@ -9636,11 +9657,11 @@ static const char* GetClipboardTextFn_DefaultImpl(void*)
::CloseClipboard();
return NULL;
}
if (ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle))
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
{
int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
buf_local.resize(buf_len);
ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, buf_local.Data, buf_len, NULL, NULL);
}
::GlobalUnlock(wbuf_handle);
::CloseClipboard();
Expand All @@ -9651,15 +9672,15 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
{
if (!::OpenClipboard(NULL))
return;
const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
if (wbuf_handle == NULL)
{
::CloseClipboard();
return;
}
ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle);
ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
::GlobalUnlock(wbuf_handle);
::EmptyClipboard();
if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
Expand Down
22 changes: 14 additions & 8 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ struct ImGuiTextFilter; // Helper to parse and apply text filters (e
typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp)
#endif
typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string)
typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings.
#ifndef ImWchar
#define ImWchar ImWchar16
#endif
typedef unsigned short ImWchar16; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings.
typedef int ImWchar32; // A single 32bit character for keyboard input/display, define ImWchar to ImWchar32 to use it. See imconfig.h .
typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling
typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions
typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type
Expand Down Expand Up @@ -1419,6 +1423,7 @@ struct ImGuiIO

// Functions
IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input
IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually

Expand Down Expand Up @@ -1461,6 +1466,7 @@ struct ImGuiIO
float KeysDownDurationPrev[512]; // Previous duration the key has been down
float NavInputsDownDuration[ImGuiNavInput_COUNT];
float NavInputsDownDurationPrev[ImGuiNavInput_COUNT];
ImWchar16 Surrogate; // For AddInputCharacterUTF16
ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper.

IMGUI_API ImGuiIO();
Expand Down Expand Up @@ -2041,7 +2047,7 @@ struct ImFontGlyphRangesBuilder
ImVector<ImU32> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)

ImFontGlyphRangesBuilder() { Clear(); }
inline void Clear() { int size_in_bytes = 0x10000 / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }
inline void Clear() { int size_in_bytes = (sizeof(ImWchar) == 2 ? 0x10000 : 0x110000) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }
inline bool GetBit(int n) const { int off = (n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
inline void SetBit(int n) { int off = (n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
inline void AddChar(ImWchar c) { SetBit(c); } // Add character
Expand All @@ -2053,12 +2059,12 @@ struct ImFontGlyphRangesBuilder
// See ImFontAtlas::AddCustomRectXXX functions.
struct ImFontAtlasCustomRect
{
unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data.
unsigned int ID; // Input // User ID. Use <0x110000 to map into a font glyph, >=0x110000 for other/internal/custom texture data.
unsigned short Width, Height; // Input // Desired rectangle dimension
unsigned short X, Y; // Output // Packed position in Atlas
float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance
ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset
ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font
float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x110000): glyph xadvance
ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x110000): glyph display offset
ImFont* Font; // Input // For custom font glyphs only (ID<0x110000): target font
ImFontAtlasCustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; }
bool IsPacked() const { return X != 0xFFFF; }
};
Expand Down Expand Up @@ -2138,8 +2144,8 @@ struct ImFontAtlas
// You can also request your rectangles to be mapped as font glyph (given a font + Unicode point),
// so you can render e.g. custom colorful icons and use them as regular glyphs.
// Read misc/fonts/README.txt for more details about using colorful icons.
IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font.
IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x110000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x110000 to register a rectangle to map into a specific font.
const ImFontAtlasCustomRect*GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; }

// [Internal]
Expand Down
2 changes: 1 addition & 1 deletion imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3331,7 +3331,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{
// Display all glyphs of the fonts in separate pages of 256 characters
for (int base = 0; base < 0x10000; base += 256)
for (int base = 0; base <= 0x10FFFF; base += 256)
{
int count = 0;
for (int n = 0; n < 256; n++)
Expand Down
10 changes: 5 additions & 5 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed

int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
{
IM_ASSERT(id >= 0x10000);
IM_ASSERT(id > 0x10FFFF);
IM_ASSERT(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF);
ImFontAtlasCustomRect r;
Expand Down Expand Up @@ -1909,6 +1909,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
{
if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)
continue;

if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font?
continue;

Expand Down Expand Up @@ -2189,7 +2190,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
for (int i = 0; i < atlas->CustomRects.Size; i++)
{
const ImFontAtlasCustomRect& r = atlas->CustomRects[i];
if (r.Font == NULL || r.ID > 0x10000)
if (r.Font == NULL || r.ID > 0x10FFFF)
continue;

IM_ASSERT(r.Font->ContainerAtlas == atlas);
Expand Down Expand Up @@ -2453,8 +2454,7 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
text += c_len;
if (c_len == 0)
break;
if (c < 0x10000)
AddChar((ImWchar)c);
AddChar((ImWchar)c);
}
}

Expand All @@ -2467,7 +2467,7 @@ void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)

void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
{
int max_codepoint = 0x10000;
int max_codepoint = 0x110000;
for (int n = 0; n < max_codepoint; n++)
if (GetBit(n))
{
Expand Down
4 changes: 2 additions & 2 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3148,7 +3148,7 @@ namespace ImStb
static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; }
static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); }
static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10FFFF ? 0 : key; }
static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
{
Expand Down Expand Up @@ -3741,7 +3741,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
s += ImTextCharFromUtf8(&c, s, NULL);
if (c == 0)
break;
if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, callback_user_data))
if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data))
continue;
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
}
Expand Down

0 comments on commit 853dac3

Please sign in to comment.