diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index e9ca12ed5..f6aad1b5c 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -418,7 +418,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw 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) #if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)) - io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy) + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) #endif bd->Window = window; @@ -539,8 +539,7 @@ static void ImGui_ImplGlfw_UpdateMouseData() ImGuiIO& io = ImGui::GetIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - io.MouseHoveredViewport = 0; - + ImGuiID mouse_viewport_id = 0; const ImVec2 mouse_pos_prev = io.MousePos; for (int n = 0; n < platform_io.Viewports.Size; n++) { @@ -577,7 +576,7 @@ static void ImGui_ImplGlfw_UpdateMouseData() } } - // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering. + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. // - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag. // - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture. @@ -593,11 +592,14 @@ static void ImGui_ImplGlfw_UpdateMouseData() glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input); #endif if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input) - io.MouseHoveredViewport = viewport->ID; + mouse_viewport_id = viewport->ID; #else // We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse. #endif } + + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) + io.AddMouseViewportEvent(mouse_viewport_id); } static void ImGui_ImplGlfw_UpdateMouseCursor() @@ -866,7 +868,7 @@ static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPAR { if (msg == WM_NCHITTEST) { - // Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL). + // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL). // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index fb624f6c3..9ca9fe5ae 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -359,7 +359,7 @@ bool ImGui_ImplOSX_Init(NSView* view) 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 set io.MouseHoveredViewport correctly (optional) + //io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) io.BackendPlatformName = "imgui_impl_osx"; // Load cursors. Some of them are undocumented. diff --git a/backends/imgui_impl_sdl.cpp b/backends/imgui_impl_sdl.cpp index 3e7237736..7137d7467 100644 --- a/backends/imgui_impl_sdl.cpp +++ b/backends/imgui_impl_sdl.cpp @@ -369,7 +369,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context) if (mouse_can_use_global_state) { io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) - io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;//We can set io.MouseHoveredViewport correctly (optional) + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;// We can call io.AddMouseViewportEvent() with correct data (optional) } bd->Window = window; @@ -521,17 +521,18 @@ static void ImGui_ImplSDL2_UpdateMouseData() } } - // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering. + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag. // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported // by the backend, and use its flawed heuristic to guess the viewport behind. // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). - io.MouseHoveredViewport = 0; + ImGuiID mouse_viewport_id = 0; if (SDL_Window* sdl_mouse_window = SDL_GetWindowFromID(bd->MouseWindowID)) if (ImGuiViewport* mouse_viewport = ImGui::FindViewportByPlatformHandle((void*)sdl_mouse_window)) - io.MouseHoveredViewport = mouse_viewport->ID; + mouse_viewport_id = mouse_viewport->ID; + io.AddMouseViewportEvent(mouse_viewport_id); } static void ImGui_ImplSDL2_UpdateMouseCursor() diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 7d7ff0fe0..017baa57a 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -131,7 +131,7 @@ bool ImGui_ImplWin32_Init(void* hwnd) 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 set io.MouseHoveredViewport correctly (optional) + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) bd->hWnd = (HWND)hwnd; bd->WantUpdateHasGamepad = true; @@ -299,18 +299,19 @@ static void ImGui_ImplWin32_UpdateMouseData() } } - // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering. + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. // - [X] Win32 backend correctly ignore viewports with the _NoInputs flag (here using ::WindowFromPoint with WM_NCHITTEST + HTTRANSPARENT in WndProc does that) // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported // by the backend, and use its flawed heuristic to guess the viewport behind. // - [X] Win32 backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). - io.MouseHoveredViewport = 0; + ImGuiID mouse_viewport_id = 0; if (has_mouse_screen_pos) if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd)) - io.MouseHoveredViewport = viewport->ID; + mouse_viewport_id = viewport->ID; + io.AddMouseViewportEvent(mouse_viewport_id); } // Gamepad navigation mapping @@ -1077,7 +1078,7 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, return MA_NOACTIVATE; break; case WM_NCHITTEST: - // Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL). + // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() correctly. (which is optional). // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 846768985..e1fd7b538 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -90,7 +90,7 @@ Other changes: - Added io.ConfigViewportsNoDecoration option. - Added io.ConfigViewportsNoDefaultParent option. - Added ImGuiBackendFlags_PlatformHasViewports, ImGuiBackendFlags_RendererHasViewports, ImGuiBackendFlags_HasMouseHoveredViewport backend flags. -- Added io.MouseHoveredViewport (optional _even_ for multi-viewport support, tied to ImGuiBackendFlags_HasMouseHoveredViewport flag). +- Added io.AddMouseViewportEvent() (optional _even_ for multi-viewport support, tied to ImGuiBackendFlags_HasMouseHoveredViewport flag). - Expanded ImGuiViewport structure, ImGuiViewportFlags flags. - Added ImGuiWindowClass and SetNextWindowClass() for passing viewport related hints to the OS/platform back-end. - Examples: Renderer: OpenGL2, OpenGL3, DirectX9, DirectX10, DirectX11, DirectX12, Vulkan: Added support for multi-viewports. @@ -206,12 +206,13 @@ Other Changes: Docking+Viewports Branch: +- Viewports, IO: Added io.AddMouseViewportEvent() function to queue hovered viewport change (when known by backend). - Viewports: Relaxed specs for backend supporting ImGuiBackendFlags_HasMouseHoveredViewport: it is now _optional_ - for the backend to have to ignore viewports with the _NoInputs flag when setting io.MouseHoveredViewport. It is + for the backend to have to ignore viewports with the _NoInputs flag when call io.AddMouseViewportEvent(). It is much better if they can (Win32 and GLFW 3.3+ backends can, SDL and GLFW 3.2 backends cannot, they are lacking data). A concrete example is: when dragging a viewport for docking, the viewport is marked with _NoInputs to allow us - to pick the target viewports for docking. If the backend reports a viewport with _NoInputs in io.MouseHoveredViewport, - then Dear ImGui will revert to its flawed heuristic to find the viewport under. + to pick the target viewports for docking. If the backend reports a viewport with _NoInputs when calling the + io.AddMouseViewportEvent() function, then Dear ImGui will revert to its flawed heuristic to find the viewport under. By lowering those specs, we allow the SDL and more backend to support this, only relying on the heuristic in a few drag and drop situations rather that relying on it everywhere. - Viewports: Fixed a CTRL+TAB crash with viewports enabled when the window list needs to appears in diff --git a/imgui.cpp b/imgui.cpp index b67202e24..644b3d7a0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1390,6 +1390,19 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) g.InputEventsQueue.push_back(e); } +void ImGuiIO::AddMouseViewportEvent(ImGuiID viewport_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); + IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport); + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MouseViewport; + e.Source = ImGuiInputSource_Mouse; + e.MouseViewport.HoveredViewportID = viewport_id; + g.InputEventsQueue.push_back(e); +} + void ImGuiIO::AddFocusEvent(bool focused) { ImGuiContext& g = *GImGui; @@ -8354,6 +8367,10 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) mouse_wheeled = true; } } + else if (e->Type == ImGuiInputEventType_MouseViewport) + { + io.MouseHoveredViewport = e->MouseViewport.HoveredViewportID; + } else if (e->Type == ImGuiInputEventType_Key) { IM_ASSERT(e->Key.Key != ImGuiKey_None); diff --git a/imgui.h b/imgui.h index 5f63e704b..3d60e3ac3 100644 --- a/imgui.h +++ b/imgui.h @@ -1611,7 +1611,7 @@ enum ImGuiBackendFlags_ // [BETA] Viewports ImGuiBackendFlags_PlatformHasViewports = 1 << 10, // Backend Platform supports multiple viewports. - ImGuiBackendFlags_HasMouseHoveredViewport=1 << 11, // Backend Platform supports setting io.MouseHoveredViewport to the viewport directly under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag (Win32 backend, GLFW 3.30+ backend can do this, SDL backend cannot). If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under. + ImGuiBackendFlags_HasMouseHoveredViewport=1 << 11, // Backend Platform supports calling io.AddMouseViewportEvent() with the viewport under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag (Win32 backend, GLFW 3.30+ backend can do this, SDL backend cannot). If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under. ImGuiBackendFlags_RendererHasViewports = 1 << 12 // Backend Renderer supports multiple viewports. }; @@ -2076,7 +2076,7 @@ struct ImGuiIO bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all backends. - ImGuiID MouseHoveredViewport; // (Optional) With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). + ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). bool KeyCtrl; // Keyboard modifier down: Control bool KeyShift; // Keyboard modifier down: Shift bool KeyAlt; // Keyboard modifier down: Alt @@ -2089,6 +2089,7 @@ struct ImGuiIO IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update + IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this. IMGUI_API void AddFocusEvent(bool focused); // Queue an hosting application/platform windows gain or loss of focus IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate diff --git a/imgui_internal.h b/imgui_internal.h index 9a5c7d9bc..5f07d7f76 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -917,6 +917,7 @@ enum ImGuiInputEventType ImGuiInputEventType_MousePos, ImGuiInputEventType_MouseWheel, ImGuiInputEventType_MouseButton, + ImGuiInputEventType_MouseViewport, ImGuiInputEventType_Key, ImGuiInputEventType_KeyMods, ImGuiInputEventType_Char, @@ -940,6 +941,7 @@ enum ImGuiInputSource struct ImGuiInputEventMousePos { float PosX, PosY; }; struct ImGuiInputEventMouseWheel { float WheelX, WheelY; }; struct ImGuiInputEventMouseButton { int Button; bool Down; }; +struct ImGuiInputEventMouseViewport { ImGuiID HoveredViewportID; }; struct ImGuiInputEventKey { ImGuiKey Key; bool Down; }; struct ImGuiInputEventKeyMods { ImGuiKeyModFlags Mods; }; struct ImGuiInputEventText { unsigned int Char; }; @@ -955,6 +957,7 @@ struct ImGuiInputEvent ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos ImGuiInputEventMouseWheel MouseWheel; // if Type == ImGuiInputEventType_MouseWheel ImGuiInputEventMouseButton MouseButton; // if Type == ImGuiInputEventType_MouseButton + ImGuiInputEventMouseViewport MouseViewport; // if Type == ImGuiInputEventType_MouseViewport ImGuiInputEventKey Key; // if Type == ImGuiInputEventType_Key ImGuiInputEventKeyMods KeyMods; // if Type == ImGuiInputEventType_Modifiers ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text