mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 20:51:06 +01:00 
			
		
		
		
	Refactor: Internals: Moved Popup functions in imgui.cpp in their own section. (part 3) (#2036)
This commit is contained in:
		
							
								
								
									
										212
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -4167,112 +4167,6 @@ static void CheckStacksSize(ImGuiWindow* window, bool write) | ||||
|     IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); | ||||
| } | ||||
|  | ||||
| ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow*) | ||||
| { | ||||
|     ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; | ||||
|     ImRect r_screen = GetViewportRect(); | ||||
|     r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); | ||||
|     return r_screen; | ||||
| } | ||||
|  | ||||
| // r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) | ||||
| // r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. | ||||
| ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) | ||||
| { | ||||
|     ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); | ||||
|     //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); | ||||
|     //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); | ||||
|  | ||||
|     // Combo Box policy (we want a connecting edge) | ||||
|     if (policy == ImGuiPopupPositionPolicy_ComboBox) | ||||
|     { | ||||
|         const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; | ||||
|         for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) | ||||
|         { | ||||
|             const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; | ||||
|             if (n != -1 && dir == *last_dir) // Already tried this direction? | ||||
|                 continue; | ||||
|             ImVec2 pos; | ||||
|             if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default) | ||||
|             if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right | ||||
|             if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left | ||||
|             if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left | ||||
|             if (!r_outer.Contains(ImRect(pos, pos + size))) | ||||
|                 continue; | ||||
|             *last_dir = dir; | ||||
|             return pos; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Default popup policy | ||||
|     const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; | ||||
|     for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) | ||||
|     { | ||||
|         const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; | ||||
|         if (n != -1 && dir == *last_dir) // Already tried this direction? | ||||
|             continue; | ||||
|         float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); | ||||
|         float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); | ||||
|         if (avail_w < size.x || avail_h < size.y) | ||||
|             continue; | ||||
|         ImVec2 pos; | ||||
|         pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; | ||||
|         pos.y = (dir == ImGuiDir_Up)   ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down)  ? r_avoid.Max.y : base_pos_clamped.y; | ||||
|         *last_dir = dir; | ||||
|         return pos; | ||||
|     } | ||||
|  | ||||
|     // Fallback, try to keep within display | ||||
|     *last_dir = ImGuiDir_None; | ||||
|     ImVec2 pos = ref_pos; | ||||
|     pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); | ||||
|     pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); | ||||
|     return pos; | ||||
| } | ||||
|  | ||||
| ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|  | ||||
|     ImRect r_outer = GetWindowAllowedExtentRect(window); | ||||
|     if (window->Flags & ImGuiWindowFlags_ChildMenu) | ||||
|     { | ||||
|         // Child menus typically request _any_ position within the parent menu item, and then our FindBestWindowPosForPopup() function will move the new menu outside the parent bounds. | ||||
|         // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. | ||||
|         IM_ASSERT(g.CurrentWindow == window); | ||||
|         ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; | ||||
|         float horizontal_overlap = g.Style.ItemSpacing.x;       // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). | ||||
|         ImRect r_avoid; | ||||
|         if (parent_window->DC.MenuBarAppending) | ||||
|             r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); | ||||
|         else | ||||
|             r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); | ||||
|         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); | ||||
|     } | ||||
|     if (window->Flags & ImGuiWindowFlags_Popup) | ||||
|     { | ||||
|         ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); | ||||
|         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); | ||||
|     } | ||||
|     if (window->Flags & ImGuiWindowFlags_Tooltip) | ||||
|     { | ||||
|         // Position tooltip (always follows mouse) | ||||
|         float sc = g.Style.MouseCursorScale; | ||||
|         ImVec2 ref_pos = NavCalcPreferredRefPos(); | ||||
|         ImRect r_avoid; | ||||
|         if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) | ||||
|             r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); | ||||
|         else | ||||
|             r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. | ||||
|         ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); | ||||
|         if (window->AutoPosLastDirection == ImGuiDir_None) | ||||
|             pos = ref_pos + 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. | ||||
|         return pos; | ||||
|     } | ||||
|     IM_ASSERT(0); | ||||
|     return window->Pos; | ||||
| } | ||||
|  | ||||
| static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) | ||||
| { | ||||
|     window->SetWindowPosAllowFlags       = enabled ? (window->SetWindowPosAllowFlags       | flags) : (window->SetWindowPosAllowFlags       & ~flags); | ||||
| @@ -6766,6 +6660,112 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) | ||||
|     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); | ||||
| } | ||||
|  | ||||
| ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow*) | ||||
| { | ||||
|     ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; | ||||
|     ImRect r_screen = GetViewportRect(); | ||||
|     r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); | ||||
|     return r_screen; | ||||
| } | ||||
|  | ||||
| // r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) | ||||
| // r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. | ||||
| ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) | ||||
| { | ||||
|     ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); | ||||
|     //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); | ||||
|     //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); | ||||
|  | ||||
|     // Combo Box policy (we want a connecting edge) | ||||
|     if (policy == ImGuiPopupPositionPolicy_ComboBox) | ||||
|     { | ||||
|         const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; | ||||
|         for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) | ||||
|         { | ||||
|             const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; | ||||
|             if (n != -1 && dir == *last_dir) // Already tried this direction? | ||||
|                 continue; | ||||
|             ImVec2 pos; | ||||
|             if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default) | ||||
|             if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right | ||||
|             if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left | ||||
|             if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left | ||||
|             if (!r_outer.Contains(ImRect(pos, pos + size))) | ||||
|                 continue; | ||||
|             *last_dir = dir; | ||||
|             return pos; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Default popup policy | ||||
|     const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; | ||||
|     for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) | ||||
|     { | ||||
|         const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; | ||||
|         if (n != -1 && dir == *last_dir) // Already tried this direction? | ||||
|             continue; | ||||
|         float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); | ||||
|         float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); | ||||
|         if (avail_w < size.x || avail_h < size.y) | ||||
|             continue; | ||||
|         ImVec2 pos; | ||||
|         pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; | ||||
|         pos.y = (dir == ImGuiDir_Up)   ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down)  ? r_avoid.Max.y : base_pos_clamped.y; | ||||
|         *last_dir = dir; | ||||
|         return pos; | ||||
|     } | ||||
|  | ||||
|     // Fallback, try to keep within display | ||||
|     *last_dir = ImGuiDir_None; | ||||
|     ImVec2 pos = ref_pos; | ||||
|     pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); | ||||
|     pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); | ||||
|     return pos; | ||||
| } | ||||
|  | ||||
| ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|  | ||||
|     ImRect r_outer = GetWindowAllowedExtentRect(window); | ||||
|     if (window->Flags & ImGuiWindowFlags_ChildMenu) | ||||
|     { | ||||
|         // Child menus typically request _any_ position within the parent menu item, and then our FindBestWindowPosForPopup() function will move the new menu outside the parent bounds. | ||||
|         // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. | ||||
|         IM_ASSERT(g.CurrentWindow == window); | ||||
|         ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; | ||||
|         float horizontal_overlap = g.Style.ItemSpacing.x;       // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). | ||||
|         ImRect r_avoid; | ||||
|         if (parent_window->DC.MenuBarAppending) | ||||
|             r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); | ||||
|         else | ||||
|             r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); | ||||
|         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); | ||||
|     } | ||||
|     if (window->Flags & ImGuiWindowFlags_Popup) | ||||
|     { | ||||
|         ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); | ||||
|         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); | ||||
|     } | ||||
|     if (window->Flags & ImGuiWindowFlags_Tooltip) | ||||
|     { | ||||
|         // Position tooltip (always follows mouse) | ||||
|         float sc = g.Style.MouseCursorScale; | ||||
|         ImVec2 ref_pos = NavCalcPreferredRefPos(); | ||||
|         ImRect r_avoid; | ||||
|         if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) | ||||
|             r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); | ||||
|         else | ||||
|             r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. | ||||
|         ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); | ||||
|         if (window->AutoPosLastDirection == ImGuiDir_None) | ||||
|             pos = ref_pos + 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. | ||||
|         return pos; | ||||
|     } | ||||
|     IM_ASSERT(0); | ||||
|     return window->Pos; | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
| // NAVIGATION | ||||
| //----------------------------------------------------------------------------- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user