Merge branch 'features/unicode'

This commit is contained in:
ocornut 2020-03-03 18:59:54 +01:00
commit b029182a73
8 changed files with 143 additions and 46 deletions

View File

@ -54,7 +54,7 @@ jobs:
- name: Build example_null (single file build) - name: Build example_null (single file build)
shell: bash shell: bash
run: | run: |
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp
@ -190,6 +190,14 @@ jobs:
- name: Build example_null (single file build) - name: Build example_null (single file build)
run: | run: |
echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
- name: Build example_null (with ImWchar32)
run: |
echo '#define ImWchar ImWchar32' > example_single_file.cpp
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
@ -226,7 +234,7 @@ jobs:
- name: Build example_null (single file build) - name: Build example_null (single file build)
run: | run: |
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp echo '#define IMGUI_IMPLEMENTATION' > example_single_file.cpp
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp echo '#include "examples/example_null/main.cpp"' >> example_single_file.cpp
clang++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp clang++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp

View File

@ -45,6 +45,15 @@ Other Changes:
when the menu is not open. (#3030) when the menu is not open. (#3030)
- InputText: Fixed password fields displaying ASCII spaces as blanks instead of using the '*' - InputText: Fixed password fields displaying ASCII spaces as blanks instead of using the '*'
glyph. (#2149, #515) glyph. (#2149, #515)
- Added optional support for Unicode plane 1-16 (#2538, #2541, #2815) [@cloudwu, @samhocevar]
- Compile-time enable with '#define ImWchar ImWchar32' in imconfig.h.
- Generally more consistent support for unsupported codepoints (0xFFFD), in particular when
using the default, non-fitting characters will be turned into 0xFFFD instead of being ignored.
- Surrogate pairs are supported when submitting UTF-16 data via io.AddInputCharacterUTF16(),
allowing for more complete CJK input.
- sizeof(ImWchar) goes from 2 to 4. IM_UNICODE_CODEPOINT_MAX goes from 0xFFFF to 0x10FFFF.
- Various structures such as ImFont, ImFontGlyphRangesBuilder will use more memory, this
is currently not particularly efficient.
- Window: Fixed a bug with child window inheriting ItemFlags from their parent when the child - Window: Fixed a bug with child window inheriting ItemFlags from their parent when the child
window also manipulate the ItemFlags stack. (#3024) [@Stanbroek] window also manipulate the ItemFlags stack. (#3024) [@Stanbroek]
- Font: Fixed non-ASCII space occasionally creating unnecessary empty polygons. - Font: Fixed non-ASCII space occasionally creating unnecessary empty polygons.
@ -53,6 +62,8 @@ Other Changes:
ImGui_ImplWin32_GetDpiScaleForMonitor() helpers functions (backported from the docking branch). ImGui_ImplWin32_GetDpiScaleForMonitor() helpers functions (backported from the docking branch).
Those functions makes it easier for example apps to support hi-dpi features without setting up Those functions makes it easier for example apps to support hi-dpi features without setting up
a manifest. a manifest.
- Backends: Win32: Calling AddInputCharacterUTF16() from WM_CHAR message handler in order to support
high-plane surrogate pairs. (#2815) [@cloudwu, @samhocevar]
- Backends: SDL: Added ImGui_ImplSDL2_InitForMetal() for API consistency (even though the function - Backends: SDL: Added ImGui_ImplSDL2_InitForMetal() for API consistency (even though the function
currently does nothing). currently does nothing).
- Backends: SDL: Fixed mapping for ImGuiKey_KeyPadEnter. (#3031) [@Davido71] - Backends: SDL: Fixed mapping for ImGuiKey_KeyPadEnter. (#3031) [@Davido71]

View File

@ -28,6 +28,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions. // 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT. // 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor. // 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
@ -324,7 +325,8 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
return 0; return 0;
case WM_CHAR: case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters. // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
io.AddInputCharacter((unsigned int)wParam); if (wParam > 0 && wParam < 0x10000)
io.AddInputCharacterUTF16((unsigned short)wParam);
return 0; return 0;
case WM_SETCURSOR: case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())

View File

@ -77,6 +77,9 @@
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. // Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int //#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) //---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly)
//struct ImDrawList; //struct ImDrawList;
//struct ImDrawCmd; //struct ImDrawCmd;

View File

@ -1094,8 +1094,33 @@ ImGuiIO::ImGuiIO()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
void ImGuiIO::AddInputCharacter(unsigned int c) void ImGuiIO::AddInputCharacter(unsigned int c)
{ {
if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX) InputQueueCharacters.push_back(c > 0 && c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
InputQueueCharacters.push_back((ImWchar)c); }
// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
// we should save the high surrogate.
void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
{
if ((c & 0xFC00) == 0xD800) // High surrogate, must save
{
if (InputQueueSurrogate != 0)
InputQueueCharacters.push_back(0xFFFD);
InputQueueSurrogate = c;
return;
}
ImWchar cp = c;
if (InputQueueSurrogate != 0)
{
if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang)
cp = IM_UNICODE_CODEPOINT_INVALID;
else
cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
InputQueueSurrogate = 0;
}
InputQueueCharacters.push_back(cp);
} }
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
@ -1104,7 +1129,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{ {
unsigned int c = 0; unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX) if (c > 0)
InputQueueCharacters.push_back((ImWchar)c); InputQueueCharacters.push_back((ImWchar)c);
} }
} }
@ -1484,17 +1509,30 @@ ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
// Default file functions // Default file functions
#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef __MINGW32__
#include <Windows.h>
#else
#include <windows.h>
#endif
#endif
ImFileHandle ImFileOpen(const char* filename, const char* mode) ImFileHandle ImFileOpen(const char* filename, const char* mode)
{ {
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
// We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; 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<ImWchar> buf; ImVector<ImWchar> buf;
buf.resize(filename_wsize + mode_wsize); buf.resize(filename_wsize + mode_wsize);
ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL); ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL); ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]); return _wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
#else #else
return fopen(filename, mode); return fopen(filename, mode);
#endif #endif
@ -1606,6 +1644,8 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char*
c += (*str++ & 0x3f); c += (*str++ & 0x3f);
// utf-8 encodings of values used in surrogate pairs are invalid // utf-8 encodings of values used in surrogate pairs are invalid
if ((c & 0xFFFFF800) == 0xD800) return 4; if ((c & 0xFFFFF800) == 0xD800) return 4;
// If codepoint does not fit in ImWchar, use replacement character U+FFFD instead
if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID;
*out_char = c; *out_char = c;
return 4; return 4;
} }
@ -1623,7 +1663,6 @@ int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const cha
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0) if (c == 0)
break; break;
if (c <= IM_UNICODE_CODEPOINT_MAX) // FIXME: Losing characters that don't fit in 2 bytes
*buf_out++ = (ImWchar)c; *buf_out++ = (ImWchar)c;
} }
*buf_out = 0; *buf_out = 0;
@ -1641,7 +1680,6 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0) if (c == 0)
break; break;
if (c <= IM_UNICODE_CODEPOINT_MAX)
char_count++; char_count++;
} }
return char_count; return char_count;
@ -1662,11 +1700,15 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
buf[1] = (char)(0x80 + (c & 0x3f)); buf[1] = (char)(0x80 + (c & 0x3f));
return 2; 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 <= 0x10FFFF)
{ {
if (buf_size < 4) return 0; if (buf_size < 4) return 0;
buf[0] = (char)(0xf0 + (c >> 18)); buf[0] = (char)(0xf0 + (c >> 18));
@ -1675,14 +1717,8 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
buf[3] = (char)(0x80 + ((c ) & 0x3f)); buf[3] = (char)(0x80 + ((c ) & 0x3f));
return 4; return 4;
} }
//else if (c < 0x10000) // Invalid code point, the max unicode is 0x10FFFF
{ 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;
}
} }
// Not optimal but we very rarely use this function. // Not optimal but we very rarely use this function.
@ -1696,8 +1732,8 @@ static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
{ {
if (c < 0x80) return 1; if (c < 0x80) return 1;
if (c < 0x800) return 2; if (c < 0x800) return 2;
if (c >= 0xdc00 && c < 0xe000) return 0; if (c < 0x10000) return 3;
if (c >= 0xd800 && c < 0xdc00) return 4; if (c <= 0x10FFFF) return 4;
return 3; return 3;
} }
@ -9748,6 +9784,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
#else #else
#include <windows.h> #include <windows.h>
#endif #endif
#include <stringapiset.h>
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions
#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
@ -9760,6 +9797,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma comment(lib, "user32") #pragma comment(lib, "user32")
#pragma comment(lib, "kernel32")
#endif #endif
// Win32 clipboard implementation // Win32 clipboard implementation
@ -9775,11 +9813,11 @@ static const char* GetClipboardTextFn_DefaultImpl(void*)
::CloseClipboard(); ::CloseClipboard();
return NULL; 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); 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); ::GlobalUnlock(wbuf_handle);
::CloseClipboard(); ::CloseClipboard();
@ -9790,15 +9828,15 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
{ {
if (!::OpenClipboard(NULL)) if (!::OpenClipboard(NULL))
return; return;
const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
if (wbuf_handle == NULL) if (wbuf_handle == NULL)
{ {
::CloseClipboard(); ::CloseClipboard();
return; return;
} }
ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle); WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
::GlobalUnlock(wbuf_handle); ::GlobalUnlock(wbuf_handle);
::EmptyClipboard(); ::EmptyClipboard();
if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)

