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 ar
| 12694 | // information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. |
| 12695 | // this allows us to have tooltips/popups displayed out of the parent viewport.) |
| 12696 | ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) |
| 12697 | { |
| 12698 | ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); |
| 12699 | //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); |
| 12700 | //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); |
| 12701 | |
| 12702 | // Combo Box policy (we want a connecting edge) |
| 12703 | if (policy == ImGuiPopupPositionPolicy_ComboBox) |
| 12704 | { |
| 12705 | const ImGuiDir dir_preferred_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; |
| 12706 | for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) |
| 12707 | { |
| 12708 | const ImGuiDir dir = (n == -1) ? *last_dir : dir_preferred_order[n]; |
| 12709 | if (n != -1 && dir == *last_dir) // Already tried this direction? |
| 12710 | continue; |
| 12711 | ImVec2 pos; |
| 12712 | if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) |
| 12713 | if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right |
| 12714 | if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left |
| 12715 | if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left |
| 12716 | if (!r_outer.Contains(ImRect(pos, pos + size))) |
| 12717 | continue; |
| 12718 | *last_dir = dir; |
| 12719 | return pos; |
| 12720 | } |
| 12721 | } |
| 12722 | |
| 12723 | // Tooltip and Default popup policy |
| 12724 | // (Always first try the direction we used on the last frame, if any) |
| 12725 | if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) |
| 12726 | { |
| 12727 | const ImGuiDir dir_preferred_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; |
| 12728 | for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) |
| 12729 | { |
| 12730 | const ImGuiDir dir = (n == -1) ? *last_dir : dir_preferred_order[n]; |
| 12731 | if (n != -1 && dir == *last_dir) // Already tried this direction? |
| 12732 | continue; |
| 12733 | |
| 12734 | 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); |
| 12735 | 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); |
| 12736 | |
| 12737 | // If there's 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) |
| 12738 | if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) |
| 12739 | continue; |
| 12740 | if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) |
| 12741 | continue; |
| 12742 | |
| 12743 | ImVec2 pos; |
| 12744 | pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; |
| 12745 | pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; |
| 12746 | |
| 12747 | // Clamp top-left corner of popup |
| 12748 | pos.x = ImMax(pos.x, r_outer.Min.x); |
| 12749 | pos.y = ImMax(pos.y, r_outer.Min.y); |
| 12750 | |
| 12751 | *last_dir = dir; |
| 12752 | return pos; |
| 12753 | } |