update Dear ImGui to 1.91.2

due to major changes around input text handling, I had to remove the multiline word wrap code...

also fix selectable highlight
This commit is contained in:
tildearrow 2025-08-11 14:06:16 -05:00
parent 51b2db864f
commit c6d5913686
17 changed files with 721 additions and 665 deletions

View file

@ -311,7 +311,8 @@ static void ImGui_ImplAllegro5_SetClipboardText(ImGuiContext*, const char* text)
} }
#endif #endif
static ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code) // Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code)
{ {
switch (key_code) switch (key_code)
{ {

View file

@ -21,6 +21,11 @@
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp // - Introduction, links and more at the top of imgui.cpp
// About Emscripten support:
// - Emscripten provides its own GLFW (3.2.1) implementation (syntax: "-sUSE_GLFW=3"), but Joystick is broken and several features are not supported (multiple windows, clipboard, timer, etc.)
// - A third-party Emscripten GLFW (3.4.0) implementation (syntax: "--use-port=contrib.glfw3") fixes the Joystick issue and implements all relevant features for the browser.
// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Comparison.md for details.
// 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)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
@ -210,9 +215,12 @@ static void ImGui_ImplGlfw_InitPlatformInterface();
static void ImGui_ImplGlfw_ShutdownPlatformInterface(); static void ImGui_ImplGlfw_ShutdownPlatformInterface();
// Functions // Functions
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
// Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode)
{ {
switch (key) IM_UNUSED(scancode);
switch (keycode)
{ {
case GLFW_KEY_TAB: return ImGuiKey_Tab; case GLFW_KEY_TAB: return ImGuiKey_Tab;
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
@ -380,6 +388,7 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
io.AddMouseWheelEvent((float)xoffset, (float)yoffset); io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
} }
// FIXME: should this be baked into ImGui_ImplGlfw_KeyToImGuiKey()? then what about the values passed to io.SetKeyEventNativeData()?
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
{ {
#if GLFW_HAS_GETKEYNAME && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) #if GLFW_HAS_GETKEYNAME && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3)
@ -430,7 +439,7 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode); ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode);
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
} }
@ -576,7 +585,7 @@ void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 3'4'0'20240817 #if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); } void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); }
#else #else
EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); });
@ -644,7 +653,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
if (install_callbacks) if (install_callbacks)
ImGui_ImplGlfw_InstallCallbacks(window); ImGui_ImplGlfw_InstallCallbacks(window);
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) // Update monitor a first time during init
// (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
ImGui_ImplGlfw_UpdateMonitors(); ImGui_ImplGlfw_UpdateMonitors();
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
@ -668,6 +678,23 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
#endif #endif
// Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime
// to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten).
#ifdef __EMSCRIPTEN__
#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
if (emscripten::glfw3::IsRuntimePlatformApple())
{
ImGui::GetIO().ConfigMacOSXBehaviors = true;
// Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used.
// This means that Meta + V only registers a single key-press, even if the keys are held.
// This is a compromise for dealing with this issue in ImGui since ImGui implements key repeat itself.
// See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key
emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10);
}
#endif
#endif
bd->ClientApi = client_api; bd->ClientApi = client_api;
return true; return true;
} }

View file

