From 38e357ef109a27599dd09f2b6324731209ba1f64 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 12 Apr 2018 19:56:14 +0200 Subject: [PATCH] Viewport: Virtual mouse position are patched immediately when viewports are moved in the virtual space, avoiding interaction glitchs on a resizing frame. (#1542) --- imgui.cpp | 16 +++++++++++++++- imgui_demo.cpp | 1 + imgui_internal.h | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 36644a437..cbe288761 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3424,6 +3424,7 @@ static void ImGui::UpdateViewports() // Destroy if (viewport == viewport_ref) viewport_ref = NULL; if (viewport == g.MousePosViewport) g.MousePosViewport = NULL; + if (viewport == g.MousePosPrevViewport) g.MousePosPrevViewport = NULL; if (viewport == g.MouseHoveredPrevViewport) g.MouseHoveredPrevViewport = NULL; IM_ASSERT(viewport->RendererUserData == NULL && viewport->PlatformUserData == NULL && viewport->PlatformHandle == NULL); IM_ASSERT(g.PlatformIO.Viewports.contains(viewport) == false); @@ -3690,6 +3691,7 @@ static void NewFrameUpdateMouseInputs() g.IO.MouseClickedPos[i] = g.IO.MousePos; g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + g.MouseClickedPosViewportId[i] = g.MousePosViewport->ID; } else if (g.IO.MouseDown[i]) { @@ -4664,11 +4666,22 @@ static void ImGui::TranslateOrEraseViewports(int viewport_idx_min, int viewport_ continue; TranslateWindowX(window, delta_x); } + for (int n = viewport_idx_min; n < viewport_idx_max; n++) { ImGuiViewportP* viewport = g.Viewports[n]; viewport->Pos.x += delta_x; viewport->Idx += delta_idx; + + // Patch mouse positions immediately so mouse delta will not appears to jump around + ImGuiID viewport_id = viewport->ID; + if (viewport_id == g.IO.MousePosViewport) // We are early in NewFrame and g.MousePosViewport hasn't been set, patch the source. + g.IO.MousePos.x += delta_x; + if (viewport == g.MousePosPrevViewport) + g.IO.MousePosPrev.x += delta_x; + for (int mouse_n = 0; mouse_n < IM_ARRAYSIZE(g.MouseClickedPosViewportId); mouse_n++) + if (g.MouseClickedPosViewportId[mouse_n] == viewport_id) + g.IO.MouseClickedPos[mouse_n].x += delta_x; } } @@ -5277,7 +5290,8 @@ ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) lock_threshold = g.IO.MouseDragThreshold; if (g.IO.MouseDown[button]) if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) - return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment). + if (g.MousePosViewport->ID == g.MouseClickedPosViewportId[button]) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment). return ImVec2(0.0f, 0.0f); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ca2be4cd7..3111599e7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1865,6 +1865,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); else ImGui::Text("Mouse pos: "); + ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } diff --git a/imgui_internal.h b/imgui_internal.h index f5e81b343..a210592d8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -643,6 +643,7 @@ struct ImGuiContext ImGuiViewportP* MousePosViewport; ImGuiViewportP* MousePosPrevViewport; ImGuiViewportP* MouseHoveredPrevViewport; + ImGuiID MouseClickedPosViewportId[5]; // For rarely used fields we only compare to, store viewport ID only so we don't have to clean dangling pointers // Navigation data (for gamepad/keyboard) ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' @@ -771,6 +772,7 @@ struct ImGuiContext CurrentViewport = NULL; MousePosViewport = NULL; MousePosPrevViewport = MouseHoveredPrevViewport = NULL; + memset(MouseClickedPosViewportId, 0, sizeof(MouseClickedPosViewportId)); NavWindow = NULL; NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;