소스 검색

Viewport: Virtual mouse position are patched immediately when viewports are moved in the virtual space, avoiding interaction glitchs on a resizing frame. (#1542)

omar 7 년 전
부모
커밋
38e357ef10
3개의 변경된 파일18개의 추가작업 그리고 1개의 파일을 삭제
  1. 15 1
      imgui.cpp
  2. 1 0
      imgui_demo.cpp
  3. 2 0
      imgui_internal.h

+ 15 - 1
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);
 }
 

+ 1 - 0
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: <INVALID>");
+            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); }

+ 2 - 0
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;