Fix popup and tooltip positioning when not fitting in the screen. Amend fa42ccea8.

# Conflicts:
#	docs/CHANGELOG.txt
This commit is contained in:
ocornut
2020-09-17 11:00:56 +02:00
parent b7b08f52a4
commit c47bcb25ed
4 changed files with 41 additions and 32 deletions

View File

@ -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;