mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-10-26 12:27:30 +00:00 
			
		
		
		
	Reorganised windows moving code, documented a lag in FindHoveredWindow(), fixing lag whole moving windows (#635)
This commit is contained in:
		
							
								
								
									
										69
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -2007,8 +2007,35 @@ void ImGui::NewFrame() | |||||||
|     g.ActiveIdPreviousFrame = g.ActiveId; |     g.ActiveIdPreviousFrame = g.ActiveId; | ||||||
|     g.ActiveIdIsAlive = false; |     g.ActiveIdIsAlive = false; | ||||||
|     g.ActiveIdIsJustActivated = false; |     g.ActiveIdIsJustActivated = false; | ||||||
|     if (!g.ActiveId) |  | ||||||
|  |     // Handle user moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. | ||||||
|  |     if (g.MovedWindowMoveId && g.MovedWindowMoveId == g.ActiveId) | ||||||
|  |     { | ||||||
|  |         KeepAliveID(g.MovedWindowMoveId); | ||||||
|  |         IM_ASSERT(g.MovedWindow && g.MovedWindow->RootWindow); | ||||||
|  |         IM_ASSERT(g.MovedWindow->RootWindow->MoveID == g.MovedWindowMoveId); | ||||||
|  |         if (g.IO.MouseDown[0]) | ||||||
|  |         { | ||||||
|  |             if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoMove)) | ||||||
|  |             { | ||||||
|  |                 g.MovedWindow->PosFloat += g.IO.MouseDelta; | ||||||
|  |                 if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoSavedSettings)) | ||||||
|  |                     MarkSettingsDirty(); | ||||||
|  |             } | ||||||
|  |             FocusWindow(g.MovedWindow); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             SetActiveID(0); | ||||||
|             g.MovedWindow = NULL; |             g.MovedWindow = NULL; | ||||||
|  |             g.MovedWindowMoveId = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         g.MovedWindow = NULL; | ||||||
|  |         g.MovedWindowMoveId = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Delay saving settings so we don't spam disk too much |     // Delay saving settings so we don't spam disk too much | ||||||
|     if (g.SettingsDirtyTimer > 0.0f) |     if (g.SettingsDirtyTimer > 0.0f) | ||||||
| @@ -2019,11 +2046,11 @@ void ImGui::NewFrame() | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow |     // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow | ||||||
|     g.HoveredWindow = FindHoveredWindow(g.IO.MousePos, false); |     g.HoveredWindow = g.MovedWindow ? g.MovedWindow : FindHoveredWindow(g.IO.MousePos, false); | ||||||
|     if (g.HoveredWindow && (g.HoveredWindow->Flags & ImGuiWindowFlags_ChildWindow)) |     if (g.HoveredWindow && (g.HoveredWindow->Flags & ImGuiWindowFlags_ChildWindow)) | ||||||
|         g.HoveredRootWindow = g.HoveredWindow->RootWindow; |         g.HoveredRootWindow = g.HoveredWindow->RootWindow; | ||||||
|     else |     else | ||||||
|         g.HoveredRootWindow = FindHoveredWindow(g.IO.MousePos, true); |         g.HoveredRootWindow = g.MovedWindow ? g.MovedWindow->RootWindow : FindHoveredWindow(g.IO.MousePos, true); | ||||||
|  |  | ||||||
|     if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow()) |     if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow()) | ||||||
|     { |     { | ||||||
| @@ -2420,8 +2447,6 @@ void ImGui::EndFrame() | |||||||
|     ImGui::End(); |     ImGui::End(); | ||||||
|  |  | ||||||
|     // Click to focus window and start moving (after we're done with all our widgets) |     // Click to focus window and start moving (after we're done with all our widgets) | ||||||
|     if (!g.ActiveId) |  | ||||||
|         g.MovedWindow = NULL; |  | ||||||
|     if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) |     if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) | ||||||
|     { |     { | ||||||
|         if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear |         if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear | ||||||
| @@ -2432,7 +2457,8 @@ void ImGui::EndFrame() | |||||||
|                 if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) |                 if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) | ||||||
|                 { |                 { | ||||||
|                     g.MovedWindow = g.HoveredWindow; |                     g.MovedWindow = g.HoveredWindow; | ||||||
|                     SetActiveID(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); |                     g.MovedWindowMoveId = g.HoveredRootWindow->MoveID; | ||||||
|  |                     SetActiveID(g.MovedWindowMoveId, g.HoveredRootWindow); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else if (g.FocusedWindow != NULL && GetFrontMostModalRootWindow() == NULL) |             else if (g.FocusedWindow != NULL && GetFrontMostModalRootWindow() == NULL) | ||||||
| @@ -2842,6 +2868,7 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items | |||||||
| } | } | ||||||
|  |  | ||||||
| // Find window given position, search front-to-back | // Find window given position, search front-to-back | ||||||
|  | // FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via 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 thankfully isn't affected. | ||||||
| static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) | static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) | ||||||
| { | { | ||||||
|     ImGuiState& g = *GImGui; |     ImGuiState& g = *GImGui; | ||||||
| @@ -2856,7 +2883,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) | |||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         // Using the clipped AABB so a child window will typically be clipped by its parent. |         // Using the clipped AABB so a child window will typically be clipped by its parent. | ||||||
|         ImRect bb(window->ClippedWindowRect.Min - g.Style.TouchExtraPadding, window->ClippedWindowRect.Max + g.Style.TouchExtraPadding); |         ImRect bb(window->WindowRectClipped.Min - g.Style.TouchExtraPadding, window->WindowRectClipped.Max + g.Style.TouchExtraPadding); | ||||||
|         if (bb.Contains(pos)) |         if (bb.Contains(pos)) | ||||||
|             return window; |             return window; | ||||||
|     } |     } | ||||||
| @@ -3884,28 +3911,6 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us | |||||||
|                 window->PosFloat = g.IO.MousePos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. |                 window->PosFloat = g.IO.MousePos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // User moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. |  | ||||||
|         KeepAliveID(window->MoveID); |  | ||||||
|         if (g.ActiveId == window->MoveID) |  | ||||||
|         { |  | ||||||
|             if (g.IO.MouseDown[0]) |  | ||||||
|             { |  | ||||||
|                 if (!(flags & ImGuiWindowFlags_NoMove)) |  | ||||||
|                 { |  | ||||||
|                     window->PosFloat += g.IO.MouseDelta; |  | ||||||
|                     if (!(flags & ImGuiWindowFlags_NoSavedSettings)) |  | ||||||
|                         MarkSettingsDirty(); |  | ||||||
|                 } |  | ||||||
|                 IM_ASSERT(g.MovedWindow != NULL); |  | ||||||
|                 FocusWindow(g.MovedWindow); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 SetActiveID(0); |  | ||||||
|                 g.MovedWindow = NULL;   // Not strictly necessary but doing it for sanity. |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Clamp position so it stays visible |         // Clamp position so it stays visible | ||||||
|         if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) |         if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) | ||||||
|         { |         { | ||||||
| @@ -4120,8 +4125,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() |         // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() | ||||||
|         window->ClippedWindowRect = window->Rect(); |         window->WindowRectClipped = window->Rect(); | ||||||
|         window->ClippedWindowRect.Clip(window->ClipRect); |         window->WindowRectClipped.Clip(window->ClipRect); | ||||||
|  |  | ||||||
|         // Pressing CTRL+C while holding on a window copy its content to the clipboard |         // Pressing CTRL+C while holding on a window copy its content to the clipboard | ||||||
|         // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. |         // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. | ||||||
| @@ -4158,7 +4163,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us | |||||||
|         window->Collapsed = parent_window && parent_window->Collapsed; |         window->Collapsed = parent_window && parent_window->Collapsed; | ||||||
|  |  | ||||||
|         if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) |         if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) | ||||||
|             window->Collapsed |= (window->ClippedWindowRect.Min.x >= window->ClippedWindowRect.Max.x || window->ClippedWindowRect.Min.y >= window->ClippedWindowRect.Max.y); |             window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y); | ||||||
|  |  | ||||||
|         // We also hide the window from rendering because we've already added its border to the command list. |         // We also hide the window from rendering because we've already added its border to the command list. | ||||||
|         // (we could perform the check earlier in the function but it is simpler at this point) |         // (we could perform the check earlier in the function but it is simpler at this point) | ||||||
|   | |||||||
| @@ -375,7 +375,8 @@ struct ImGuiState | |||||||
|     bool                    ActiveIdIsJustActivated;            // Set at the time of activation for one frame |     bool                    ActiveIdIsJustActivated;            // Set at the time of activation for one frame | ||||||
|     bool                    ActiveIdAllowOverlap;               // Set only by active widget |     bool                    ActiveIdAllowOverlap;               // Set only by active widget | ||||||
|     ImGuiWindow*            ActiveIdWindow; |     ImGuiWindow*            ActiveIdWindow; | ||||||
|     ImGuiWindow*            MovedWindow;                        // Track the child window we clicked on to move a window. Pointer is only valid if ActiveID is the "#MOVE" identifier of a window. |     ImGuiWindow*            MovedWindow;                        // Track the child window we clicked on to move a window. | ||||||
|  |     ImGuiID                 MovedWindowMoveId;                  // == MovedWindow->RootWindow->MoveId | ||||||
|     ImVector<ImGuiIniData>  Settings;                           // .ini Settings |     ImVector<ImGuiIniData>  Settings;                           // .ini Settings | ||||||
|     float                   SettingsDirtyTimer;                 // Save .ini settinngs on disk when time reaches zero |     float                   SettingsDirtyTimer;                 // Save .ini settinngs on disk when time reaches zero | ||||||
|     ImVector<ImGuiColMod>   ColorModifiers;                     // Stack for PushStyleColor()/PopStyleColor() |     ImVector<ImGuiColMod>   ColorModifiers;                     // Stack for PushStyleColor()/PopStyleColor() | ||||||
| @@ -460,6 +461,7 @@ struct ImGuiState | |||||||
|         ActiveIdAllowOverlap = false; |         ActiveIdAllowOverlap = false; | ||||||
|         ActiveIdWindow = NULL; |         ActiveIdWindow = NULL; | ||||||
|         MovedWindow = NULL; |         MovedWindow = NULL; | ||||||
|  |         MovedWindowMoveId = 0; | ||||||
|         SettingsDirtyTimer = 0.0f; |         SettingsDirtyTimer = 0.0f; | ||||||
|  |  | ||||||
|         SetNextWindowPosVal = ImVec2(0.0f, 0.0f); |         SetNextWindowPosVal = ImVec2(0.0f, 0.0f); | ||||||
| @@ -627,7 +629,7 @@ struct IMGUI_API ImGuiWindow | |||||||
|     ImGuiDrawContext        DC;                                 // Temporary per-window data, reset at the beginning of the frame |     ImGuiDrawContext        DC;                                 // Temporary per-window data, reset at the beginning of the frame | ||||||
|     ImVector<ImGuiID>       IDStack;                            // ID stack. ID are hashes seeded with the value at the top of the stack |     ImVector<ImGuiID>       IDStack;                            // ID stack. ID are hashes seeded with the value at the top of the stack | ||||||
|     ImRect                  ClipRect;                           // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. |     ImRect                  ClipRect;                           // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. | ||||||
|     ImRect                  ClippedWindowRect;                  // = ClipRect just after setup in Begin() |     ImRect                  WindowRectClipped;                  // = WindowRect just after setup in Begin(). == window->Rect() for root window. | ||||||
|     int                     LastFrameActive; |     int                     LastFrameActive; | ||||||
|     float                   ItemWidthDefault; |     float                   ItemWidthDefault; | ||||||
|     ImGuiSimpleColumns      MenuColumns;                        // Simplified columns storage for menu items |     ImGuiSimpleColumns      MenuColumns;                        // Simplified columns storage for menu items | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ocornut
					ocornut