@ -289,7 +289,9 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
@end @end
// Functions // Functions
static ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code)
// Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code)
{ {
switch (key_code) switch (key_code)
{ {

View file

@ -26,6 +26,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)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190)
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
@ -129,7 +130,9 @@ extern "C" {
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9) #define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9)
#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18) #define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18)
#if !SDL_HAS_VULKAN #if SDL_HAS_VULKAN
extern "C" { extern DECLSPEC void SDLCALL SDL_Vulkan_GetDrawableSize(SDL_Window* window, int* w, int* h); }
#elif
static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
#endif #endif
@ -204,7 +207,8 @@ static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view
} }
} }
static ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) // Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode)
{ {
IM_UNUSED(scancode); IM_UNUSED(scancode);
switch (keycode) switch (keycode)
@ -528,7 +532,6 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
#else #else
bd->MouseCanReportHoveredViewport = false; bd->MouseCanReportHoveredViewport = false;
#endif #endif
bd->WantUpdateMonitors = true;
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
@ -539,6 +542,9 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; };
#endif #endif
// Update monitor a first time during init
ImGui_ImplSDL2_UpdateMonitors();
// Gamepad handling // Gamepad handling
bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst;
bd->WantUpdateGamepadsList = true; bd->WantUpdateGamepadsList = true;
@ -899,14 +905,19 @@ void ImGui_ImplSDL2_NewFrame()
SDL_GetWindowSize(bd->Window, &w, &h); SDL_GetWindowSize(bd->Window, &w, &h);
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED) if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
w = h = 0; w = h = 0;
if (bd->Renderer != NULL) { if (bd->Renderer != nullptr) {
if (SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h)!=0) { if (SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h)!=0) {
display_w=0; display_w=0;
display_h=0; display_h=0;
} }
} else {
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
} }
#if SDL_HAS_VULKAN
else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN)
SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h);
#endif
else
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
if (w > 0 && h > 0) { if (w > 0 && h > 0) {
io.DisplaySize = ImVec2((float)w, (float)h); io.DisplaySize = ImVec2((float)w, (float)h);
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);

View file

@ -13,7 +13,6 @@
// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue. // [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
// Issues: // Issues:
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). // [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -26,6 +25,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)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2024-09-11: (Docking) Added support for viewport->ParentViewportId field to support parenting at OS level. (#7973)
// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807) // 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807)
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
@ -172,7 +172,8 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view
} }
} }
static ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) // Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode)
{ {
// Keypad doesn't have individual key values in SDL3 // Keypad doesn't have individual key values in SDL3
switch (scancode) switch (scancode)
@ -509,13 +510,15 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
#else #else
bd->MouseCanReportHoveredViewport = false; bd->MouseCanReportHoveredViewport = false;
#endif #endif
bd->WantUpdateMonitors = true;
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText;
platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText;
platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData;
// Update monitor a first time during init
ImGui_ImplSDL3_UpdateMonitors();
// Gamepad handling // Gamepad handling
bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst;
bd->WantUpdateGamepadsList = true; bd->WantUpdateGamepadsList = true;
@ -905,20 +908,34 @@ void ImGui_ImplSDL3_NewFrame()
struct ImGui_ImplSDL3_ViewportData struct ImGui_ImplSDL3_ViewportData
{ {
SDL_Window* Window; SDL_Window* Window;
SDL_Window* ParentWindow;
Uint32 WindowID; Uint32 WindowID;
bool WindowOwned; bool WindowOwned;
SDL_GLContext GLContext; SDL_GLContext GLContext;
ImGui_ImplSDL3_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } ImGui_ImplSDL3_ViewportData() { Window = ParentWindow = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; }
~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } ~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); }
}; };
static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewportID(ImGuiID viewport_id)
{
if (viewport_id != 0)
if (ImGuiViewport* viewport = ImGui::FindViewportByID(viewport_id))
{
SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
return SDL_GetWindowFromID(window_id);
}
return nullptr;
}
static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport) static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport)
{ {
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)(); ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)();
viewport->PlatformUserData = vd; viewport->PlatformUserData = vd;
vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId);
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData; ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData;
@ -937,12 +954,10 @@ static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport)
sdl_flags |= SDL_GetWindowFlags(bd->Window); sdl_flags |= SDL_GetWindowFlags(bd->Window);
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
#if !defined(_WIN32)
// See SDL hack in ImGui_ImplSDL3_ShowWindow().
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_UTILITY : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_UTILITY : 0;
#endif
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
SDL_SetWindowParent(vd->Window, vd->ParentWindow);
SDL_SetWindowPosition(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); SDL_SetWindowPosition(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
vd->WindowOwned = true; vd->WindowOwned = true;
if (use_opengl) if (use_opengl)
@ -977,13 +992,14 @@ static void ImGui_ImplSDL3_ShowWindow(ImGuiViewport* viewport)
#if defined(_WIN32) #if defined(_WIN32)
HWND hwnd = (HWND)viewport->PlatformHandleRaw; HWND hwnd = (HWND)viewport->PlatformHandleRaw;
// SDL hack: Hide icon from task bar // SDL hack: Show icon in task bar (#7989)
// Note: SDL 3.0.0+ has a SDL_WINDOW_UTILITY flag which is supported under Windows but the way it create the window breaks our seamless transition. // Note: SDL_WINDOW_UTILITY can be used to control task bar visibility, but on Windows, it does not affect child windows.
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) if (!(viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon))
{ {
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
ex_style &= ~WS_EX_APPWINDOW; ex_style |= WS_EX_APPWINDOW;
ex_style |= WS_EX_TOOLWINDOW; ex_style &= ~WS_EX_TOOLWINDOW;
::ShowWindow(hwnd, SW_HIDE);
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
} }
#endif #endif
@ -992,6 +1008,20 @@ static void ImGui_ImplSDL3_ShowWindow(ImGuiViewport* viewport)
SDL_ShowWindow(vd->Window); SDL_ShowWindow(vd->Window);
} }
static void ImGui_ImplSDL3_UpdateWindow(ImGuiViewport* viewport)
{
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
// Update SDL3 parent if it changed _after_ creation.
// This is for advanced apps that are manipulating ParentViewportID manually.
SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId);
if (new_parent != vd->ParentWindow)
{
vd->ParentWindow = new_parent;
SDL_SetWindowParent(vd->Window, vd->ParentWindow);
}
}
static ImVec2 ImGui_ImplSDL3_GetWindowPos(ImGuiViewport* viewport) static ImVec2 ImGui_ImplSDL3_GetWindowPos(ImGuiViewport* viewport)
{ {
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
@ -1085,6 +1115,7 @@ static void ImGui_ImplSDL3_InitPlatformInterface(SDL_Window* window, void* sdl_g
platform_io.Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow; platform_io.Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow;
platform_io.Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow; platform_io.Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow;
platform_io.Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow; platform_io.Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow;
platform_io.Platform_UpdateWindow = ImGui_ImplSDL3_UpdateWindow;
platform_io.Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos; platform_io.Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos;
platform_io.Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos; platform_io.Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos;
platform_io.Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize; platform_io.Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize;

View file

@ -13,7 +13,6 @@
// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue. // [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
// Issues: // Issues:
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). // [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
// [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.

View file

@ -18,6 +18,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)
// 2024-09-16: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU define to handle ever-changing native implementations. (#7977)
// 2024-01-22: Added configurable PipelineMultisampleState struct. (#7240) // 2024-01-22: Added configurable PipelineMultisampleState struct. (#7240)
// 2024-01-22: (Breaking) ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure instead of variety of parameters, allowing for easier further changes. // 2024-01-22: (Breaking) ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure instead of variety of parameters, allowing for easier further changes.
// 2024-01-22: Fixed pipeline layout leak. (#7245) // 2024-01-22: Fixed pipeline layout leak. (#7245)
@ -37,6 +38,18 @@
// 2021-02-18: Change blending equation to preserve alpha in output buffer. // 2021-02-18: Change blending equation to preserve alpha in output buffer.
// 2021-01-28: Initial version. // 2021-01-28: Initial version.
// When targeting native platforms (i.e. NOT emscripten), one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN
// or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details.
#ifndef __EMSCRIPTEN__
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#error exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined!
#endif
#else
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#error neither IMGUI_IMPL_WEBGPU_BACKEND_DAWN nor IMGUI_IMPL_WEBGPU_BACKEND_WGPU may be defined if targeting emscripten!
#endif
#endif
#include "imgui.h" #include "imgui.h"
#ifndef IMGUI_DISABLE #ifndef IMGUI_DISABLE
#include "imgui_impl_wgpu.h" #include "imgui_impl_wgpu.h"
@ -247,7 +260,11 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; WGPUShaderModuleWGSLDescriptor wgsl_desc = {};
#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN
wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
#else
wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
#endif
wgsl_desc.code = wgsl_source; wgsl_desc.code = wgsl_source;
WGPUShaderModuleDescriptor desc = {}; WGPUShaderModuleDescriptor desc = {};
@ -662,7 +679,11 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
// Create depth-stencil State // Create depth-stencil State
WGPUDepthStencilState depth_stencil_state = {}; WGPUDepthStencilState depth_stencil_state = {};
depth_stencil_state.format = bd->depthStencilFormat; depth_stencil_state.format = bd->depthStencilFormat;
#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN
depth_stencil_state.depthWriteEnabled = WGPUOptionalBool_False;
#else
depth_stencil_state.depthWriteEnabled = false; depth_stencil_state.depthWriteEnabled = false;
#endif
depth_stencil_state.depthCompare = WGPUCompareFunction_Always; depth_stencil_state.depthCompare = WGPUCompareFunction_Always;
depth_stencil_state.stencilFront.compare = WGPUCompareFunction_Always; depth_stencil_state.stencilFront.compare = WGPUCompareFunction_Always;
depth_stencil_state.stencilFront.failOp = WGPUStencilOperation_Keep; depth_stencil_state.stencilFront.failOp = WGPUStencilOperation_Keep;
@ -732,7 +753,15 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
// Setup backend capabilities flags // Setup backend capabilities flags
ImGui_ImplWGPU_Data* bd = IM_NEW(ImGui_ImplWGPU_Data)(); ImGui_ImplWGPU_Data* bd = IM_NEW(ImGui_ImplWGPU_Data)();
io.BackendRendererUserData = (void*)bd; io.BackendRendererUserData = (void*)bd;
#if defined(__EMSCRIPTEN__)
io.BackendRendererName = "imgui_impl_webgpu_emscripten";
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
io.BackendRendererName = "imgui_impl_webgpu_dawn";
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
io.BackendRendererName = "imgui_impl_webgpu_wgpu";
#else
io.BackendRendererName = "imgui_impl_webgpu"; io.BackendRendererName = "imgui_impl_webgpu";
#endif
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
bd->initInfo = *init_info; bd->initInfo = *init_info;

View file

@ -2,6 +2,13 @@
// This needs to be used along with a Platform Binding (e.g. GLFW) // This needs to be used along with a Platform Binding (e.g. GLFW)
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.) // (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
// Important note to dawn and/or wgpu users: when targeting native platforms (i.e. NOT emscripten),
// one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided.
// Add #define to your imconfig.h file, or as a compilation flag in your build system.
// This requirement will be removed once WebGPU stabilizes and backends converge on a unified interface.
//#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
//#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.