16
imgui.h
View File

@ -92,7 +92,7 @@ Index of this file:
#else #else
#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro.
#endif #endif
#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Last Unicode code point supported by this build. #define IM_UNICODE_CODEPOINT_MAX (sizeof(ImWchar) == 2 ? 0xFFFF : 0x10FFFF) // Last Unicode code point supported by this build.
#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Standard invalid Unicode code point. #define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Standard invalid Unicode code point.
// Warnings // Warnings
@ -143,7 +143,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) 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 #endif
typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) 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 unsigned int ImWchar32; // A single U32 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 ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling
typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions
typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type
@ -1465,6 +1469,7 @@ struct ImGuiIO
// Functions // Functions
IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input 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 AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually
@ -1507,6 +1512,7 @@ struct ImGuiIO
float KeysDownDurationPrev[512]; // Previous duration the key has been down float KeysDownDurationPrev[512]; // Previous duration the key has been down
float NavInputsDownDuration[ImGuiNavInput_COUNT]; float NavInputsDownDuration[ImGuiNavInput_COUNT];
float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; float NavInputsDownDurationPrev[ImGuiNavInput_COUNT];
ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16
ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper. ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper.
IMGUI_API ImGuiIO(); IMGUI_API ImGuiIO();
@ -2093,8 +2099,8 @@ struct ImFontGlyphRangesBuilder
ImFontGlyphRangesBuilder() { Clear(); } ImFontGlyphRangesBuilder() { Clear(); }
inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 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 = (IM_UNICODE_CODEPOINT_MAX + 1) / 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 bool GetBit(size_t n) const { int off = (int)(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 SetBit(size_t n) { int off = (int)(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 inline void AddChar(ImWchar c) { SetBit(c); } // Add character
IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
@ -2251,6 +2257,7 @@ struct ImFont
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations accross all used codepoints.
// Methods // Methods
IMGUI_API ImFont(); IMGUI_API ImFont();
@ -2276,6 +2283,7 @@ struct ImFont
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); IMGUI_API void SetGlyphVisible(ImWchar c, bool visible);
IMGUI_API void SetFallbackChar(ImWchar c); IMGUI_API void SetFallbackChar(ImWchar c);
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
}; };
#if defined(__clang__) #if defined(__clang__)

View File

@ -3443,6 +3443,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
// Display all glyphs of the fonts in separate pages of 256 characters // Display all glyphs of the fonts in separate pages of 256 characters
for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
{ {
// Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
// This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT is large.
// (if ImWchar==ImWchar32 we will do at least about 272 queries here)
if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
{
base += 4096 - 256;
continue;
}
int count = 0; int count = 0;
for (unsigned int n = 0; n < 256; n++) for (unsigned int n = 0; n < 256; n++)
count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;

View File

@ -2550,7 +2550,6 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
text += c_len; text += c_len;
if (c_len == 0) if (c_len == 0)
break; break;
if (c <= IM_UNICODE_CODEPOINT_MAX)
AddChar((ImWchar)c); AddChar((ImWchar)c);
} }
} }
@ -2595,6 +2594,7 @@ ImFont::ImFont()
Scale = 1.0f; Scale = 1.0f;
Ascent = Descent = 0.0f; Ascent = Descent = 0.0f;
MetricsTotalSurface = 0; MetricsTotalSurface = 0;
memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
} }
ImFont::~ImFont() ImFont::~ImFont()
@ -2627,12 +2627,17 @@ void ImFont::BuildLookupTable()
IndexAdvanceX.clear(); IndexAdvanceX.clear();
IndexLookup.clear(); IndexLookup.clear();
DirtyLookupTables = false; DirtyLookupTables = false;
memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
GrowIndex(max_codepoint + 1); GrowIndex(max_codepoint + 1);
for (int i = 0; i < Glyphs.Size; i++) for (int i = 0; i < Glyphs.Size; i++)
{ {
int codepoint = (int)Glyphs[i].Codepoint; int codepoint = (int)Glyphs[i].Codepoint;
IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
IndexLookup[codepoint] = (ImWchar)i; IndexLookup[codepoint] = (ImWchar)i;
// Mark 4K page as used
const int page_n = codepoint / 4096;
Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
} }
// Create a glyph to handle TAB // Create a glyph to handle TAB
@ -2661,6 +2666,19 @@ void ImFont::BuildLookupTable()
IndexAdvanceX[i] = FallbackAdvanceX; IndexAdvanceX[i] = FallbackAdvanceX;
} }
// API is designed this way to avoid exposing the 4K page size
// e.g. use with IsGlyphRangeUnused(0, 255)
bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
{
unsigned int page_begin = (c_begin / 4096);
unsigned int page_last = (c_last / 4096);
for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
if ((page_n >> 3) < sizeof(Used4kPagesMap))
if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
return false;
return true;
}
void ImFont::SetGlyphVisible(ImWchar c, bool visible) void ImFont::SetGlyphVisible(ImWchar c, bool visible)
{ {
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
@ -2725,7 +2743,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
{ {
if (c >= IndexLookup.Size) if (c >= (size_t)IndexLookup.Size)
return FallbackGlyph; return FallbackGlyph;
const ImWchar i = IndexLookup.Data[c]; const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1) if (i == (ImWchar)-1)
@ -2735,7 +2753,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
{ {
if (c >= IndexLookup.Size) if (c >= (size_t)IndexLookup.Size)
return NULL; return NULL;
const ImWchar i = IndexLookup.Data[c]; const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1) if (i == (ImWchar)-1)