Skip to content

Commit

Permalink
Full Unicode Support
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudwu committed May 8, 2019
1 parent 3bedb30 commit a9c741c
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 46 deletions.
4 changes: 2 additions & 2 deletions examples/imgui_impl_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
g_PrevUserCallbackChar(window, c);

ImGuiIO& io = ImGui::GetIO();
if (c > 0 && c < 0x10000)
io.AddInputCharacter((unsigned short)c);
if (c > 0 && c <= 0x10FFFF)
io.AddInputCharacter(c);
}

static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
Expand Down
2 changes: 1 addition & 1 deletion examples/imgui_impl_glut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
//printf("char_down_func %d '%c'\n", c, c);
ImGuiIO& io = ImGui::GetIO();
if (c >= 32)
io.AddInputCharacter((unsigned short)c);
io.AddInputCharacter(c);

// Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.
Expand Down
4 changes: 2 additions & 2 deletions examples/imgui_impl_marmalade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
{
ImGuiIO& io = ImGui::GetIO();
s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
if ((e->m_Char > 0 && e->m_Char < 0x10000))
io.AddInputCharacter((unsigned short)e->m_Char);
if ((e->m_Char > 0 && e->m_Char <= 0x10FFFF))
io.AddInputCharacter(e->m_Char);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion examples/imgui_impl_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if (wParam > 0 && wParam < 0x10000)
io.AddInputCharacter((unsigned short)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 @@ -64,6 +64,9 @@
//---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it.
//#define ImDrawIdx unsigned int

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

//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
Expand Down
12 changes: 6 additions & 6 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ void ImGuiIO::AddInputCharacter(ImWchar c)
}

// UTF16 string use Surrogate to encode unicode > 0x10000, so we should save the Surrogate.
void ImGuiIO::AddInputCharacterUTF16(ImWchar c)
void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
{
if (c >= 0xD800 && c <= 0xDBFF)
{
Expand All @@ -1282,7 +1282,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{
unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
if (c > 0 && c <= 0xFFFF)
if (c > 0)
InputQueueCharacters.push_back((ImWchar)c);
}
}
Expand Down Expand Up @@ -1690,6 +1690,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 @@ -1707,8 +1709,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 @@ -1725,8 +1726,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 Down
27 changes: 17 additions & 10 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,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 Set*()
typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type
Expand Down Expand Up @@ -1403,7 +1407,7 @@ struct ImGuiIO

// Functions
IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input
IMGUI_API void AddInputCharacterUTF16(ImWchar c); // Queue new character input from an UTF-16 character, it can be a surrogate
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 @@ -1446,7 +1450,7 @@ struct ImGuiIO
float KeysDownDurationPrev[512]; // Previous duration the key has been down
float NavInputsDownDuration[ImGuiNavInput_COUNT];
float NavInputsDownDurationPrev[ImGuiNavInput_COUNT];
ImWchar Surrogate; // For AddInputCharacterUTF16
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 @@ -1997,7 +2001,10 @@ struct ImFontGlyphRangesBuilder
{
ImVector<int> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)

ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / sizeof(int)); memset(UsedChars.Data, 0, 0x10000 / sizeof(int)); }
ImFontGlyphRangesBuilder() {
int MaxUnicode = sizeof(ImWchar) == 2 ? 0x10000 : 0x110000;
UsedChars.resize(MaxUnicode / sizeof(int)); memset(UsedChars.Data, 0, MaxUnicode / sizeof(int));
}
bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
void AddChar(ImWchar c) { SetBit(c); } // Add character
Expand Down Expand Up @@ -2080,18 +2087,18 @@ 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.
struct CustomRect
{
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 <=0x10FFFF to map into a font glyph, >0x10FFFF 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<=0x10FFFF): glyph xadvance
ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<=0x10FFFF): glyph display offset
ImFont* Font; // Input // For custom font glyphs only (ID<=0x10FFFF): target font
CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; }
bool IsPacked() const { return X != 0xFFFF; }
};

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 > 0x10FFFF. 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 <= 0x10FFFF to register a rectangle to map into a specific font.
const CustomRect* 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 @@ -3078,7 +3078,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
13 changes: 7 additions & 6 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1666,7 +1666,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);
CustomRect r;
Expand Down Expand Up @@ -1850,6 +1850,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 @@ -2130,7 +2131,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
for (int i = 0; i < atlas->CustomRects.Size; i++)
{
const ImFontAtlas::CustomRect& 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 @@ -2377,8 +2378,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 @@ -2391,11 +2391,11 @@ void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)

void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
{
for (int n = 0; n < 0x10000; n++)
for (int n = 0; n <= 0x10FFFF; n++)
if (GetBit(n))
{
out_ranges->push_back((ImWchar)n);
while (n < 0x10000 && GetBit(n + 1))
while (n <= 0x10FFFF && GetBit(n + 1))
n++;
out_ranges->push_back((ImWchar)n);
}
Expand Down Expand Up @@ -2542,6 +2542,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1)
return FallbackGlyph;

return &Glyphs.Data[i];
}

Expand Down
34 changes: 17 additions & 17 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3033,7 +3033,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; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->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 @@ -3107,21 +3107,21 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im
}

// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)
#define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left
#define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right
#define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up
#define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down
#define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line
#define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line
#define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text
#define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text
#define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor
#define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor
#define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo
#define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo
#define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word
#define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word
#define STB_TEXTEDIT_K_SHIFT 0x20000
#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left
#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right
#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up
#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down
#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line
#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line
#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text
#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text
#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor
#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor
#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo
#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo
#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word
#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word
#define STB_TEXTEDIT_K_SHIFT 0x400000

#define STB_TEXTEDIT_IMPLEMENTATION
#include "imstb_textedit.h"
Expand Down Expand Up @@ -3626,7 +3626,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 a9c741c

Please sign in to comment.