mirror of
https://github.com/Drezil/imgui.git
synced 2024-12-19 06:26:35 +00:00
Refactor: Internals: Moved Popup functions in imgui.cpp in their own section. (part 3) (#2036)
This commit is contained in:
parent
d7c04ccbfb
commit
00262d51ad
244
imgui.cpp
244
imgui.cpp
@ -4842,128 +4842,6 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
|
||||
IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
|
||||
}
|
||||
|
||||
// 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.
|
||||
// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor
|
||||
// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport.
|
||||
// this allows us to have tooltips/popups displayed out of the parent viewport.)
|
||||
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;
|
||||
}
|
||||
|
||||
ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImRect r_screen;
|
||||
if (window->ViewportAllowPlatformMonitorExtend >= 0)
|
||||
{
|
||||
// Extent with be in the frame of reference of the given viewport (so Min is likely to be negative here)
|
||||
const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[window->ViewportAllowPlatformMonitorExtend];
|
||||
r_screen.Min = monitor.WorkPos;
|
||||
r_screen.Max = monitor.WorkPos + monitor.WorkSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_screen.Min = window->Viewport->Pos;
|
||||
r_screen.Max = window->Viewport->Pos + window->Viewport->Size;
|
||||
}
|
||||
ImVec2 padding = g.Style.DisplaySafeAreaPadding;
|
||||
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;
|
||||
}
|
||||
|
||||
ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
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.
|
||||
ImGuiWindow* parent_window = window->ParentWindow;
|
||||
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_outer = GetWindowAllowedExtentRect(window);
|
||||
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_outer = GetWindowAllowedExtentRect(window);
|
||||
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_outer = GetWindowAllowedExtentRect(window);
|
||||
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);
|
||||
@ -7763,6 +7641,128 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
|
||||
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor
|
||||
// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport.
|
||||
// this allows us to have tooltips/popups displayed out of the parent viewport.)
|
||||
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;
|
||||
}
|
||||
|
||||
ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImRect r_screen;
|
||||
if (window->ViewportAllowPlatformMonitorExtend >= 0)
|
||||
{
|
||||
// Extent with be in the frame of reference of the given viewport (so Min is likely to be negative here)
|
||||
const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[window->ViewportAllowPlatformMonitorExtend];
|
||||
r_screen.Min = monitor.WorkPos;
|
||||
r_screen.Max = monitor.WorkPos + monitor.WorkSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_screen.Min = window->Viewport->Pos;
|
||||
r_screen.Max = window->Viewport->Pos + window->Viewport->Size;
|
||||
}
|
||||
ImVec2 padding = g.Style.DisplaySafeAreaPadding;
|
||||
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;
|
||||
}
|
||||
|
||||
ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
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.
|
||||
ImGuiWindow* parent_window = window->ParentWindow;
|
||||
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_outer = GetWindowAllowedExtentRect(window);
|
||||
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_outer = GetWindowAllowedExtentRect(window);
|
||||
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_outer = GetWindowAllowedExtentRect(window);
|
||||
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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user