@ -1537,7 +1537,9 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// [SECTION] Widgets: ComboBox
// [SECTION] Widgets: ComboBox
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// - CalcMaxPopupHeightFromItemCount() [Internal]
// - BeginCombo()
// - BeginCombo()
// - BeginComboPopup() [Internal]
// - EndCombo()
// - EndCombo()
// - Combo()
// - Combo()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
@ -1552,78 +1554,91 @@ static float CalcMaxPopupHeightFromItemCount(int items_count)
bool ImGui : : BeginCombo ( const char * label , const char * preview_value , ImGuiComboFlags flags )
bool ImGui : : BeginCombo ( const char * label , const char * preview_value , ImGuiComboFlags flags )
{
{
// Always consume the SetNextWindowSizeConstraint() call in our early return paths
ImGuiContext & g = * GImGui ;
ImGuiContext & g = * GImGui ;
bool has_window_size_constraint = ( g . NextWindowData . Flags & ImGuiNextWindowDataFlags_HasSizeConstraint ) ! = 0 ;
g . NextWindowData . Flags & = ~ ImGuiNextWindowDataFlags_HasSizeConstraint ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
ImGuiNextWindowDataFlags backup_next_window_data_flags = g . NextWindowData . Flags ;
g . NextWindowData . ClearFlags ( ) ; // We behave like Begin() and need to consume those values
if ( window - > SkipItems )
if ( window - > SkipItems )
return false ;
return false ;
IM_ASSERT ( ( flags & ( ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview ) ) ! = ( ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview ) ) ; // Can't use both flags together
const ImGuiStyle & style = g . Style ;
const ImGuiStyle & style = g . Style ;
const ImGuiID id = window - > GetID ( label ) ;
const ImGuiID id = window - > GetID ( label ) ;
IM_ASSERT ( ( flags & ( ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview ) ) ! = ( ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview ) ) ; // Can't use both flags together
const float arrow_size = ( flags & ImGuiComboFlags_NoArrowButton ) ? 0.0f : GetFrameHeight ( ) ;
const float arrow_size = ( flags & ImGuiComboFlags_NoArrowButton ) ? 0.0f : GetFrameHeight ( ) ;
const ImVec2 label_size = CalcTextSize ( label , NULL , true ) ;
const ImVec2 label_size = CalcTextSize ( label , NULL , true ) ;
const float w = ( flags & ImGuiComboFlags_NoPreview ) ? arrow_size : CalcItemWidth ( ) ;
const float w = ( flags & ImGuiComboFlags_NoPreview ) ? arrow_size : CalcItemWidth ( ) ;
const ImRect frame_ bb( window - > DC . CursorPos , window - > DC . CursorPos + ImVec2 ( w , label_size . y + style . FramePadding . y * 2.0f ) ) ;
const ImRect bb( window - > DC . CursorPos , window - > DC . CursorPos + ImVec2 ( w , label_size . y + style . FramePadding . y * 2.0f ) ) ;
const ImRect total_bb ( frame_ bb. Min , frame_ bb. Max + ImVec2 ( label_size . x > 0.0f ? style . ItemInnerSpacing . x + label_size . x : 0.0f , 0.0f ) ) ;
const ImRect total_bb ( bb. Min , bb. Max + ImVec2 ( label_size . x > 0.0f ? style . ItemInnerSpacing . x + label_size . x : 0.0f , 0.0f ) ) ;
ItemSize ( total_bb , style . FramePadding . y ) ;
ItemSize ( total_bb , style . FramePadding . y ) ;
if ( ! ItemAdd ( total_bb , id , & frame_ bb) )
if ( ! ItemAdd ( total_bb , id , & bb) )
return false ;
return false ;
// Open on click
bool hovered , held ;
bool hovered , held ;
bool pressed = ButtonBehavior ( frame_bb , id , & hovered , & held ) ;
bool pressed = ButtonBehavior ( bb , id , & hovered , & held ) ;
const ImGuiID popup_id = ImHashStr ( " ##ComboPopup " , 0 , id ) ;
const ImGuiID popup_id = ImHashStr ( " ##ComboPopup " , 0 , id ) ;
bool popup_open = IsPopupOpen ( popup_id , ImGuiPopupFlags_None ) ;
bool popup_open = IsPopupOpen ( popup_id , ImGuiPopupFlags_None ) ;
if ( ( pressed | | g . NavActivateId = = id ) & & ! popup_open )
{
OpenPopupEx ( popup_id , ImGuiPopupFlags_None ) ;
popup_open = true ;
}
// Render shape
const ImU32 frame_col = GetColorU32 ( hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg ) ;
const ImU32 frame_col = GetColorU32 ( hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg ) ;
const float value_x2 = ImMax ( frame_bb . Min . x , frame_bb . Max . x - arrow_size ) ;
const float value_x2 = ImMax ( bb. Min . x , bb. Max . x - arrow_size ) ;
RenderNavHighlight ( frame_bb , id ) ;
RenderNavHighlight ( bb, id ) ;
if ( ! ( flags & ImGuiComboFlags_NoPreview ) )
if ( ! ( flags & ImGuiComboFlags_NoPreview ) )
window - > DrawList - > AddRectFilled ( frame_ bb. Min , ImVec2 ( value_x2 , frame_ bb. Max . y ) , frame_col , style . FrameRounding , ( flags & ImGuiComboFlags_NoArrowButton ) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft ) ;
window - > DrawList - > AddRectFilled ( bb. Min , ImVec2 ( value_x2 , bb. Max . y ) , frame_col , style . FrameRounding , ( flags & ImGuiComboFlags_NoArrowButton ) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft ) ;
if ( ! ( flags & ImGuiComboFlags_NoArrowButton ) )
if ( ! ( flags & ImGuiComboFlags_NoArrowButton ) )
{
{
ImU32 bg_col = GetColorU32 ( ( popup_open | | hovered ) ? ImGuiCol_ButtonHovered : ImGuiCol_Button ) ;
ImU32 bg_col = GetColorU32 ( ( popup_open | | hovered ) ? ImGuiCol_ButtonHovered : ImGuiCol_Button ) ;
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
window - > DrawList - > AddRectFilled ( ImVec2 ( value_x2 , frame_ bb. Min . y ) , frame_ bb. Max , bg_col , style . FrameRounding , ( w < = arrow_size ) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight ) ;
window - > DrawList - > AddRectFilled ( ImVec2 ( value_x2 , bb. Min . y ) , bb. Max , bg_col , style . FrameRounding , ( w < = arrow_size ) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight ) ;
if ( value_x2 + arrow_size - style . FramePadding . x < = frame_ bb. Max . x )
if ( value_x2 + arrow_size - style . FramePadding . x < = bb. Max . x )
RenderArrow ( window - > DrawList , ImVec2 ( value_x2 + style . FramePadding . y , frame_ bb. Min . y + style . FramePadding . y ) , text_col , ImGuiDir_Down , 1.0f ) ;
RenderArrow ( window - > DrawList , ImVec2 ( value_x2 + style . FramePadding . y , bb. Min . y + style . FramePadding . y ) , text_col , ImGuiDir_Down , 1.0f ) ;
}
}
RenderFrameBorder ( frame_bb . Min , frame_bb . Max , style . FrameRounding ) ;
RenderFrameBorder ( bb . Min , bb . Max , style . FrameRounding ) ;
// Render preview and label
if ( preview_value ! = NULL & & ! ( flags & ImGuiComboFlags_NoPreview ) )
if ( preview_value ! = NULL & & ! ( flags & ImGuiComboFlags_NoPreview ) )
{
{
ImVec2 preview_pos = frame_bb . Min + style . FramePadding ;
if ( g . LogEnabled )
if ( g . LogEnabled )
LogSetNextTextDecoration ( " { " , " } " ) ;
LogSetNextTextDecoration ( " { " , " } " ) ;
RenderTextClipped ( preview_pos , ImVec2 ( value_x2 , frame_ bb. Max . y ) , preview_value , NULL , NULL , ImVec2 ( 0.0f , 0.0f ) ) ;
RenderTextClipped ( bb. Min + style . FramePadding , ImVec2 ( value_x2 , bb. Max . y ) , preview_value , NULL , NULL ) ;
}
}
if ( label_size . x > 0 )
if ( label_size . x > 0 )
RenderText ( ImVec2 ( frame_bb . Max . x + style . ItemInnerSpacing . x , frame_bb . Min . y + style . FramePadding . y ) , label ) ;
RenderText ( ImVec2 ( bb . Max . x + style . ItemInnerSpacing . x , bb . Min . y + style . FramePadding . y ) , label ) ;
if ( ( pressed | | g . NavActivateId = = id ) & & ! popup_open )
{
OpenPopupEx ( popup_id , ImGuiPopupFlags_None ) ;
popup_open = true ;
}
if ( ! popup_open )
if ( ! popup_open )
return false ;
return false ;
if ( has_window_size_constraint )
g . NextWindowData . Flags = backup_next_window_data_flags ;
return BeginComboPopup ( popup_id , bb , flags ) ;
}
bool ImGui : : BeginComboPopup ( ImGuiID popup_id , const ImRect & bb , ImGuiComboFlags flags )
{
ImGuiContext & g = * GImGui ;
if ( ! IsPopupOpen ( popup_id , ImGuiPopupFlags_None ) )
{
g . NextWindowData . ClearFlags ( ) ;
return false ;
}
// Set popup size
float w = bb . GetWidth ( ) ;
if ( g . NextWindowData . Flags & ImGuiNextWindowDataFlags_HasSizeConstraint )
{
{
g . NextWindowData . Flags | = ImGuiNextWindowDataFlags_HasSizeConstraint ;
g . NextWindowData . SizeConstraintRect . Min . x = ImMax ( g . NextWindowData . SizeConstraintRect . Min . x , w ) ;
g . NextWindowData . SizeConstraintRect . Min . x = ImMax ( g . NextWindowData . SizeConstraintRect . Min . x , w ) ;
}
}
else
else
{
{
if ( ( flags & ImGuiComboFlags_HeightMask_ ) = = 0 )
if ( ( flags & ImGuiComboFlags_HeightMask_ ) = = 0 )
flags | = ImGuiComboFlags_HeightRegular ;
flags | = ImGuiComboFlags_HeightRegular ;
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiComboFlags_HeightMask_ ) ) ; // Only one
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiComboFlags_HeightMask_ ) ) ; // Only one
int popup_max_height_in_items = - 1 ;
int popup_max_height_in_items = - 1 ;
if ( flags & ImGuiComboFlags_HeightRegular ) popup_max_height_in_items = 8 ;
if ( flags & ImGuiComboFlags_HeightRegular ) popup_max_height_in_items = 8 ;
else if ( flags & ImGuiComboFlags_HeightSmall ) popup_max_height_in_items = 4 ;
else if ( flags & ImGuiComboFlags_HeightSmall ) popup_max_height_in_items = 4 ;
@ -1631,11 +1646,13 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
SetNextWindowSizeConstraints ( ImVec2 ( w , 0.0f ) , ImVec2 ( FLT_MAX , CalcMaxPopupHeightFromItemCount ( popup_max_height_in_items ) ) ) ;
SetNextWindowSizeConstraints ( ImVec2 ( w , 0.0f ) , ImVec2 ( FLT_MAX , CalcMaxPopupHeightFromItemCount ( popup_max_height_in_items ) ) ) ;
}
}
// This is essentially a specialized version of BeginPopupEx()
char name [ 16 ] ;
char name [ 16 ] ;
ImFormatString ( name , IM_ARRAYSIZE ( name ) , " ##Combo_%02d " , g . BeginPopupStack . Size ) ; // Recycle windows based on depth
ImFormatString ( name , IM_ARRAYSIZE ( name ) , " ##Combo_%02d " , g . BeginPopupStack . Size ) ; // Recycle windows based on depth
// Position the window given a custom constraint (peak into expected window size so we can position it)
// Set position given a custom constraint (peak into expected window size so we can position it)
// This might be easier to express with an hypothetical SetNextWindowPosConstraints() function.
// FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function?
// FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()?
if ( ImGuiWindow * popup_window = FindWindowByName ( name ) )
if ( ImGuiWindow * popup_window = FindWindowByName ( name ) )
if ( popup_window - > WasActive )
if ( popup_window - > WasActive )
{
{
@ -1643,15 +1660,13 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
ImVec2 size_expected = CalcWindowNextAutoFitSize ( popup_window ) ;
ImVec2 size_expected = CalcWindowNextAutoFitSize ( popup_window ) ;
popup_window - > AutoPosLastDirection = ( flags & ImGuiComboFlags_PopupAlignLeft ) ? ImGuiDir_Left : ImGuiDir_Down ; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)"
popup_window - > AutoPosLastDirection = ( flags & ImGuiComboFlags_PopupAlignLeft ) ? ImGuiDir_Left : ImGuiDir_Down ; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)"
ImRect r_outer = GetPopupAllowedExtentRect ( popup_window ) ;
ImRect r_outer = GetPopupAllowedExtentRect ( popup_window ) ;
ImVec2 pos = FindBestWindowPosForPopupEx ( frame_ bb. GetBL ( ) , size_expected , & popup_window - > AutoPosLastDirection , r_outer , frame_ bb, ImGuiPopupPositionPolicy_ComboBox ) ;
ImVec2 pos = FindBestWindowPosForPopupEx ( bb. GetBL ( ) , size_expected , & popup_window - > AutoPosLastDirection , r_outer , bb, ImGuiPopupPositionPolicy_ComboBox ) ;
SetNextWindowPos ( pos ) ;
SetNextWindowPos ( pos ) ;
}
}
// We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx()
// We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx()
ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove ;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove ;
PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 ( g . Style . FramePadding . x , g . Style . WindowPadding . y ) ) ; // Horizontally align ourselves with the framed text
// Horizontally align ourselves with the framed text
PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 ( style . FramePadding . x , style . WindowPadding . y ) ) ;
bool ret = Begin ( name , NULL , window_flags ) ;
bool ret = Begin ( name , NULL , window_flags ) ;
PopStyleVar ( ) ;
PopStyleVar ( ) ;
if ( ! ret )
if ( ! ret )