@ -4167,112 +4167,6 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
IM_ASSERT ( p_backup = = window - > DC . StackSizesBackup + IM_ARRAYSIZE ( window - > DC . StackSizesBackup ) ) ;
}
ImRect ImGui : : GetWindowAllowedExtentRect ( ImGuiWindow * )
{
ImVec2 padding = GImGui - > Style . DisplaySafeAreaPadding ;
ImRect r_screen = GetViewportRect ( ) ;
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 ;
}
// 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.
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 ;
}
ImVec2 ImGui : : FindBestWindowPosForPopup ( ImGuiWindow * window )
{
ImGuiContext & g = * GImGui ;
ImRect r_outer = GetWindowAllowedExtentRect ( window ) ;
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.
IM_ASSERT ( g . CurrentWindow = = window ) ;
ImGuiWindow * parent_window = g . CurrentWindowStack [ g . CurrentWindowStack . Size - 2 ] ;
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_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_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_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 ) ;
@ -6766,6 +6660,112 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
return BeginPopupEx ( id , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings ) ;
}
ImRect ImGui : : GetWindowAllowedExtentRect ( ImGuiWindow * )
{
ImVec2 padding = GImGui - > Style . DisplaySafeAreaPadding ;
ImRect r_screen = GetViewportRect ( ) ;
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 ;
}
// 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.
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 ;
}
ImVec2 ImGui : : FindBestWindowPosForPopup ( ImGuiWindow * window )
{
ImGuiContext & g = * GImGui ;
ImRect r_outer = GetWindowAllowedExtentRect ( window ) ;
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.
IM_ASSERT ( g . CurrentWindow = = window ) ;
ImGuiWindow * parent_window = g . CurrentWindowStack [ g . CurrentWindowStack . Size - 2 ] ;
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_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_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_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
//-----------------------------------------------------------------------------