mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 05:01:05 +01:00 
			
		
		
		
	Fix popup and tooltip positioning when not fitting in the screen. Amend fa42ccea8.
# Conflicts: # docs/CHANGELOG.txt
This commit is contained in:
		
							
								
								
									
										65
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -8007,37 +8007,47 @@ ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& s | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 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++) | ||||
|     // Tooltip and Default popup policy | ||||
|     // (Always first try the direction we used on the last frame, if any) | ||||
|     if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) | ||||
|     { | ||||
|         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); | ||||
|         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; | ||||
|  | ||||
|         // There is no point in switching left/right sides when popup height exceeds available height or top/bottom | ||||
|         // sides when popup width exceeds available width. | ||||
|         if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) | ||||
|             continue; | ||||
|         else if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) | ||||
|             continue; | ||||
|             const 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); | ||||
|             const 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); | ||||
|  | ||||
|         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; | ||||
|             // If there not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width) | ||||
|             if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) | ||||
|                 continue; | ||||
|             if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) | ||||
|                 continue; | ||||
|  | ||||
|         // Clamp top-left (or top-right for RTL languages in the future) corner of popup to remain visible. | ||||
|         pos.x = ImMax(pos.x, r_outer.Min.x); | ||||
|         pos.y = ImMax(pos.y, r_outer.Min.y); | ||||
|             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; | ||||
|             // Clamp top-left corner of popup | ||||
|             pos.x = ImMax(pos.x, r_outer.Min.x); | ||||
|             pos.y = ImMax(pos.y, r_outer.Min.y); | ||||
|  | ||||
|             *last_dir = dir; | ||||
|             return pos; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Fallback, try to keep within display | ||||
|     // Fallback when not enough room: | ||||
|     *last_dir = ImGuiDir_None; | ||||
|  | ||||
|     // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. | ||||
|     if (policy == ImGuiPopupPositionPolicy_Tooltip) | ||||
|         return ref_pos + ImVec2(2, 2);  | ||||
|  | ||||
|     // Otherwise try to keep within display | ||||
|     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); | ||||
| @@ -8070,12 +8080,12 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) | ||||
|             r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field | ||||
|         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); | ||||
|         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); | ||||
|     } | ||||
|     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); | ||||
|         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); | ||||
|     } | ||||
|     if (window->Flags & ImGuiWindowFlags_Tooltip) | ||||
|     { | ||||
| @@ -8087,10 +8097,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) | ||||
|             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; | ||||
|         return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); | ||||
|     } | ||||
|     IM_ASSERT(0); | ||||
|     return window->Pos; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user