diff --git a/TODO.txt b/TODO.txt index 3cd9af46..3fff67ed 100644 --- a/TODO.txt +++ b/TODO.txt @@ -261,7 +261,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - viewport: popup/tooltip glitches when appearing near the monitor limits (e.g. opening a menu). - viewport: platform: introduce getfocus/setfocus api, so e.g. focus flags can be honored, imgui-side ctrl-tab can focus os window, OS alt-tab can focus imgui window etc. - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for. - - viewport: IME positioning are wrong. - viewport: vulkan renderer implementation. - viewport: need to clarify how to use GetMousePos() from a user point of view. diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp index c82b7cc8..d9cde6d1 100644 --- a/examples/imgui_impl_allegro5.cpp +++ b/examples/imgui_impl_allegro5.cpp @@ -199,10 +199,6 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y; io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z; -#ifdef _WIN32 - io.ImeWindowHandle = al_get_win_window_handle(g_Display); -#endif - return true; } diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 19fa93d3..0c74aa2c 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -150,9 +150,6 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; io.ClipboardUserData = g_Window; -#ifdef _WIN32 - io.ImeWindowHandle = glfwGetWin32Window(g_Window); -#endif g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); @@ -500,7 +497,33 @@ static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*) glfwSwapBuffers(data->Window); } +//-------------------------------------------------------------------------------------------------------- +// IME (Input Method Editor) basic support for e.g. Asian language users +//-------------------------------------------------------------------------------------------------------- + +// We provide a Win32 implementation because this is such a common issue for IME users +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(__GNUC__) +#define HAS_WIN32_IME 1 +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif +static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos) +{ + COMPOSITIONFORM cf = { CFS_FORCE_POSITION, { (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) }, { 0, 0, 0, 0 } }; + if (ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData) + if (HWND hwnd = glfwGetWin32Window(data->Window)) + if (HIMC himc = ImmGetContext(hwnd)) + ImmSetCompositionWindow(himc, &cf); +} +#else +#define HAS_WIN32_IME 0 +#endif + +//-------------------------------------------------------------------------------------------------------- // Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) +//-------------------------------------------------------------------------------------------------------- + // Avoid including so we can build without it #if GLFW_HAS_VULKAN #ifndef VULKAN_H_ @@ -571,6 +594,9 @@ static void ImGui_ImplGlfw_InitPlatformInterface() #if GLFW_HAS_VULKAN platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface; #endif +#if HAS_WIN32_IME + platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos; +#endif ImGui_ImplGlfw_UpdateMonitors(); diff --git a/examples/imgui_impl_sdl2.cpp b/examples/imgui_impl_sdl2.cpp index 4342afbb..6b25e906 100644 --- a/examples/imgui_impl_sdl2.cpp +++ b/examples/imgui_impl_sdl2.cpp @@ -170,13 +170,6 @@ bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context) g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); -#ifdef _WIN32 - SDL_SysWMinfo wmInfo; - SDL_VERSION(&wmInfo.version); - SDL_GetWindowWMInfo(window, &wmInfo); - io.ImeWindowHandle = wmInfo.info.win.window; -#endif - // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = (void*)window; diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 13257360..b90b7a26 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -76,8 +76,6 @@ bool ImGui_ImplWin32_Init(void* hwnd) io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Z] = 'Z'; - io.ImeWindowHandle = g_hWnd; - return true; } @@ -279,7 +277,7 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa return 0; } -// -------------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------- // DPI handling // Those in theory should be simple calls but Windows has multiple ways to handle DPI, and most of them // require recent Windows versions at runtime or recent Windows SDK at compile-time. Neither we want to depend on. @@ -370,9 +368,30 @@ float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2) return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); } -// -------------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------- +// IME (Input Method Editor) basic support for e.g. Asian language users +//-------------------------------------------------------------------------------------------------------- + +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(__GNUC__) +#define HAS_WIN32_IME 1 +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif +static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos) +{ + COMPOSITIONFORM cf = { CFS_FORCE_POSITION,{ (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) },{ 0, 0, 0, 0 } }; + if (HWND hwnd = (HWND)viewport->PlatformHandle) + if (HIMC himc = ImmGetContext(hwnd)) + ImmSetCompositionWindow(himc, &cf); +} +#else +#define HAS_WIN32_IME 0 +#endif + +//-------------------------------------------------------------------------------------------------------- // Platform Windows -// -------------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------- struct ImGuiViewportDataWin32 { @@ -625,6 +644,9 @@ static void ImGui_ImplWin32_InitPlatformInterface() platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha; platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI +#if HAS_WIN32_IME + platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos; +#endif // Register main window handle (which is owned by the main application, not by us) ImGuiViewport* main_viewport = ImGui::GetMainViewport(); diff --git a/imgui.cpp b/imgui.cpp index 95c2d2bc..ca967ec1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -262,6 +262,8 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2018/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. + - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. - 2018/03/20 (1.60) - Renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). - 2018/03/12 (1.60) - Removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. @@ -617,10 +619,7 @@ Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. Text input: it is up to your application to pass the right character code by calling - io.AddInputCharacter(). The applications in examples/ are doing that. For languages relying - on an Input Method Editor (IME), on Windows you can copy the Hwnd of your application in the - io.ImeWindowHandle field. The default implementation of io.ImeSetInputScreenPosFn() will set - your Microsoft IME position correctly. + io.AddInputCharacter(). The applications in examples/ are doing that. Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) A: - You can create a dummy window. Call SetNextWindowBgAlpha(0.0f), call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flags. @@ -771,7 +770,6 @@ static void SetCurrentViewport(ImGuiViewportP* viewport); static const char* GetClipboardTextFn_DefaultImpl(void* user_data); static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); //----------------------------------------------------------------------------- // Context @@ -907,8 +905,6 @@ ImGuiIO::ImGuiIO() GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; ClipboardUserData = NULL; - ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; - ImeWindowHandle = NULL; #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS RenderDrawListsFn = NULL; @@ -3924,7 +3920,8 @@ void ImGui::NewFrame() g.MouseCursor = ImGuiMouseCursor_Arrow; g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; - g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + g.PlatformImePosViewport = NULL; // Mouse wheel scrolling, scale if (g.HoveredWindow && !g.HoveredWindow->Collapsed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f)) @@ -4464,10 +4461,11 @@ void ImGui::EndFrame() return; // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) - if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.OsImePosRequest - g.OsImePosSet) > 0.0001f) + if (g.PlatformIO.Platform_SetImeInputPos && g.PlatformImePosViewport != NULL && ImLengthSqr(g.PlatformImePos - g.PlatformImeLastPos) > 0.0001f) { - g.IO.ImeSetInputScreenPosFn((int)g.OsImePosRequest.x, (int)g.OsImePosRequest.y); - g.OsImePosSet = g.OsImePosRequest; + g.PlatformIO.Platform_SetImeInputPos(g.PlatformImePosViewport, g.PlatformImePos); + g.PlatformImeLastPos = g.PlatformImePos; + g.PlatformImePosViewport = NULL; } // Hide implicit "Debug" window if it hasn't been used @@ -11316,7 +11314,10 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (is_editable) - g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); + { + g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); + g.PlatformImePosViewport = window->Viewport; + } } else { @@ -14027,34 +14028,6 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text) #endif -// Win32 API IME support (for Asian languages, etc.) -#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) - -#include -#ifdef _MSC_VER -#pragma comment(lib, "imm32") -#endif - -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) -{ - // Notify OS Input Method Editor of text input position - if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle) - if (HIMC himc = ImmGetContext(hwnd)) - { - COMPOSITIONFORM cf; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - cf.dwStyle = CFS_FORCE_POSITION; - ImmSetCompositionWindow(himc, &cf); - } -} - -#else - -static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} - -#endif - //----------------------------------------------------------------------------- // HELP //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 95815a99..3396d048 100644 --- a/imgui.h +++ b/imgui.h @@ -1059,11 +1059,6 @@ struct ImGuiIO void (*SetClipboardTextFn)(void* user_data, const char* text); void* ClipboardUserData; - // Optional: notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME in Windows) - // (default to use native imm32 api on Windows) - void (*ImeSetInputScreenPosFn)(int x, int y); - void* ImeWindowHandle; // (Windows) Set this to your HWND to get automatic IME cursor positioning. - #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // [OBSOLETE] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). // See example applications if you are unsure of how to implement this. @@ -1896,7 +1891,7 @@ struct ImGuiPlatformIO // Input - Back-end interface/functions + Monitor List //------------------------------------------------------------------ - // Platform functions (e.g. Win32, GLFW, SDL2) + // (Optional) Platform functions (e.g. Win32, GLFW, SDL2) void (*Platform_CreateWindow)(ImGuiViewport* vp); // Create a new platform window for the given viewport void (*Platform_DestroyWindow)(ImGuiViewport* vp); void (*Platform_ShowWindow)(ImGuiViewport* vp); // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them first @@ -1910,16 +1905,17 @@ struct ImGuiPlatformIO void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (platform side) float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. (FIXME-DPI) void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // (Optional) DPI handling: Called during Begin() every time the viewport we are outputting into changes, so back-end has a chance to swap fonts to adjust style. + void (*Platform_SetImeInputPos)(ImGuiViewport* vp, ImVec2 pos); // (Optional) Set IME (Input Method Editor, e.g. for Asian languages) input position, so text preview appears over the imgui input box. int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For Renderer to call into Platform code - // Renderer functions (e.g. DirectX, OpenGL3, Vulkan) + // (Optional) Renderer functions (e.g. DirectX, OpenGL3, Vulkan) void (*Renderer_CreateWindow)(ImGuiViewport* vp); // Create swap chains, frame buffers etc. void (*Renderer_DestroyWindow)(ImGuiViewport* vp); void (*Renderer_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // Resize swap chain, frame buffers etc. void (*Renderer_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Clear targets, Render viewport->DrawData void (*Renderer_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (renderer side) - // List of monitors (updated by: app/back-end, used by: imgui to clamp popups/tooltips within same monitor and not have them straddle monitors) + // (Optional) List of monitors (updated by: app/back-end, used by: imgui to clamp popups/tooltips within same monitor and not have them straddle monitors) ImVector Monitors; //------------------------------------------------------------------ diff --git a/imgui_internal.h b/imgui_internal.h index f3377152..4dd7c9ba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -715,7 +715,10 @@ struct ImGuiContext ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? int TooltipOverrideCount; ImVector PrivateClipboard; // If no custom clipboard handler is defined - ImVec2 OsImePosRequest, OsImePosSet; // Cursor position request & last passed to the OS Input Method Editor + + // Platform support + ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor + ImGuiViewport* PlatformImePosViewport; // Settings bool SettingsLoaded; @@ -822,7 +825,8 @@ struct ImGuiContext DragSpeedScaleFast = 10.0f; ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); TooltipOverrideCount = 0; - OsImePosRequest = OsImePosSet = ImVec2(-1.0f, -1.0f); + PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + PlatformImePosViewport = 0; SettingsLoaded = false; SettingsDirtyTimer = 0.0f;