View file

@ -23,6 +23,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)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2024-09-16: [Docking] Inputs: fixed an issue where a viewport destroyed while clicking would hog mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971)
// 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768)
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
// 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL). // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL).
@ -114,7 +115,7 @@ struct ImGui_ImplWin32_Data
{ {
HWND hWnd; HWND hWnd;
HWND MouseHwnd; HWND MouseHwnd;
int MouseTrackedArea; // 0: not tracked, 1: client are, 2: non-client area int MouseTrackedArea; // 0: not tracked, 1: client area, 2: non-client area
int MouseButtonsDown; int MouseButtonsDown;
INT64 Time; INT64 Time;
INT64 TicksPerSecond; INT64 TicksPerSecond;
@ -175,12 +176,14 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
bd->hWnd = (HWND)hwnd; bd->hWnd = (HWND)hwnd;
bd->WantUpdateMonitors = true;
bd->TicksPerSecond = perf_frequency; bd->TicksPerSecond = perf_frequency;
bd->Time = perf_counter; bd->Time = perf_counter;
bd->LastMouseCursor = ImGuiMouseCursor_COUNT; bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
ImGui_ImplWin32_UpdateKeyboardCodePage(); ImGui_ImplWin32_UpdateKeyboardCodePage();
// Update monitor a first time during init
ImGui_ImplWin32_UpdateMonitors();
// Our mouse update function expect PlatformHandle to be filled for the main viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd; main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd;
@ -492,12 +495,14 @@ void ImGui_ImplWin32_NewFrame()
ImGui_ImplWin32_UpdateGamepads(); ImGui_ImplWin32_UpdateGamepads();
} }
// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
// Map VK_xxx to ImGuiKey_xxx. // Map VK_xxx to ImGuiKey_xxx.
static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam) // Not static to allow third-party code to use that if they want to (but undocumented)
ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam)
{ {
// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED.
if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
return ImGuiKey_KeypadEnter;
switch (wParam) switch (wParam)
{ {
case VK_TAB: return ImGuiKey_Tab; case VK_TAB: return ImGuiKey_Tab;
@ -546,7 +551,6 @@ static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)
case VK_MULTIPLY: return ImGuiKey_KeypadMultiply; case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
case VK_SUBTRACT: return ImGuiKey_KeypadSubtract; case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
case VK_ADD: return ImGuiKey_KeypadAdd; case VK_ADD: return ImGuiKey_KeypadAdd;
case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
case VK_LSHIFT: return ImGuiKey_LeftShift; case VK_LSHIFT: return ImGuiKey_LeftShift;
case VK_LCONTROL: return ImGuiKey_LeftCtrl; case VK_LCONTROL: return ImGuiKey_LeftCtrl;
case VK_LMENU: return ImGuiKey_LeftAlt; case VK_LMENU: return ImGuiKey_LeftAlt;
@ -705,6 +709,16 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
} }
return 0; return 0;
} }
case WM_DESTROY:
if (bd->MouseHwnd == hwnd && bd->MouseTrackedArea != 0)
{
TRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 };
::TrackMouseEvent(&tme_cancel);
bd->MouseHwnd = nullptr;
bd->MouseTrackedArea = 0;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
return 0;
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
@ -758,12 +772,9 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
// Submit modifiers // Submit modifiers
ImGui_ImplWin32_UpdateKeyModifiers(); ImGui_ImplWin32_UpdateKeyModifiers();
// Obtain virtual key code // Obtain virtual key code and convert to ImGuiKey
// (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.) const ImGuiKey key = ImGui_ImplWin32_KeyEventToImGuiKey(wParam, lParam);
int vk = (int)wParam; const int vk = (int)wParam;
if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
vk = IM_VK_KEYPAD_ENTER;
const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);
const int scancode = (int)LOBYTE(HIWORD(lParam)); const int scancode = (int)LOBYTE(HIWORD(lParam));
// Special behavior for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit the key down event. // Special behavior for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit the key down event.
@ -1158,11 +1169,20 @@ static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
return ImVec2((float)pos.x, (float)pos.y); return ImVec2((float)pos.x, (float)pos.y);
} }
static void ImGui_ImplWin32_UpdateWin32StyleFromWindow(ImGuiViewport* viewport)
{
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
vd->DwStyle = ::GetWindowLongW(vd->Hwnd, GWL_STYLE);
vd->DwExStyle = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE);
}
static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
{ {
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
IM_ASSERT(vd->Hwnd != 0); IM_ASSERT(vd->Hwnd != 0);
RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y }; RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y };
if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)
ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using
::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle);
::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); ::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
} }
@ -1181,6 +1201,8 @@ static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
IM_ASSERT(vd->Hwnd != 0); IM_ASSERT(vd->Hwnd != 0);
RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y }; RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)
ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using
::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen
::SetWindowPos(vd->Hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); ::SetWindowPos(vd->Hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
} }
@ -1227,14 +1249,14 @@ static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f); IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
if (alpha < 1.0f) if (alpha < 1.0f)
{ {
DWORD style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED; DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED;
::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, style); ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style);
::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA); ::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA);
} }
else else
{ {
DWORD style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED; DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED;
::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, style); ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style);
} }
} }

View file

