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
| 10627 | // information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. |
| 10628 | // this allows us to have tooltips/popups displayed out of the parent viewport.) |
| 10629 | ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) |
| 10630 | { |
| 10631 | ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); |
| 10632 | //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); |
| 10633 | //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); |
| 10634 | |
| 10635 | // Combo Box policy (we want a connecting edge) |
| 10636 | if (policy == ImGuiPopupPositionPolicy_ComboBox) |
| 10637 | { |
| 10638 | const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; |
| 10639 | for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) |
| 10640 | { |
| 10641 | const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; |
| 10642 | if (n != -1 && dir == *last_dir) // Already tried this direction? |
| 10643 | continue; |
| 10644 | ImVec2 pos; |
| 10645 | if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) |
| 10646 | if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right |
| 10647 | if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left |
| 10648 | if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left |
| 10649 | if (!r_outer.Contains(ImRect(pos, pos + size))) |
| 10650 | continue; |
| 10651 | *last_dir = dir; |
| 10652 | return pos; |
| 10653 | } |
| 10654 | } |
| 10655 | |
| 10656 | // Tooltip and Default popup policy |
| 10657 | // (Always first try the direction we used on the last frame, if any) |
| 10658 | if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) |
| 10659 | { |
| 10660 | const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; |
| 10661 | for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) |
| 10662 | { |
| 10663 | const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; |
| 10664 | if (n != -1 && dir == *last_dir) // Already tried this direction? |
| 10665 | continue; |
| 10666 | |
| 10667 | 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); |
| 10668 | 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); |
| 10669 | |
| 10670 | // 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) |
| 10671 | if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) |
| 10672 | continue; |
| 10673 | if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) |
| 10674 | continue; |
| 10675 | |
| 10676 | ImVec2 pos; |
| 10677 | pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; |
| 10678 | pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; |
| 10679 | |
| 10680 | // Clamp top-left corner of popup |
| 10681 | pos.x = ImMax(pos.x, r_outer.Min.x); |
| 10682 | pos.y = ImMax(pos.y, r_outer.Min.y); |
| 10683 | |
| 10684 | *last_dir = dir; |
| 10685 | return pos; |
| 10686 | } |