Viewport: Win32, GLFW, SDL: Clarified back-ends by using global mouse position direction. GLFW: disabled io.MouseHoveredViewport setting under Mac/Linux. (#1542, #2117) + various comments.

This commit is contained in:
omar
2018-12-06 16:30:10 +01:00
parent ac52d9d44c
commit f3a0b17bb8
4 changed files with 67 additions and 34 deletions

View File

@ -141,7 +141,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
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)
#if GLFW_HAS_GLFW_HOVERED
#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
#endif
io.BackendPlatformName = "imgui_impl_glfw";
@ -264,14 +264,32 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
{
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x + viewport->Pos.x, (float)mouse_y + viewport->Pos.y);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
int window_x, window_y;
glfwGetWindowPos(window, &window_x, &window_y);
io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y);
}
else
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
}
}
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0;
}
#if GLFW_HAS_GLFW_HOVERED
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
// (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
// Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
// - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
// - This is _regardless_ of whether another viewport is focused or being dragged from.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the
// rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows.
// [GLFW] FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
// See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32)
if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !(viewport->Flags & ImGuiViewportFlags_NoInputs))
io.MouseHoveredViewport = viewport->ID;
#endif

View File

@ -264,16 +264,20 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
SDL_Window* focused_window = SDL_GetKeyboardFocus();
if (focused_window)
{
// SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
// The creation of new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
int wx, wy;
SDL_GetWindowPosition(focused_window, &wx, &wy);
SDL_GetGlobalMouseState(&mx, &my);
mx -= wx;
my -= wy;
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
SDL_GetGlobalMouseState(&mx, &my);
if (ImGui::FindViewportByPlatformHandle((void*)focused_window) != NULL)
io.MousePos = ImVec2((float)mx, (float)my);
}
else
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
if (focused_window == g_Window)
io.MousePos = ImVec2((float)mx, (float)my);
}
}
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)focused_window))
io.MousePos = ImVec2(viewport->Pos.x + (float)mx, viewport->Pos.y + (float)my);
// We already retrieve global mouse position, SDL_CaptureMouse() also let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't trigger the OS window resize cursor
// The function is only supported from SDL 2.0.4 (released Jan 2016)

View File

@ -135,21 +135,14 @@ static bool ImGui_ImplWin32_UpdateMouseCursor()
return true;
}
// This code supports multiple OS Windows mapped into different ImGui viewports,
// Because of that, it is a little more complicated than your typical single-viewport binding code.
// A) In Single-viewport mode imgui needs:
// - io.MousePos ............... mouse position, in client window coordinates (what you'd get from GetCursorPos+ScreenToClient() or from WM_MOUSEMOVE)
// io.MousePos is (0,0) when the mouse is on the upper-left corner of the application window.
// B) In Multi-viewport mode imgui needs: (when ImGuiConfigFlags_ViewportsEnable is set)
// - io.MousePos ............... mouse position, in OS absolute coordinates (what you'd get from GetCursorPos(), or from WM_MOUSEMOVE+viewport->Pos).
// io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor.
// - io.MouseHoveredViewport ... [optional] viewport which mouse is hovering, with _VERY_ specific and strict conditions (Read comments next to io.MouseHoveredViewport. This is _NOT_ easy to provide in many high-level engine because of how we use the ImGuiViewportFlags_NoInputs flag)
// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
// Because of that, it is a little more complicated than your typical single-viewport binding code!
static void ImGui_ImplWin32_UpdateMousePos()
{
ImGuiIO& io = ImGui::GetIO();
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// (When multi-viewports are enabled, all imgui positions are same as OS positions.)
// (When multi-viewports are enabled, all imgui positions are same as OS positions)
if (io.WantSetMousePos)
{
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
@ -161,21 +154,39 @@ static void ImGui_ImplWin32_UpdateMousePos()
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
io.MouseHoveredViewport = 0;
// Set mouse position and viewport
// (Note that ScreenToClient() and adding +viewport->Pos are mutually cancelling each others when we have multi-viewport enabled. In single-viewport mode, viewport->Pos will be zero)
POINT pos;
if (!::GetCursorPos(&pos))
// Set imgui mouse position
POINT mouse_screen_pos;
if (!::GetCursorPos(&mouse_screen_pos))
return;
if (HWND focused_hwnd = ::GetActiveWindow())
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)focused_hwnd))
{
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
POINT client_pos = pos;
::ScreenToClient(focused_hwnd, &client_pos);
io.MousePos = ImVec2(viewport->Pos.x + (float)client_pos.x, viewport->Pos.y + (float)client_pos.y);
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
// This is the position you can get with GetCursorPos(). In theory adding viewport->Pos is also the reverse operation of doing ScreenToClient().
if (ImGui::FindViewportByPlatformHandle((void*)focused_hwnd) != NULL)
io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y);
}
else
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window.)
// This is the position you can get with GetCursorPos() + ScreenToClient() or from WM_MOUSEMOVE.
if (focused_hwnd == g_hWnd)
{
POINT mouse_client_pos = mouse_screen_pos;
::ScreenToClient(focused_hwnd, &mouse_client_pos);
io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y);
}
}
}
// Our back-end can tell which window is under the mouse cursor (not every back-end can), so pass that info to imgui
if (HWND hovered_hwnd = ::WindowFromPoint(pos))
// (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
// Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
// - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
// - This is _regardless_ of whether another viewport is focused or being dragged from.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the
// rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows.
if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd))
io.MouseHoveredViewport = viewport->ID;
}