diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index a7cc8d644..9688f6867 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -424,6 +424,7 @@ static ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code) bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_android.cpp b/backends/imgui_impl_android.cpp index f387c4830..994b0c6f2 100644 --- a/backends/imgui_impl_android.cpp +++ b/backends/imgui_impl_android.cpp @@ -264,6 +264,8 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event) bool ImGui_ImplAndroid_Init(ANativeWindow* window) { + IMGUI_CHECKVERSION(); + g_Window = window; g_Time = 0.0; diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 1dcb713f2..0123aa65b 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -540,6 +540,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() bool ImGui_ImplDX10_Init(ID3D10Device* device) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 1027493a0..3d7ec7e88 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -552,6 +552,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 781281ab7..cde8981b9 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -777,6 +777,7 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 308071301..59475d2ae 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -298,6 +298,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index af3c667f5..23b0adb8b 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -572,6 +572,7 @@ void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows) static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); //printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED); diff --git a/backends/imgui_impl_glut.cpp b/backends/imgui_impl_glut.cpp index a6f02d76f..0678603bd 100644 --- a/backends/imgui_impl_glut.cpp +++ b/backends/imgui_impl_glut.cpp @@ -167,6 +167,7 @@ static ImGuiKey ImGui_ImplGLUT_KeyToImGuiKey(int key) bool ImGui_ImplGLUT_Init() { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); #ifdef FREEGLUT io.BackendPlatformName = "imgui_impl_glut (freeglut)"; diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index f7c2a4736..22aa37eee 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -87,7 +87,6 @@ struct ImGui_ImplMetal_Data ImGui_ImplMetal_Data() { memset(this, 0, sizeof(*this)); } }; -static ImGui_ImplMetal_Data* ImGui_ImplMetal_CreateBackendData() { return IM_NEW(ImGui_ImplMetal_Data)(); } static ImGui_ImplMetal_Data* ImGui_ImplMetal_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } static void ImGui_ImplMetal_DestroyBackendData(){ IM_DELETE(ImGui_ImplMetal_GetBackendData()); } @@ -133,8 +132,11 @@ bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device) bool ImGui_ImplMetal_Init(id device) { - ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_CreateBackendData(); ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)(); io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_metal"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 4082614d8..4c4832e91 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -89,6 +89,7 @@ static void ImGui_ImplOpenGL2_ShutdownPlatformInterface(); bool ImGui_ImplOpenGL2_Init() { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 46345d220..6b994bf3a 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -281,6 +281,7 @@ struct ImGui_ImplOpenGL3_VtxAttribState bool ImGui_ImplOpenGL3_Init(const char* glsl_version) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Initialize our loader diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index c411edbfb..a96027d92 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -90,7 +90,6 @@ struct ImGui_ImplOSX_Data ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); } }; -static ImGui_ImplOSX_Data* ImGui_ImplOSX_CreateBackendData() { return IM_NEW(ImGui_ImplOSX_Data)(); } static ImGui_ImplOSX_Data* ImGui_ImplOSX_GetBackendData() { return (ImGui_ImplOSX_Data*)ImGui::GetIO().BackendPlatformUserData; } static void ImGui_ImplOSX_DestroyBackendData() { IM_DELETE(ImGui_ImplOSX_GetBackendData()); } @@ -423,15 +422,17 @@ IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view) { bool ImGui_ImplOSX_Init(NSView* view) { ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_CreateBackendData(); - io.BackendPlatformUserData = (void*)bd; + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); // Setup backend capabilities flags + ImGui_ImplOSX_Data* bd = IM_NEW(ImGui_ImplOSX_Data)(); + io.BackendPlatformUserData = (void*)bd; + io.BackendPlatformName = "imgui_impl_osx"; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) //io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) //io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) - io.BackendPlatformName = "imgui_impl_osx"; bd->Observer = [ImGuiObserver new]; bd->Window = view.window ?: NSApp.orderedWindows.firstObject; diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 569b01d1e..38c31a522 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -449,6 +449,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); // Check and store if we are on a SDL backend that supports global mouse position diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index b00757a1c..59b287207 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -411,6 +411,7 @@ static void ImGui_ImplSDL3_SetupPlatformHandles(ImGuiViewport* viewport, SDL_Win static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); IM_UNUSED(sdl_gl_context); // Unused in this branch diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 74afcde69..2a85fd771 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -65,6 +65,7 @@ static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData() bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 7e629580d..22b71195e 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -61,6 +61,7 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData() bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 3690e4a49..d4ec405ba 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1123,6 +1123,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) } ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 6e82ebf4f..ceee552fa 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -726,6 +726,7 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects() bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 71e61966c..c079a2b50 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -154,6 +154,7 @@ static void ImGui_ImplWin32_UpdateKeyboardCodePage() static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) { ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); INT64 perf_frequency, perf_counter; @@ -653,11 +654,10 @@ static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). - if (ImGui::GetCurrentContext() == nullptr) - return 0; - + // We silently allow both context or just only backend data to be nullptr. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplWin32_Init()?"); + if (bd == nullptr) + return 0; ImGuiIO& io = ImGui::GetIO(); switch (msg) @@ -686,7 +686,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA ::ScreenToClient(hwnd, &mouse_pos); io.AddMouseSourceEvent(mouse_source); io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y); - break; + return 0; } case WM_MOUSELEAVE: case WM_NCMOUSELEAVE: @@ -699,7 +699,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA bd->MouseTrackedArea = 0; io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); } - break; + return 0; } case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 21efccb71..242bb2363 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,30 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.90.7 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + +- Nav: fixed holding Ctrl or gamepad L1 from not slowing down keyboard/gamepad tweak speed. + Broken during a refactor refactor for 1.89. Holding Shift/R1 to speed up wasn't broken. +- Tables: fixed cell background of fully clipped row overlapping with header. (#7575, #7041) [@prabuinet] +- Backends: all backends + demo now call IMGUI_CHECKVERSION() to verify ABI compatibility between caller + code and compiled version of Dear ImGui. If you get an assert it most likely mean you have a build issue, + read comments near the assert. (#7568) +- Backends: Win32: undo an assert introduced in 1.90.6 which didn't allow WndProc + handler to be called before backend initialization. Because of how ::CreateWindow() + calls in WndProc this is facilitating. (#6275) [@MennoVink] + + +Docking+Viewports Branch: + +- Tables: resizing border hit-rect scales according to current monitor dpi scale. + + ----------------------------------------------------------------------- VERSION 1.90.6 (Released 2024-05-08) ----------------------------------------------------------------------- diff --git a/docs/FAQ.md b/docs/FAQ.md index 7e9842cc4..9c7df2334 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -23,7 +23,7 @@ or view this file with any Markdown viewer. | [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) | | [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) | | **Q&A: Usage** | -| **[About the ID Stack system..
Why is my widget not reacting when I click on it?
How can I have widgets with an empty label?
How can I have multiple widgets with the same label?
How can I have multiple windows with the same label?](#q-about-the-id-stack-system)** | +| **[About the ID Stack system..
Why is my widget not reacting when I click on it?
Why is the wrong widget reacting when I click on one?
How can I have widgets with an empty label?
How can I have multiple widgets with the same label?
How can I have multiple windows with the same label?](#q-about-the-id-stack-system)** | | [How can I display an image? What is ImTextureID, how does it work?](#q-how-can-i-display-an-image-what-is-imtextureid-how-does-it-work)| | [How can I use maths operators with ImVec2?](#q-how-can-i-use-maths-operators-with-imvec2) | | [How can I use my own maths types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-maths-types-instead-of-imvec2imvec4) | @@ -199,10 +199,42 @@ ctx->RSSetScissorRects(1, &r); ### Q: About the ID Stack system... ### Q: Why is my widget not reacting when I click on it? +### Q: Why is the wrong widget reacting when I click on one? ### Q: How can I have widgets with an empty label? ### Q: How can I have multiple widgets with the same label? ### Q: How can I have multiple windows with the same label? +**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE:** + + + + + +
+
+ImGui::Begin("Incorrect!");
+ImGui::DragFloat2("My value", &objects[0]->pos.x);
+ImGui::DragFloat2("My value", &objects[1]->pos.x);
+ImGui::DragFloat2("My value", &objects[2]->pos.x);
+ImGui::End();
+ 
+ImGui::Begin("Correct!");
+ImGui::DragFloat2("My value", &objects[0]->pos.x);
+ImGui::DragFloat2("My value##2", &objects[1]->pos.x);
+ImGui::DragFloat2("My value##3", &objects[2]->pos.x);
+ImGui::End();
+ 
+ImGui::Begin("Also Correct!");
+for (int n = 0; n < 3; n++)
+{
+    ImGui::PushID(n);
+    ImGui::DragFloat2("My value", &objects[n]->pos.x);
+    ImGui::PopID();
+}
+ImGui::End();
+
+
+ A primer on labels and the ID Stack... Dear ImGui internally needs to uniquely identify UI elements. diff --git a/imgui.cpp b/imgui.cpp index 074560efa..13ab7cbf1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 +// dear imgui, v1.90.7 WIP // (main code and documentation) // Help: @@ -1088,7 +1088,6 @@ static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For u //------------------------------------------------------------------------- static void SetCurrentWindow(ImGuiWindow* window); -static void FindHoveredWindow(); static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); @@ -4657,6 +4656,9 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() { ImGuiContext& g = *GImGui; ImGuiIO& io = g.IO; + + // FIXME-DPI: This storage was added on 2021/03/31 for test engine, but if we want to multiply WINDOWS_HOVER_PADDING + // by DpiScale, we need to make this window-agnostic anyhow, maybe need storing inside ImGuiWindow. g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); // Find the window hovered by mouse: @@ -4664,7 +4666,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. bool clear_hovered_windows = false; - FindHoveredWindow(); + FindHoveredWindowEx(g.IO.MousePos, false, &g.HoveredWindow, &g.HoveredWindowUnderMovingWindow); IM_ASSERT(g.HoveredWindow == NULL || g.HoveredWindow == g.MovingWindow || g.HoveredWindow->Viewport == g.MouseViewport); // Modal windows prevents mouse from hovering behind them. @@ -5465,22 +5467,26 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex } // Find window given position, search front-to-back -// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically -// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is -// called, aka before the next Begin(). Moving window isn't affected. -static void FindHoveredWindow() +// - Typically write output back to g.HoveredWindow and g.HoveredWindowUnderMovingWindow. +// - FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically +// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is +// called, aka before the next Begin(). Moving window isn't affected. +// - The 'find_first_and_in_any_viewport = true' mode is only used by TestEngine. It is simpler to maintain here. +void ImGui::FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window) { ImGuiContext& g = *GImGui; + ImGuiWindow* hovered_window = NULL; + ImGuiWindow* hovered_window_under_moving_window = NULL; // Special handling for the window being moved: Ignore the mouse viewport check (because it may reset/lose its viewport during the undocking frame) - ImGuiViewportP* moving_window_viewport = g.MovingWindow ? g.MovingWindow->Viewport : NULL; - if (g.MovingWindow) + ImGuiViewportP* backup_moving_window_viewport = NULL; + if (find_first_and_in_any_viewport == false && g.MovingWindow) + { + backup_moving_window_viewport = g.MovingWindow->Viewport; g.MovingWindow->Viewport = g.MouseViewport; - - ImGuiWindow* hovered_window = NULL; - ImGuiWindow* hovered_window_ignoring_moving_window = NULL; - if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) - hovered_window = g.MovingWindow; + if (!(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) + hovered_window = g.MovingWindow; + } ImVec2 padding_regular = g.Style.TouchExtraPadding; ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular; @@ -5498,7 +5504,7 @@ static void FindHoveredWindow() // Using the clipped AABB, a child window will typically be clipped by its parent (not always) ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize; - if (!window->OuterRectClipped.ContainsWithPad(g.IO.MousePos, hit_padding)) + if (!window->OuterRectClipped.ContainsWithPad(pos, hit_padding)) continue; // Support for one rectangular hole in any given window @@ -5507,24 +5513,32 @@ static void FindHoveredWindow() { ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y); ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y); - if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos)) + if (ImRect(hole_pos, hole_pos + hole_size).Contains(pos)) continue; } - if (hovered_window == NULL) + if (find_first_and_in_any_viewport) + { hovered_window = window; - IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. - if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree)) - hovered_window_ignoring_moving_window = window; - if (hovered_window && hovered_window_ignoring_moving_window) break; + } + else + { + if (hovered_window == NULL) + hovered_window = window; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. + if (hovered_window_under_moving_window == NULL && (!g.MovingWindow || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree)) + hovered_window_under_moving_window = window; + if (hovered_window && hovered_window_under_moving_window) + break; + } } - g.HoveredWindow = hovered_window; - g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; - - if (g.MovingWindow) - g.MovingWindow->Viewport = moving_window_viewport; + *out_hovered_window = hovered_window; + if (out_hovered_window_under_moving_window != NULL) + *out_hovered_window_under_moving_window = hovered_window_under_moving_window; + if (find_first_and_in_any_viewport == false && g.MovingWindow) + g.MovingWindow->Viewport = backup_moving_window_viewport; } bool ImGui::IsItemActive() @@ -10271,8 +10285,8 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags // [SECTION] ERROR CHECKING //----------------------------------------------------------------------------- -// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. -// This is called by IMGUI_CHECKVERSION(). +// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. +// Called by IMGUI_CHECKVERSION(). // Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit // If this triggers you have mismatched headers and compiled code versions. // - It could be because of a build issue (using new headers with old compiled code) @@ -10285,12 +10299,12 @@ bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si { bool error = false; if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); } - if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } + if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } - if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } - if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } - if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } - if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } + if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } + if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } + if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } + if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } return !error; } diff --git a/imgui.h b/imgui.h index 2d7afdd9e..284d6951d 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 WIP +// dear imgui, v1.90.7 WIP // (headers) // Help: @@ -27,8 +27,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.90.6" -#define IMGUI_VERSION_NUM 19060 +#define IMGUI_VERSION "1.90.7 WIP" +#define IMGUI_VERSION_NUM 19062 #define IMGUI_HAS_TABLE #define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_DOCK // Docking WIP branch @@ -92,6 +92,8 @@ Index of this file: #endif #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! #define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. + +// Check that version and structures layouts are matching between compiled imgui code and caller. Read comments above DebugCheckVersionAndDataLayout() for details. #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. @@ -706,7 +708,8 @@ namespace ImGui // Tooltips // - Tooltips are windows following the mouse. They do not take focus away. - // - A tooltip window can contain items of any types. SetTooltip() is a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom. + // - A tooltip window can contain items of any types. + // - SetTooltip() is more or less a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom (with a subtlety that it discard any previously submitted tooltip) IMGUI_API bool BeginTooltip(); // begin/append a tooltip window. IMGUI_API void EndTooltip(); // only call EndTooltip() if BeginTooltip()/BeginItemTooltip() returns true! IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip. Often used after a ImGui::IsItemHovered() check. Override any previous call to SetTooltip(). diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 499a48d0c..80bbc27fc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 +// dear imgui, v1.90.7 WIP // (demo code) // Help: @@ -278,6 +278,9 @@ void ImGui::ShowDemoWindow(bool* p_open) // Most functions would normally just assert/crash if the context is missing. IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!"); + // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. + IMGUI_CHECKVERSION(); + // Examples Apps (accessible from the "Examples" menu) static bool show_app_main_menu_bar = false; static bool show_app_console = false; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index edc825819..393f417df 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 +// dear imgui, v1.90.7 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index bde750dce..03ac975da 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 +// dear imgui, v1.90.7 WIP // (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. @@ -2135,6 +2135,7 @@ struct ImGuiContext ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; double Time; int FrameCount; @@ -2161,7 +2162,7 @@ struct ImGuiContext ImVector CurrentWindowStack; ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* int WindowsActiveCount; // Number of unique windows submitted by frame - ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING) + ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING). ImGuiID DebugBreakInWindow; // Set to break in Begin() call. ImGuiWindow* CurrentWindow; // Window being drawn into ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. @@ -2244,7 +2245,6 @@ struct ImGuiContext // Viewports ImVector Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData. - float CurrentDpiScale; // == CurrentViewport->DpiScale ImGuiViewportP* CurrentViewport; // We track changes of viewport (happening in Begin) so we can call Platform_OnChangedViewport() ImGuiViewportP* MouseViewport; ImGuiViewportP* MouseLastHoveredViewport; // Last known viewport that was hovered by mouse (even if we are not hovering any viewport any more) + honoring the _NoInputs flag. @@ -2480,7 +2480,7 @@ struct ImGuiContext ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None; FontAtlasOwnedByContext = shared_font_atlas ? false : true; Font = NULL; - FontSize = FontBaseSize = 0.0f; + FontSize = FontBaseSize = CurrentDpiScale = 0.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); Time = 0.0f; FrameCount = 0; @@ -2540,7 +2540,6 @@ struct ImGuiContext CurrentItemFlags = ImGuiItemFlags_None; DebugShowGroupRects = false; - CurrentDpiScale = 0.0f; CurrentViewport = NULL; MouseViewport = MouseLastHoveredViewport = NULL; PlatformLastFocusedViewportId = 0; @@ -3310,6 +3309,7 @@ namespace ImGui // NewFrame IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock); IMGUI_API void UpdateMouseMovingWindowNewFrame(); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 6815af5ad..4c0890be9 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 +// dear imgui, v1.90.7 WIP // (tables and columns code) /* @@ -1256,7 +1256,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table) // really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height). // Actual columns highlight/render will be performed in EndTable() and not be affected. ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); - const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS; + const float hit_half_width = ImTrunc(TABLE_RESIZE_SEPARATOR_HALF_THICKNESS * g.CurrentDpiScale); const float hit_y1 = (table->FreezeRowsCount >= 1 ? table->OuterRect.Min.y : table->WorkRect.Min.y) + table->AngledHeadersHeight; const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight - table->AngledHeadersHeight); const float hit_y2_head = hit_y1 + table_instance->LastTopHeadersRowHeight; @@ -1433,7 +1433,7 @@ void ImGui::EndTable() if (table->ResizedColumn != -1 && table->InstanceCurrent == table->InstanceInteracted) { ImGuiTableColumn* column = &table->Columns[table->ResizedColumn]; - const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS); + const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + ImTrunc(TABLE_RESIZE_SEPARATOR_HALF_THICKNESS * g.CurrentDpiScale)); const float new_width = ImTrunc(new_x2 - column->MinX - table->CellSpacingX1 - table->CellPaddingX * 2.0f); table->ResizedColumnNextWidth = new_width; } @@ -1963,7 +1963,8 @@ void ImGui::TableEndRow(ImGuiTable* table) cell_bg_rect.ClipWith(table->BgClipRect); cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX); - window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); + if (cell_bg_rect.Min.y < cell_bg_rect.Max.y) + window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); } } @@ -4040,7 +4041,7 @@ float ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offse return offset / (columns->OffMaxX - columns->OffMinX); } -static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; +static const float COLUMNS_HIT_RECT_HALF_THICKNESS = 4.0f; static float GetDraggedColumnOffset(ImGuiOldColumns* columns, int column_index) { @@ -4051,7 +4052,7 @@ static float GetDraggedColumnOffset(ImGuiOldColumns* columns, int column_index) IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); - float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + ImTrunc(COLUMNS_HIT_RECT_HALF_THICKNESS * g.CurrentDpiScale) - window->Pos.x; x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); if ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths)) x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); @@ -4366,7 +4367,7 @@ void ImGui::EndColumns() ImGuiOldColumnData* column = &columns->Columns[n]; float x = window->Pos.x + GetColumnOffset(n); const ImGuiID column_id = columns->ID + ImGuiID(n); - const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; + const float column_hit_hw = ImTrunc(COLUMNS_HIT_RECT_HALF_THICKNESS * g.CurrentDpiScale); const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); if (!ItemAdd(column_hit_rect, column_id, NULL, ImGuiItemFlags_NoNav)) continue; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4fab94969..856e7175d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.6 +// dear imgui, v1.90.7 WIP // (widgets code) /* @@ -2315,7 +2315,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); - const float tweak_factor = tweak_slow ? 1.0f / 1.0f : tweak_fast ? 10.0f : 1.0f; + const float tweak_factor = tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f; adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } @@ -4512,6 +4512,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_cancel = Shortcut(ImGuiKey_Escape, id, f_repeat) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, id, f_repeat)); // FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of. + // FIXME-OSX: Missing support for Alt(option)+Right/Left = go to end of line, or next line if already in end of line. if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }