mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 13:11:05 +01:00 
			
		
		
		
	Refactor: Internals: Moved Popup functions in imgui.cpp in their own section. (part 1) (#2036)
This commit is contained in:
		
							
								
								
									
										308
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										308
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -4709,132 +4709,6 @@ void ImGui::EndTooltip() | ||||
|     End(); | ||||
| } | ||||
|  | ||||
| // Mark popup as open (toggle toward open state). | ||||
| // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. | ||||
| // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). | ||||
| // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) | ||||
| void ImGui::OpenPopupEx(ImGuiID id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* parent_window = g.CurrentWindow; | ||||
|     int current_stack_size = g.CurrentPopupStack.Size; | ||||
|     ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. | ||||
|     popup_ref.PopupId = id; | ||||
|     popup_ref.Window = NULL; | ||||
|     popup_ref.ParentWindow = parent_window; | ||||
|     popup_ref.OpenFrameCount = g.FrameCount; | ||||
|     popup_ref.OpenParentId = parent_window->IDStack.back(); | ||||
|     popup_ref.OpenMousePos = g.IO.MousePos; | ||||
|     popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); | ||||
|  | ||||
|     //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id); | ||||
|     if (g.OpenPopupStack.Size < current_stack_size + 1) | ||||
|     { | ||||
|         g.OpenPopupStack.push_back(popup_ref); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui | ||||
|         // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing | ||||
|         // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. | ||||
|         if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) | ||||
|         { | ||||
|             g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Close child popups if any, then flag popup for open/reopen | ||||
|             g.OpenPopupStack.resize(current_stack_size + 1); | ||||
|             g.OpenPopupStack[current_stack_size] = popup_ref; | ||||
|         } | ||||
|  | ||||
|         // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). | ||||
|         // This is equivalent to what ClosePopupToLevel() does. | ||||
|         //if (g.OpenPopupStack[current_stack_size].PopupId == id) | ||||
|         //    FocusWindow(parent_window); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void ImGui::OpenPopup(const char* str_id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     OpenPopupEx(g.CurrentWindow->GetID(str_id)); | ||||
| } | ||||
|  | ||||
| void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     if (g.OpenPopupStack.empty()) | ||||
|         return; | ||||
|  | ||||
|     // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. | ||||
|     // Don't close our own child popup windows. | ||||
|     int n = 0; | ||||
|     if (ref_window) | ||||
|     { | ||||
|         for (n = 0; n < g.OpenPopupStack.Size; n++) | ||||
|         { | ||||
|             ImGuiPopupRef& popup = g.OpenPopupStack[n]; | ||||
|             if (!popup.Window) | ||||
|                 continue; | ||||
|             IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); | ||||
|             if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) | ||||
|                 continue; | ||||
|  | ||||
|             // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) | ||||
|             bool has_focus = false; | ||||
|             for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) | ||||
|                 has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow); | ||||
|             if (!has_focus) | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|     if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below | ||||
|         ClosePopupToLevel(n); | ||||
| } | ||||
|  | ||||
| ImGuiWindow* ImGui::GetFrontMostPopupModal() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) | ||||
|         if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) | ||||
|             if (popup->Flags & ImGuiWindowFlags_Modal) | ||||
|                 return popup; | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void ImGui::ClosePopupToLevel(int remaining) | ||||
| { | ||||
|     IM_ASSERT(remaining >= 0); | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow; | ||||
|     if (g.NavLayer == 0) | ||||
|         focus_window = NavRestoreLastChildNavWindow(focus_window); | ||||
|     FocusWindow(focus_window); | ||||
|     focus_window->DC.NavHideHighlightOneFrame = true; | ||||
|     g.OpenPopupStack.resize(remaining); | ||||
| } | ||||
|  | ||||
| void ImGui::ClosePopup(ImGuiID id) | ||||
| { | ||||
|     if (!IsPopupOpen(id)) | ||||
|         return; | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ClosePopupToLevel(g.OpenPopupStack.Size - 1); | ||||
| } | ||||
|  | ||||
| // Close the popup we have begin-ed into. | ||||
| void ImGui::CloseCurrentPopup() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     int popup_idx = g.CurrentPopupStack.Size - 1; | ||||
|     if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) | ||||
|         return; | ||||
|     while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|         popup_idx--; | ||||
|     ClosePopupToLevel(popup_idx); | ||||
| } | ||||
|  | ||||
| bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -4868,18 +4742,6 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) | ||||
|     return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); | ||||
| } | ||||
|  | ||||
| bool ImGui::IsPopupOpen(ImGuiID id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; | ||||
| } | ||||
|  | ||||
| bool ImGui::IsPopupOpen(const char* str_id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); | ||||
| } | ||||
|  | ||||
| bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -4904,7 +4766,6 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla | ||||
|             ClosePopup(id); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| @@ -4920,19 +4781,6 @@ void ImGui::EndPopup() | ||||
|     End(); | ||||
| } | ||||
|  | ||||
| bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) | ||||
| { | ||||
|     ImGuiWindow* window = GImGui->CurrentWindow; | ||||
|     if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) | ||||
|     { | ||||
|         ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! | ||||
|         IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) | ||||
|         OpenPopupEx(id); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| // This is a helper to handle the simplest case of associating one named popup to one given widget. | ||||
| // You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). | ||||
| // You can pass a NULL str_id to use the identifier of the last item. | ||||
| @@ -5010,7 +4858,6 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size | ||||
|         SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item | ||||
|         g.ActiveIdSource = ImGuiInputSource_Nav; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| @@ -7761,6 +7608,161 @@ void ImGui::Unindent(float indent_w) | ||||
|     window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
| // POPUPS | ||||
| //----------------------------------------------------------------------------- | ||||
|  | ||||
| bool ImGui::IsPopupOpen(ImGuiID id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; | ||||
| } | ||||
|  | ||||
| bool ImGui::IsPopupOpen(const char* str_id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); | ||||
| } | ||||
|  | ||||
| ImGuiWindow* ImGui::GetFrontMostPopupModal() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) | ||||
|         if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) | ||||
|             if (popup->Flags & ImGuiWindowFlags_Modal) | ||||
|                 return popup; | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void ImGui::OpenPopup(const char* str_id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     OpenPopupEx(g.CurrentWindow->GetID(str_id)); | ||||
| } | ||||
|  | ||||
| // Mark popup as open (toggle toward open state). | ||||
| // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. | ||||
| // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). | ||||
| // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) | ||||
| void ImGui::OpenPopupEx(ImGuiID id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* parent_window = g.CurrentWindow; | ||||
|     int current_stack_size = g.CurrentPopupStack.Size; | ||||
|     ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. | ||||
|     popup_ref.PopupId = id; | ||||
|     popup_ref.Window = NULL; | ||||
|     popup_ref.ParentWindow = parent_window; | ||||
|     popup_ref.OpenFrameCount = g.FrameCount; | ||||
|     popup_ref.OpenParentId = parent_window->IDStack.back(); | ||||
|     popup_ref.OpenMousePos = g.IO.MousePos; | ||||
|     popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); | ||||
|  | ||||
|     //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id); | ||||
|     if (g.OpenPopupStack.Size < current_stack_size + 1) | ||||
|     { | ||||
|         g.OpenPopupStack.push_back(popup_ref); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui | ||||
|         // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing | ||||
|         // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. | ||||
|         if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) | ||||
|         { | ||||
|             g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Close child popups if any, then flag popup for open/reopen | ||||
|             g.OpenPopupStack.resize(current_stack_size + 1); | ||||
|             g.OpenPopupStack[current_stack_size] = popup_ref; | ||||
|         } | ||||
|  | ||||
|         // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). | ||||
|         // This is equivalent to what ClosePopupToLevel() does. | ||||
|         //if (g.OpenPopupStack[current_stack_size].PopupId == id) | ||||
|         //    FocusWindow(parent_window); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) | ||||
| { | ||||
|     ImGuiWindow* window = GImGui->CurrentWindow; | ||||
|     if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) | ||||
|     { | ||||
|         ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! | ||||
|         IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) | ||||
|         OpenPopupEx(id); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     if (g.OpenPopupStack.empty()) | ||||
|         return; | ||||
|  | ||||
|     // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. | ||||
|     // Don't close our own child popup windows. | ||||
|     int n = 0; | ||||
|     if (ref_window) | ||||
|     { | ||||
|         for (n = 0; n < g.OpenPopupStack.Size; n++) | ||||
|         { | ||||
|             ImGuiPopupRef& popup = g.OpenPopupStack[n]; | ||||
|             if (!popup.Window) | ||||
|                 continue; | ||||
|             IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); | ||||
|             if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) | ||||
|                 continue; | ||||
|  | ||||
|             // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) | ||||
|             bool has_focus = false; | ||||
|             for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) | ||||
|                 has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow); | ||||
|             if (!has_focus) | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|     if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below | ||||
|         ClosePopupToLevel(n); | ||||
| } | ||||
|  | ||||
| void ImGui::ClosePopupToLevel(int remaining) | ||||
| { | ||||
|     IM_ASSERT(remaining >= 0); | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow; | ||||
|     if (g.NavLayer == 0) | ||||
|         focus_window = NavRestoreLastChildNavWindow(focus_window); | ||||
|     FocusWindow(focus_window); | ||||
|     focus_window->DC.NavHideHighlightOneFrame = true; | ||||
|     g.OpenPopupStack.resize(remaining); | ||||
| } | ||||
|  | ||||
| void ImGui::ClosePopup(ImGuiID id) | ||||
| { | ||||
|     if (!IsPopupOpen(id)) | ||||
|         return; | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ClosePopupToLevel(g.OpenPopupStack.Size - 1); | ||||
| } | ||||
|  | ||||
| // Close the popup we have begin-ed into. | ||||
| void ImGui::CloseCurrentPopup() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     int popup_idx = g.CurrentPopupStack.Size - 1; | ||||
|     if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) | ||||
|         return; | ||||
|     while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|         popup_idx--; | ||||
|     ClosePopupToLevel(popup_idx); | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
| // NAVIGATION | ||||
| //----------------------------------------------------------------------------- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user