@ -1,4 +1,4 @@
// dear imgui, v1.91.1 // dear imgui, v1.91.2
// (main code and documentation) // (main code and documentation)
// Help: // Help:
@ -10,7 +10,7 @@
// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
// - Homepage ................... https://github.com/ocornut/imgui // - Homepage ................... https://github.com/ocornut/imgui
// - Releases & changelog ....... https://github.com/ocornut/imgui/releases // - Releases & changelog ....... https://github.com/ocornut/imgui/releases
// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!) // - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!)
// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) // - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
@ -1448,6 +1448,8 @@ ImGuiIO::ImGuiIO()
ConfigWindowsResizeFromEdges = true; ConfigWindowsResizeFromEdges = true;
ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsMoveFromTitleBarOnly = false;
ConfigMemoryCompactTimer = 60.0f; ConfigMemoryCompactTimer = 60.0f;
ConfigDebugIsDebuggerPresent = false;
ConfigDebugHighlightIdConflicts = true;
ConfigDebugBeginReturnValueOnce = false; ConfigDebugBeginReturnValueOnce = false;
ConfigDebugBeginReturnValueLoop = false; ConfigDebugBeginReturnValueLoop = false;
@ -2047,7 +2049,7 @@ const char* ImStreolRange(const char* str, const char* str_end)
return p ? p : str_end; return p ? p : str_end;
} }
const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line
{ {
while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
buf_mid_line--; buf_mid_line--;
@ -3867,7 +3869,8 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl
void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values.
mouse_cursor = ImGuiMouseCursor_Arrow;
ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
for (ImGuiViewportP* viewport : g.Viewports) for (ImGuiViewportP* viewport : g.Viewports)
{ {
@ -3947,7 +3950,7 @@ void ImGui::DestroyContext(ImGuiContext* ctx)
IM_DELETE(ctx); IM_DELETE(ctx);
} }
// IMPORTANT: ###xxx suffixes must be same in ALL languages to allow for automation. // IMPORTANT: interactive elements requires a fixed ###xxx suffix, it must be same in ALL languages to allow for automation.
static const ImGuiLocEntry GLocalizationEntriesEnUS[] = static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{ {
{ ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" }, { ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" },
@ -3958,8 +3961,9 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{ ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" },
{ ImGuiLocKey_WindowingPopup, "(Popup)" }, { ImGuiLocKey_WindowingPopup, "(Popup)" },
{ ImGuiLocKey_WindowingUntitled, "(Untitled)" }, { ImGuiLocKey_WindowingUntitled, "(Untitled)" },
{ ImGuiLocKey_OpenLink_s, "Open '%s'" },
{ ImGuiLocKey_CopyLink, "Copy Link###CopyLink" }, { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" },
{ ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" }, { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
{ ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." }, { ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." },
{ ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." }, { ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." },
}; };
@ -4206,7 +4210,7 @@ static void SetCurrentWindow(ImGuiWindow* window)
if (window) if (window)
{ {
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
g.FontScale = g.FontSize / g.Font->FontSize; g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
ImGui::NavUpdateCurrentWindowIsScrollPushableX(); ImGui::NavUpdateCurrentWindowIsScrollPushableX();
} }
} }
@ -4507,6 +4511,17 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
// Detect ID conflicts
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0)
{
g.HoveredIdPreviousFrameItemCount++;
if (g.DebugDrawIdConflicts == id)
window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
}
#endif
if (g.HoveredWindow != window) if (g.HoveredWindow != window)
return false; return false;
if (!IsMouseHoveringRect(bb.Min, bb.Max)) if (!IsMouseHoveringRect(bb.Min, bb.Max))
@ -4546,7 +4561,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// Display shortcut (only works with mouse) // Display shortcut (only works with mouse)
// (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip) // (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip)
if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut)) if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut) && g.ActiveId != id)
if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal)) if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal))
SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut)); SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut));
} }
@ -5130,6 +5145,11 @@ void ImGui::NewFrame()
if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
KeepAliveID(g.DragDropPayload.SourceId); KeepAliveID(g.DragDropPayload.SourceId);
// [DEBUG]
g.DebugDrawIdConflicts = 0;
if (g.IO.ConfigDebugHighlightIdConflicts && g.HoveredIdPreviousFrameItemCount > 1)
g.DebugDrawIdConflicts = g.HoveredIdPreviousFrame;
// Update HoveredId data // Update HoveredId data
if (!g.HoveredIdPreviousFrame) if (!g.HoveredIdPreviousFrame)
g.HoveredIdTimer = 0.0f; g.HoveredIdTimer = 0.0f;
@ -5140,6 +5160,7 @@ void ImGui::NewFrame()
if (g.HoveredId && g.ActiveId != g.HoveredId) if (g.HoveredId && g.ActiveId != g.HoveredId)
g.HoveredIdNotActiveTimer += g.IO.DeltaTime; g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
g.HoveredIdPreviousFrame = g.HoveredId; g.HoveredIdPreviousFrame = g.HoveredId;
g.HoveredIdPreviousFrameItemCount = 0;
g.HoveredId = 0; g.HoveredId = 0;
g.HoveredIdAllowOverlap = false; g.HoveredIdAllowOverlap = false;
g.HoveredIdIsDisabled = false; g.HoveredIdIsDisabled = false;
@ -5592,6 +5613,29 @@ void ImGui::EndFrame()
return; return;
IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
if (g.DebugDrawIdConflicts != 0)
{
PushStyleColor(ImGuiCol_PopupBg, ImLerp(g.Style.Colors[ImGuiCol_PopupBg], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.10f));
if (g.DebugItemPickerActive == false && BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))
{
SeparatorText("MESSAGE FROM DEAR IMGUI");
Text("Programmer error: %d visible items with conflicting ID!", g.HoveredIdPreviousFrameItemCount);
BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!");
BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!");
BulletText("Press F1 to open \"FAQ -> About the ID Stack System\" and read details.");
BulletText("Press CTRL+P to activate Item Picker and debug-break in item call-stack.");
BulletText("Set io.ConfigDebugDetectIdConflicts=false to disable this warning in non-programmers builds.");
EndTooltip();
}
PopStyleColor();
if (Shortcut(ImGuiMod_Ctrl | ImGuiKey_P, ImGuiInputFlags_RouteGlobal))
DebugStartItemPicker();
if (Shortcut(ImGuiKey_F1, ImGuiInputFlags_RouteGlobal) && g.PlatformIO.Platform_OpenInShellFn != NULL)
g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage");
}
#endif
CallContextHooks(&g, ImGuiContextHookType_EndFramePre); CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
ErrorCheckEndFrameSanityChecks(); ErrorCheckEndFrameSanityChecks();
@ -6589,7 +6633,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
//GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
if (hovered || held) if (hovered || held)
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; SetMouseCursor((resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE);
if (held && g.IO.MouseDoubleClicked[0]) if (held && g.IO.MouseDoubleClicked[0])
{ {
@ -6635,7 +6679,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER)
hovered = false; hovered = false;
if (hovered || held) if (hovered || held)
g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; SetMouseCursor((axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS);
if (held && g.IO.MouseDoubleClicked[0]) if (held && g.IO.MouseDoubleClicked[0])
{ {
// Double-clicking bottom or right border auto-fit on this axis // Double-clicking bottom or right border auto-fit on this axis
@ -7487,9 +7531,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags, const
// At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive) if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive)
{ {
// We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed),
// so verify that we don't have items over the title bar.
ImRect title_bar_rect = window->TitleBarRect(); ImRect title_bar_rect = window->TitleBarRect();
if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max)) if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && g.ActiveId == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max))
if (g.IO.MouseClickedCount[0] == 2 && GetKeyOwner(ImGuiKey_MouseLeft) == ImGuiKeyOwner_NoOwner) if (g.IO.MouseClickedCount[0] == 2 && GetKeyOwner(ImGuiKey_MouseLeft) == ImGuiKeyOwner_NoOwner)
window->WantCollapseToggle = true; window->WantCollapseToggle = true;
if (window->WantCollapseToggle) if (window->WantCollapseToggle)
@ -9873,7 +9918,7 @@ bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
return IsKeyPressed(key, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None, ImGuiKeyOwner_Any); return IsKeyPressed(key, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None, ImGuiKeyOwner_Any);
} }
// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. // Important: unlike legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id) bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id)
{ {
const ImGuiKeyData* key_data = GetKeyData(key); const ImGuiKeyData* key_data = GetKeyData(key);
@ -10125,6 +10170,9 @@ ImGuiMouseCursor ImGui::GetMouseCursor()
return g.MouseCursor; return g.MouseCursor;
} }
// We intentionally accept values of ImGuiMouseCursor that are outside our bounds, in case users needs to hack-in a custom cursor value.
// Custom cursors may be handled by custom backends. If you are using a standard backend and want to hack in a custom cursor, you may
// handle it before the backend _NewFrame() call and temporarily set ImGuiConfigFlags_NoMouseCursorChange during the backend _NewFrame() call.
void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -14135,9 +14183,11 @@ static void ImGui::NavUpdateWindowing()
// Keyboard: Press and Release ALT to toggle menu layer // Keyboard: Press and Release ALT to toggle menu layer
const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt }; const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt };
bool windowing_toggle_layer_start = false;
for (ImGuiKey windowing_toggle_key : windowing_toggle_keys) for (ImGuiKey windowing_toggle_key : windowing_toggle_keys)
if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner)) if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner))
{ {
windowing_toggle_layer_start = true;
g.NavWindowingToggleLayer = true; g.NavWindowingToggleLayer = true;
g.NavWindowingToggleKey = windowing_toggle_key; g.NavWindowingToggleKey = windowing_toggle_key;
g.NavInputSource = ImGuiInputSource_Keyboard; g.NavInputSource = ImGuiInputSource_Keyboard;
@ -14151,7 +14201,9 @@ static void ImGui::NavUpdateWindowing()
// We cancel toggling nav layer if an owner has claimed the key. // We cancel toggling nav layer if an owner has claimed the key.
if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper) if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper)
g.NavWindowingToggleLayer = false; g.NavWindowingToggleLayer = false;
if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false) else if (windowing_toggle_layer_start == false && g.LastKeyboardKeyPressTime == g.Time)
g.NavWindowingToggleLayer = false;
else if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false)
g.NavWindowingToggleLayer = false; g.NavWindowingToggleLayer = false;
// Apply layer toggle on Alt release // Apply layer toggle on Alt release
@ -15516,7 +15568,7 @@ static bool ImGui::UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window)
// Translate Dear ImGui windows when a Host Viewport has been moved // Translate Dear ImGui windows when a Host Viewport has been moved
// (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!)
void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos) void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(viewport->Window == NULL && (viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows)); IM_ASSERT(viewport->Window == NULL && (viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows));
@ -15530,7 +15582,7 @@ void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& o
ImRect test_still_fit_rect(old_pos, old_pos + viewport->Size); ImRect test_still_fit_rect(old_pos, old_pos + viewport->Size);
ImVec2 delta_pos = new_pos - old_pos; ImVec2 delta_pos = new_pos - old_pos;
for (ImGuiWindow* window : g.Windows) // FIXME-OPT for (ImGuiWindow* window : g.Windows) // FIXME-OPT
if (translate_all_windows || (window->Viewport == viewport && test_still_fit_rect.Contains(window->Rect()))) if (translate_all_windows || (window->Viewport == viewport && (old_size == new_size || test_still_fit_rect.Contains(window->Rect()))))
TranslateWindow(window, delta_pos); TranslateWindow(window, delta_pos);
} }
@ -15707,7 +15759,7 @@ static void ImGui::UpdateViewportsNewFrame()
// (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!)
const ImVec2 viewport_delta_pos = viewport->Pos - viewport->LastPos; const ImVec2 viewport_delta_pos = viewport->Pos - viewport->LastPos;
if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && (viewport_delta_pos.x != 0.0f || viewport_delta_pos.y != 0.0f)) if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && (viewport_delta_pos.x != 0.0f || viewport_delta_pos.y != 0.0f))
TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos); TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos, viewport->LastSize, viewport->Size);
// Update DPI scale // Update DPI scale
float new_dpi_scale; float new_dpi_scale;
@ -15817,6 +15869,7 @@ static void ImGui::UpdateViewportsEndFrame()
{ {
ImGuiViewportP* viewport = g.Viewports[i]; ImGuiViewportP* viewport = g.Viewports[i];
viewport->LastPos = viewport->Pos; viewport->LastPos = viewport->Pos;
viewport->LastSize = viewport->Size;
if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f)
if (i > 0) // Always include main viewport in the list if (i > 0) // Always include main viewport in the list
continue; continue;
@ -15863,7 +15916,7 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
viewport->ID = id; viewport->ID = id;
viewport->Idx = g.Viewports.Size; viewport->Idx = g.Viewports.Size;
viewport->Pos = viewport->LastPos = pos; viewport->Pos = viewport->LastPos = pos;
viewport->Size = size; viewport->Size = viewport->LastSize = size;
viewport->Flags = flags; viewport->Flags = flags;
UpdateViewportPlatformMonitor(viewport); UpdateViewportPlatformMonitor(viewport);
g.Viewports.push_back(viewport); g.Viewports.push_back(viewport);

View file

@ -1,4 +1,4 @@
// dear imgui, v1.91.1 // dear imgui, v1.91.2
// (headers) // (headers)
// Help: // Help:
@ -11,7 +11,7 @@
// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
// - Homepage ................... https://github.com/ocornut/imgui // - Homepage ................... https://github.com/ocornut/imgui
// - Releases & changelog ....... https://github.com/ocornut/imgui/releases // - Releases & changelog ....... https://github.com/ocornut/imgui/releases
// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!) // - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!)
// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) // - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
@ -28,8 +28,8 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.91.1" #define IMGUI_VERSION "1.91.2"
#define IMGUI_VERSION_NUM 19110 #define IMGUI_VERSION_NUM 19120
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch #define IMGUI_HAS_DOCK // Docking WIP branch
@ -1181,6 +1181,7 @@ enum ImGuiItemFlags_
ImGuiItemFlags_NoNavDefaultFocus = 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items). ImGuiItemFlags_NoNavDefaultFocus = 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items).
ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held. ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held.
ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window. ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window.
ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set.
}; };
// Flags for ImGui::InputText() // Flags for ImGui::InputText()
@ -1289,7 +1290,7 @@ enum ImGuiSelectableFlags_
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one
ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered
ImGuiSelectableFlags_NoHashTextHide = 1 << 5, // do not hide text after `##` ImGuiSelectableFlags_NoHashTextHide = 1 << 6, // do not hide text after `##`
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0 ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0
@ -2335,6 +2336,7 @@ struct ImGuiIO
const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
void* UserData; // = NULL // Store your own data. void* UserData; // = NULL // Store your own data.
// Font system
ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture. ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture.
float FontGlobalScale; // = 1.0f // Global scale all fonts float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
@ -2362,6 +2364,7 @@ struct ImGuiIO
bool AlwaysScrollText; // = false // Always scroll scroll texts bool AlwaysScrollText; // = false // Always scroll scroll texts
// Miscellaneous options // Miscellaneous options
// (you can visualize and interact with all options in 'Demo->Configuration')
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl.
bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout.
@ -2391,6 +2394,12 @@ struct ImGuiIO
// e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). // e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version).
bool ConfigDebugIsDebuggerPresent; // = false // Enable various tools calling IM_DEBUG_BREAK(). bool ConfigDebugIsDebuggerPresent; // = false // Enable various tools calling IM_DEBUG_BREAK().
// Tools to detect code submitting items with conflicting/duplicate IDs
// - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers.
// - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead!
// - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message when multiple items have conflicting identifiers.
// Tools to test correct Begin/End and BeginChild/EndChild behaviors. // Tools to test correct Begin/End and BeginChild/EndChild behaviors.
// - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() // - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX()
// - This is inconsistent with other BeginXXX functions and create confusion for many users. // - This is inconsistent with other BeginXXX functions and create confusion for many users.

View file

@ -1,4 +1,4 @@
// dear imgui, v1.91.1 // dear imgui, v1.91.2
// (demo code) // (demo code)
// Help: // Help:
@ -600,8 +600,10 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::SeparatorText("Debug"); ImGui::SeparatorText("Debug");
ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent); ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application."); ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
ImGui::BeginDisabled(); ImGui::BeginDisabled();
ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // . ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover."); ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.");
ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
@ -744,6 +746,7 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
if (ImGui::BeginMenu("Tools")) if (ImGui::BeginMenu("Tools"))
{ {
IMGUI_DEMO_MARKER("Menu/Tools"); IMGUI_DEMO_MARKER("Menu/Tools");
ImGuiIO& io = ImGui::GetIO();
#ifndef IMGUI_DISABLE_DEBUG_TOOLS #ifndef IMGUI_DISABLE_DEBUG_TOOLS
const bool has_debug_tools = true; const bool has_debug_tools = true;
#else #else
@ -752,14 +755,16 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent;
if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present)) if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
ImGui::DebugStartItemPicker(); ImGui::DebugStartItemPicker();
if (!is_debugger_present) if (!is_debugger_present)
ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools."); ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
ImGui::Separator(); ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout); ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
ImGui::SeparatorText("Debug Options");
ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::EndMenuBar(); ImGui::EndMenuBar();
@ -2060,8 +2065,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
ImGui::SameLine(); ImGui::SameLine();
ImGui::SliderInt("Sample count", &display_count, 1, 400); ImGui::SliderInt("Sample count", &display_count, 1, 400);
float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
@ -2656,6 +2661,11 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
if (ImGui::TreeNode("Drag to reorder items (simple)")) if (ImGui::TreeNode("Drag to reorder items (simple)"))
{ {
// FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
// This code was always slightly faulty but in a way which was not easily noticeable.
// Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
// Simple reordering // Simple reordering
HelpMarker( HelpMarker(
"We don't use the drag and drop api at all here! " "We don't use the drag and drop api at all here! "
@ -2677,6 +2687,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
} }
} }
} }
ImGui::PopItemFlag();
ImGui::TreePop(); ImGui::TreePop();
} }
@ -4300,7 +4312,7 @@ static void ShowDemoWindowLayout()
// down by FramePadding.y ahead of time) // down by FramePadding.y ahead of time)
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
ImGui::Text("OK Blahblah"); ImGui::SameLine(); ImGui::Text("OK Blahblah"); ImGui::SameLine();
ImGui::Button("Some framed item"); ImGui::SameLine(); ImGui::Button("Some framed item##2"); ImGui::SameLine();
HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
// SmallButton() uses the same vertical padding as Text // SmallButton() uses the same vertical padding as Text
@ -7223,12 +7235,14 @@ static void ShowDemoWindowColumns()
{ {
if (h_borders && ImGui::GetColumnIndex() == 0) if (h_borders && ImGui::GetColumnIndex() == 0)
ImGui::Separator(); ImGui::Separator();
ImGui::PushID(i);
ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
ImGui::Text("Long text that is likely to clip"); ImGui::Text("Long text that is likely to clip");
ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
ImGui::PopID();
ImGui::NextColumn(); ImGui::NextColumn();
} }
ImGui::Columns(1); ImGui::Columns(1);
@ -7551,7 +7565,8 @@ static void ShowDemoWindowInputs()
IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
ImGuiMouseCursor current = ImGui::GetMouseCursor(); ImGuiMouseCursor current = ImGui::GetMouseCursor();
ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
ImGui::BeginDisabled(true); ImGui::BeginDisabled(true);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
ImGui::EndDisabled(); ImGui::EndDisabled();

View file

@ -1,4 +1,4 @@
// dear imgui, v1.91.1 // dear imgui, v1.91.2
// (drawing and font code) // (drawing and font code)
/* /*
@ -2601,13 +2601,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
{ {
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
IM_ASSERT(font_cfg->SizePixels > 0.0f); IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
IM_ASSERT(font_cfg->OversampleH > 0 && font_cfg->OversampleV > 0 && "Is ImFontConfig struct correctly initialized?");
// Create new font // Create new font
if (!font_cfg->MergeMode) if (!font_cfg->MergeMode)
Fonts.push_back(IM_NEW(ImFont)); Fonts.push_back(IM_NEW(ImFont));
else else
IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
ConfigData.push_back(*font_cfg); ConfigData.push_back(*font_cfg);
ImFontConfig& new_font_cfg = ConfigData.back(); ImFontConfig& new_font_cfg = ConfigData.back();

View file

@ -1,4 +1,4 @@
// dear imgui, v1.91.1 // dear imgui, v1.91.2
// (internal structures/api) // (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@ -204,24 +204,6 @@ typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...);
extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#endif #endif
//-------------------------------------------------------------------------
// [SECTION] STB libraries includes
//-------------------------------------------------------------------------
namespace ImStb
{
#undef IMSTB_TEXTEDIT_STRING
#undef IMSTB_TEXTEDIT_CHARTYPE
#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState
#define IMSTB_TEXTEDIT_CHARTYPE ImWchar
#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f)
#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
#include "imstb_textedit.h"
} // namespace ImStb
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Macros // [SECTION] Macros
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -395,7 +377,7 @@ IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end
IMGUI_API void ImStrTrimBlanks(char* str); // Remove leading and trailing blanks from a buffer. IMGUI_API void ImStrTrimBlanks(char* str); // Remove leading and trailing blanks from a buffer.
IMGUI_API const char* ImStrSkipBlank(const char* str); // Find first non-blank character. IMGUI_API const char* ImStrSkipBlank(const char* str); // Find first non-blank character.
IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string) IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string)
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line (ImWchar string) IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line
IM_MSVC_RUNTIME_CHECKS_OFF IM_MSVC_RUNTIME_CHECKS_OFF
static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
@ -1125,20 +1107,31 @@ struct IMGUI_API ImGuiInputTextDeactivatedState
ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); } ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); }
void ClearFreeMemory() { ID = 0; TextA.clear(); } void ClearFreeMemory() { ID = 0; TextA.clear(); }
}; };
// Forward declare imstb_textedit.h structure + make its main configuration define accessible
#undef IMSTB_TEXTEDIT_STRING
#undef IMSTB_TEXTEDIT_CHARTYPE
#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState
#define IMSTB_TEXTEDIT_CHARTYPE char
#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f)
#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
namespace ImStb { struct STB_TexteditState; }
typedef ImStb::STB_TexteditState ImStbTexteditState;
// Internal state of the currently focused/edited text input box // Internal state of the currently focused/edited text input box
// For a given item ID, access with ImGui::GetInputTextState() // For a given item ID, access with ImGui::GetInputTextState()
struct IMGUI_API ImGuiInputTextState struct IMGUI_API ImGuiInputTextState
{ {
ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent).
ImStbTexteditState* Stb; // State for stb_textedit.h
ImGuiID ID; // widget id owning the text state ImGuiID ID; // widget id owning the text state
int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. int CurLenA; // UTF-8 length of the string in TextA (in bytes)
ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. ImVector<char> TextA; // main UTF8 buffer.
ImVector<char> TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
ImVector<char> InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) ImVector<char> InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) ImVector<char> CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack
int BufCapacityA; // end-user buffer capacity int BufCapacityA; // end-user buffer capacity
ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y)
ImStb::STB_TexteditState Stb; // state for stb_textedit.h
float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
@ -1149,34 +1142,33 @@ struct IMGUI_API ImGuiInputTextState
int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet. int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet.
int ReloadSelectionEnd; int ReloadSelectionEnd;
ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } ImGuiInputTextState();
void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } ~ImGuiInputTextState();
void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } void ClearText() { CurLenA = 0; TextA[0] = 0; CursorClamp(); }
int GetUndoAvailCount() const { return Stb.undostate.undo_point; } void ClearFreeMemory() { TextA.clear(); InitialTextA.clear(); }
int GetRedoAvailCount() const { return IMSTB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; }
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
void OnCharPressed(unsigned int c);
bool HasWordWrap() const { return WordWrapWidth > 0.0; } bool HasWordWrap() const { return WordWrapWidth > 0.0; }
// Cursor & Selection // Cursor & Selection
void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking void CursorAnimReset();
void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } void CursorClamp();
bool HasSelection() const { return Stb.select_start != Stb.select_end; } bool HasSelection() const;
void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } void ClearSelection();
int GetCursorPos() const { return Stb.cursor; } int GetCursorPos() const;
int GetSelectionStart() const { return Stb.select_start; } int GetSelectionStart() const;
int GetSelectionEnd() const { return Stb.select_end; } int GetSelectionEnd() const;
void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } void SelectAll();
// Reload user buf (WIP #2890) // Reload user buf (WIP #2890)
// If you modify underlying user-passed const char* while active you need to call this (InputText V2 may lift this) // If you modify underlying user-passed const char* while active you need to call this (InputText V2 may lift this)
// strcpy(my_buf, "hello"); // strcpy(my_buf, "hello");
// if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item // if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item
// state->ReloadUserBufAndSelectAll(); // state->ReloadUserBufAndSelectAll();
void ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } void ReloadUserBufAndSelectAll();
void ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb.select_start; ReloadSelectionEnd = Stb.select_end; } void ReloadUserBufAndKeepSelection();
void ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } void ReloadUserBufAndMoveToEnd();
}; };
enum ImGuiWindowRefreshFlags_ enum ImGuiWindowRefreshFlags_
@ -1983,6 +1975,7 @@ struct ImGuiViewportP : public ImGuiViewport
int LastFocusedStampCount; // Last stamp number from when a window hosted by this viewport was focused (by comparing this value between two viewport we have an implicit viewport z-order we use as fallback) int LastFocusedStampCount; // Last stamp number from when a window hosted by this viewport was focused (by comparing this value between two viewport we have an implicit viewport z-order we use as fallback)
ImGuiID LastNameHash; ImGuiID LastNameHash;
ImVec2 LastPos; ImVec2 LastPos;
ImVec2 LastSize;
float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent) float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent)
float LastAlpha; float LastAlpha;
bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused. bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused.
@ -2075,6 +2068,7 @@ enum ImGuiLocKey : int
ImGuiLocKey_WindowingMainMenuBar, ImGuiLocKey_WindowingMainMenuBar,
ImGuiLocKey_WindowingPopup, ImGuiLocKey_WindowingPopup,
ImGuiLocKey_WindowingUntitled, ImGuiLocKey_WindowingUntitled,
ImGuiLocKey_OpenLink_s,
ImGuiLocKey_CopyLink, ImGuiLocKey_CopyLink,
ImGuiLocKey_DockingHideTabBar, ImGuiLocKey_DockingHideTabBar,
ImGuiLocKey_DockingHoldShiftToDock, ImGuiLocKey_DockingHoldShiftToDock,
@ -2251,9 +2245,11 @@ struct ImGuiContext
ImVec2 WheelingAxisAvg; ImVec2 WheelingAxisAvg;
// Item/widgets state and tracking information // Item/widgets state and tracking information
ImGuiID DebugDrawIdConflicts; // Set when we detect multiple items with the same identifier
ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]
ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredId; // Hovered widget, filled during the frame
ImGuiID HoveredIdPreviousFrame; ImGuiID HoveredIdPreviousFrame;
int HoveredIdPreviousFrameItemCount; // Count numbers of items using the same ID as last frame's hovered id
float HoveredIdTimer; // Measure contiguous hovering time float HoveredIdTimer; // Measure contiguous hovering time
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
bool HoveredIdAllowOverlap; bool HoveredIdAllowOverlap;
@ -2596,8 +2592,10 @@ struct ImGuiContext
WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1; WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1;
WheelingWindowReleaseTimer = 0.0f; WheelingWindowReleaseTimer = 0.0f;
DebugDrawIdConflicts = 0;
DebugHookIdInfo = 0; DebugHookIdInfo = 0;
HoveredId = HoveredIdPreviousFrame = 0; HoveredId = HoveredIdPreviousFrame = 0;
HoveredIdPreviousFrameItemCount = 0;
HoveredIdAllowOverlap = false; HoveredIdAllowOverlap = false;
HoveredIdIsDisabled = false; HoveredIdIsDisabled = false;
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
@ -3433,7 +3431,7 @@ namespace ImGui
IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type);
// Viewports // Viewports
IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos); IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size);
IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale);
IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport); IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport);
IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport);

View file

@ -1,4 +1,4 @@
// dear imgui, v1.91.1 // dear imgui, v1.91.2
// (tables and columns code) // (tables and columns code)
/* /*
@ -328,7 +328,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[]. // - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[].
const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0;
const ImVec2 avail_size = GetContentRegionAvail(); const ImVec2 avail_size = GetContentRegionAvail();
const ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); const ImVec2 actual_outer_size = ImTrunc(CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f));
const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows! const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows!
if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size) if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size)
@ -869,7 +869,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
// Combine width from regular rows + width from headers unless requested not to. // Combine width from regular rows + width from headers unless requested not to.
if (!column->IsPreserveWidthAuto) if (!column->IsPreserveWidthAuto && table->InstanceCurrent == 0)
column->WidthAuto = TableGetColumnWidthAuto(table, column); column->WidthAuto = TableGetColumnWidthAuto(table, column);
// Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto) // Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto)
@ -1264,7 +1264,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (table->Flags & ImGuiTableFlags_NoClip) if (table->Flags & ImGuiTableFlags_NoClip)
table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
else else
inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); // FIXME: use table->InnerClipRect?
} }
// Process hit-testing on resizing borders. Actual size change will be applied in EndTable() // Process hit-testing on resizing borders. Actual size change will be applied in EndTable()
@ -2014,7 +2014,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
{ {
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main;
const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); const float y0 = ImMax(table->RowPosY2 + 1, table->InnerClipRect.Min.y);
table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y; table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y;
if (unfreeze_rows_actual) if (unfreeze_rows_actual)
@ -2023,8 +2023,8 @@ void ImGui::TableEndRow(ImGuiTable* table)
table->IsUnfrozenRows = true; table->IsUnfrozenRows = true;
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, table->InnerClipRect.Max.y);
table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = table->InnerClipRect.Max.y;
table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;
IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);
@ -4412,7 +4412,7 @@ void ImGui::EndColumns()
{ {
ButtonBehavior(column_hit_rect, column_id, &hovered, &held); ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
if (hovered || held) if (hovered || held)
g.MouseCursor = ImGuiMouseCursor_ResizeEW; SetMouseCursor(ImGuiMouseCursor_ResizeEW);
if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize))
dragging_column = n; dragging_column = n;
} }

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,8 @@
// Those changes would need to be pushed into nothings/stb: // Those changes would need to be pushed into nothings/stb:
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783) // - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
// - Added name to struct or it may be forward declared in our code.
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
// Grep for [DEAR IMGUI] to find the changes. // Grep for [DEAR IMGUI] to find the changes.
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_* // - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
@ -209,6 +211,7 @@
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
// //
// Each of these functions potentially updates the string and updates the // Each of these functions potentially updates the string and updates the
// state. // state.
@ -243,7 +246,12 @@
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
// anything other type you wante before including. // anything other type you want before including.
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
// transformed into text and stb_textedit_text() is automatically called.
//
// text: [DEAR IMGUI] added 2024-09
// call this to text inputs sent to the textfield.
// //
// //
// When rendering, you can read the cursor position and selection state from // When rendering, you can read the cursor position and selection state from
@ -318,7 +326,7 @@ typedef struct
int undo_char_point, redo_char_point; int undo_char_point, redo_char_point;
} StbUndoState; } StbUndoState;
typedef struct typedef struct STB_TexteditState
{ {
///////////////////// /////////////////////
// //
@ -438,13 +446,13 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
if (x < r.x1) { if (x < r.x1) {
// search characters in row for one that straddles 'x' // search characters in row for one that straddles 'x'
prev_x = r.x0; prev_x = r.x0;
for (k=0; k < r.num_chars; ++k) { for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
float w = STB_TEXTEDIT_GETWIDTH(str, i, k); float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
if (x < prev_x+w) { if (x < prev_x+w) {
if (x < prev_x+w/2) if (x < prev_x+w/2)
return k+i; return k+i;
else else
return k+i+1; return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
} }
prev_x += w; prev_x += w;
} }
@ -563,7 +571,7 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING
// now scan to find xpos // now scan to find xpos
find->x = r.x0; find->x = r.x0;
for (i=0; first+i < n; ++i) for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
} }
@ -640,6 +648,17 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
} }
} }
// [DEAR IMGUI]
// Functions must be implemented for UTF8 support
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
#endif
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
#endif
#ifdef STB_TEXTEDIT_IS_SPACE #ifdef STB_TEXTEDIT_IS_SPACE
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx ) static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
{ {
@ -723,42 +742,45 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
#define STB_TEXTEDIT_KEYTYPE int #define STB_TEXTEDIT_KEYTYPE int
#endif #endif
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
{
// can't add newline in single-line mode
if (text[0] == '\n' && state->single_line)
return;
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
state->cursor += text_len;
state->has_preferred_x = 0;
}
}
else {
stb_textedit_delete_selection(str, state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
stb_text_makeundo_insert(state, state->cursor, text_len);
state->cursor += text_len;
state->has_preferred_x = 0;
}
}
}
// API key: process a keyboard input // API key: process a keyboard input
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
{ {
retry: retry:
switch (key) { switch (key) {
default: { default: {
#ifdef STB_TEXTEDIT_KEYTOTEXT
int c = STB_TEXTEDIT_KEYTOTEXT(key); int c = STB_TEXTEDIT_KEYTOTEXT(key);
if (c > 0) { if (c > 0) {
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE) c; // TODO: PLEASE CHECK FOR BREAKAGE.
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
// can't add newline in single-line mode stb_textedit_text(str, state, &ch, 1);
if (c == '\n' && state->single_line)
break;
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
++state->cursor;
state->has_preferred_x = 0;
} else {
printf("key failed: first section.\n");
state->cursor=0;
}
} else {
stb_textedit_delete_selection(str,state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
stb_text_makeundo_insert(state, state->cursor, 1);
++state->cursor;
state->has_preferred_x = 0;
} else {
printf("key failed: second section.\n");
state->cursor=0;
}
}
} }
#endif
break; break;
} }
@ -784,7 +806,7 @@ retry:
stb_textedit_move_to_first(state); stb_textedit_move_to_first(state);
else else
if (state->cursor > 0) if (state->cursor > 0)
--state->cursor; state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
@ -793,7 +815,7 @@ retry:
if (STB_TEXT_HAS_SELECTION(state)) if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str, state); stb_textedit_move_to_last(str, state);
else else
++state->cursor; state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
@ -803,7 +825,7 @@ retry:
stb_textedit_prep_selection_at_cursor(state); stb_textedit_prep_selection_at_cursor(state);
// move selection left // move selection left
if (state->select_end > 0) if (state->select_end > 0)
--state->select_end; state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
state->cursor = state->select_end; state->cursor = state->select_end;
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
@ -853,7 +875,7 @@ retry:
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
stb_textedit_prep_selection_at_cursor(state); stb_textedit_prep_selection_at_cursor(state);
// move selection right // move selection right
++state->select_end; state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
state->cursor = state->select_end; state->cursor = state->select_end;
state->has_preferred_x = 0; state->has_preferred_x = 0;
@ -909,7 +931,7 @@ retry:
x += dx; x += dx;
if (x > goal_x) if (x > goal_x)
break; break;
++state->cursor; state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
} }
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
@ -971,7 +993,7 @@ retry:
x += dx; x += dx;
if (x > goal_x) if (x > goal_x)
break; break;
++state->cursor; state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
} }
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
@ -999,7 +1021,7 @@ retry:
else { else {
int n = STB_TEXTEDIT_STRINGLEN(str); int n = STB_TEXTEDIT_STRINGLEN(str);
if (state->cursor < n) if (state->cursor < n)
stb_textedit_delete(str, state, state->cursor, 1); stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
} }
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
@ -1011,8 +1033,9 @@ retry:
else { else {
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
if (state->cursor > 0) { if (state->cursor > 0) {
stb_textedit_delete(str, state, state->cursor-1, 1); int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
--state->cursor; stb_textedit_delete(str, state, prev, state->cursor - prev);
state->cursor = prev;
} }
} }
state->has_preferred_x = 0; state->has_preferred_x = 0;