mirror of https://github.com/ocornut/imgui
fix build for WideCharToMultiByte [3181ff1e] Full Unicode Support [6c9e73ac] Fix ImTextCountUtf8BytesFromChar and ImTextCharToUtf8, these APIs assume the input is an unicode code point, not UTF-16 [ba85665b] Add AddInputCharacterUTF16 for windows backend to handle WM_CHAR [fafdcaf0] Use Windows API to convert UTF-16 for ImFileOpen [dc7d5925] Use windows API to convert UTF-16 for clipboard
This commit is contained in:
parent
8c683de33f
commit
6d59653e82
|
@ -324,7 +324,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())
|
||||||
|
|
|
@ -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;
|
||||||
|
|
78
imgui.cpp
78
imgui.cpp
|
@ -1098,13 +1098,35 @@ void ImGuiIO::AddInputCharacter(unsigned int c)
|
||||||
InputQueueCharacters.push_back((ImWchar)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 = IM_UNICODE_CODEPOINT_INVALID;
|
||||||
|
else
|
||||||
|
cp = ((ImWchar)(Surrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000;
|
||||||
|
Surrogate = 0;
|
||||||
|
}
|
||||||
|
InputQueueCharacters.push_back(cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
||||||
{
|
{
|
||||||
while (*utf8_chars != 0)
|
while (*utf8_chars != 0)
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1488,13 +1510,13 @@ 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;
|
const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
|
||||||
const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
|
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, &buf[0], filename_wsize);
|
||||||
ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
|
::MultiByteToWideChar(CP_UTF8, 0, mode, -1,&buf[filename_wsize], mode_wsize);
|
||||||
return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
|
return _wfopen(&buf[0], &buf[filename_wsize]);
|
||||||
#else
|
#else
|
||||||
return fopen(filename, mode);
|
return fopen(filename, mode);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1606,6 +1628,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 ImWchar is 16bit, use replacement character U+FFFD instead
|
||||||
|
if (sizeof(ImWchar) == 2 && c >= 0x10000) c = IM_UNICODE_CODEPOINT_INVALID;
|
||||||
*out_char = c;
|
*out_char = c;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -1623,7 +1647,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 +1664,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 +1684,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 +1701,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 +1716,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 +9768,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 +9781,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 +9797,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 +9812,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)
|
||||||
|
|
14
imgui.h
14
imgui.h
|
@ -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 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 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 Surrogate; // 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();
|
||||||
|
@ -2092,7 +2098,11 @@ struct ImFontGlyphRangesBuilder
|
||||||
ImVector<ImU32> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
|
ImVector<ImU32> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
|
||||||
|
|
||||||
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 MaxUnicode = sizeof(ImWchar) == 2 ? 0x10000 : 0x110000;
|
||||||
|
UsedChars.resize(MaxUnicode / sizeof(int)); memset(UsedChars.Data, 0, MaxUnicode / sizeof(int));
|
||||||
|
}
|
||||||
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(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 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
|
inline void AddChar(ImWchar c) { SetBit(c); } // Add character
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue