@ -6996,12 +6996,15 @@ void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data)
//-------------------------------------------------------------------------
// [SECTION] Widgets: Box-Select support
// This has been extracted away from Multi-Select logic in the hope that it could eventually be used elsewhere, but hasn't been yet.
//-------------------------------------------------------------------------
// - BoxSelectStart() [Internal]
// - BoxSelectStartDrag () [Internal]
// - BoxSelectScrollWithMouseDrag() [Internal]
// - BeginBoxSelect() [Internal]
// - EndBoxSelect() [Internal]
//-------------------------------------------------------------------------
static void BoxSelectStart ( ImGuiID id , ImGuiSelectionUserData clicked_item )
static void BoxSelectStartDrag ( ImGuiID id , ImGuiSelectionUserData clicked_item )
{
ImGuiContext & g = * GImGui ;
ImGuiBoxSelectState * bs = & g . BoxSelectState ;
@ -7042,6 +7045,91 @@ static void BoxSelectScrollWithMouseDrag(ImGuiWindow* window, const ImRect& inne
}
}
bool ImGui : : BeginBoxSelect ( ImGuiWindow * window , ImGuiID box_select_id , ImGuiMultiSelectFlags ms_flags )
{
ImGuiContext & g = * GImGui ;
ImGuiBoxSelectState * bs = & g . BoxSelectState ;
KeepAliveID ( box_select_id ) ;
if ( bs - > ID ! = box_select_id )
return false ;
bs - > UnclipMode = false ;
bs - > RequestClear = false ;
// IsStarting is set by MultiSelectItemFooter() when considering a possible box-select. We validate it here and lock geometry.
if ( bs - > IsStarting & & IsMouseDragPastThreshold ( 0 ) )
{
bs - > IsActive = true ;
bs - > Window = window ;
bs - > IsStarting = false ;
SetActiveID ( bs - > ID , window ) ;
if ( bs - > IsStartedFromVoid & & ( bs - > KeyMods & ImGuiMod_Shift ) = = 0 )
bs - > RequestClear = true ;
}
else if ( ( bs - > IsStarting | | bs - > IsActive ) & & g . IO . MouseDown [ 0 ] = = false )
{
bs - > IsActive = bs - > IsStarting = false ;
if ( g . ActiveId = = bs - > ID )
ClearActiveID ( ) ;
bs - > ID = 0 ;
}
if ( ! bs - > IsActive )
return false ;
// Current frame absolute prev/current rectangles are used to toggle selection.
// They are derived from positions relative to scrolling space.
const ImRect scope_rect = window - > InnerClipRect ;
ImVec2 start_pos_abs = WindowPosRelToAbs ( window , bs - > StartPosRel ) ;
ImVec2 prev_end_pos_abs = WindowPosRelToAbs ( window , bs - > EndPosRel ) ; // Clamped already
ImVec2 curr_end_pos_abs = g . IO . MousePos ;
if ( ms_flags & ImGuiMultiSelectFlags_ScopeWindow ) // Box-select scrolling only happens with ScopeWindow
curr_end_pos_abs = ImClamp ( curr_end_pos_abs , scope_rect . Min , scope_rect . Max ) ;
bs - > BoxSelectRectPrev . Min = ImMin ( start_pos_abs , prev_end_pos_abs ) ;
bs - > BoxSelectRectPrev . Max = ImMax ( start_pos_abs , prev_end_pos_abs ) ;
bs - > BoxSelectRectCurr . Min = ImMin ( start_pos_abs , curr_end_pos_abs ) ;
bs - > BoxSelectRectCurr . Max = ImMax ( start_pos_abs , curr_end_pos_abs ) ;
// Box-select 2D mode detects horizontal changes (vertical ones are already picked by Clipper)
// Storing an extra rect used by widgets supporting box-select.
if ( ms_flags & ImGuiMultiSelectFlags_BoxSelect2d )
if ( bs - > BoxSelectRectPrev . Min . x ! = bs - > BoxSelectRectCurr . Min . x | | bs - > BoxSelectRectPrev . Max . x ! = bs - > BoxSelectRectCurr . Max . x )
{
bs - > UnclipRect = bs - > BoxSelectRectPrev ;
bs - > UnclipRect . Add ( bs - > BoxSelectRectCurr ) ;
bs - > UnclipMode = true ;
}
//GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f);
//GetForegroundDrawList()->AddRect(bs->BoxSelectRectPrev.Min, bs->BoxSelectRectPrev.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f);
//GetForegroundDrawList()->AddRect(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectCurr.Max, IM_COL32(0,255,0,200), 0.0f, 0, 1.0f);
return true ;
}
void ImGui : : EndBoxSelect ( const ImRect & scope_rect , bool enable_scroll )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
ImGuiBoxSelectState * bs = & g . BoxSelectState ;
IM_ASSERT ( bs - > IsActive ) ;
bs - > UnclipMode = false ;
// Render selection rectangle
bs - > EndPosRel = WindowPosAbsToRel ( window , ImClamp ( g . IO . MousePos , scope_rect . Min , scope_rect . Max ) ) ; // Clamp stored position according to current scrolling view
ImRect box_select_r = bs - > BoxSelectRectCurr ;
box_select_r . ClipWith ( scope_rect ) ;
window - > DrawList - > AddRectFilled ( box_select_r . Min , box_select_r . Max , GetColorU32 ( ImGuiCol_SeparatorHovered , 0.30f ) ) ; // FIXME-MULTISELECT: Styling
window - > DrawList - > AddRect ( box_select_r . Min , box_select_r . Max , GetColorU32 ( ImGuiCol_NavHighlight ) ) ; // FIXME-MULTISELECT: Styling
// Scroll
if ( enable_scroll )
{
ImRect scroll_r = scope_rect ;
scroll_r . Expand ( - g . FontSize ) ;
//GetForegroundDrawList()->AddRect(scroll_r.Min, scroll_r.Max, IM_COL32(0, 255, 0, 255));
if ( ! scroll_r . Contains ( g . IO . MousePos ) )
BoxSelectScrollWithMouseDrag ( window , scroll_r ) ;
}
}
//-------------------------------------------------------------------------
// [SECTION] Widgets: Multi-Select support
@ -7151,59 +7239,9 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
if ( flags & ImGuiMultiSelectFlags_BoxSelect )
{
ms - > BoxSelectId = GetID ( " ##BoxSelect " ) ;
KeepAliveID ( ms - > BoxSelectId ) ;
}
if ( ( flags & ImGuiMultiSelectFlags_BoxSelect ) & & ms - > BoxSelectId = = bs - > ID )
{
bs - > UnclipMode = false ;
// BoxSelectStarting is set by MultiSelectItemFooter() when considering a possible box-select. We validate it here and lock geometry.
if ( bs - > IsStarting & & IsMouseDragPastThreshold ( 0 ) )
{
bs - > IsActive = true ;
bs - > Window = ms - > Storage - > Window ;
bs - > IsStarting = false ;
SetActiveID ( ms - > BoxSelectId , window ) ;
if ( bs - > IsStartedFromVoid & & ( bs - > KeyMods & ImGuiMod_Shift ) = = 0 )
request_clear = true ;
}
else if ( ( bs - > IsStarting | | bs - > IsActive ) & & g . IO . MouseDown [ 0 ] = = false )
{
bs - > ID = 0 ;
bs - > IsActive = bs - > IsStarting = false ;
if ( g . ActiveId = = ms - > BoxSelectId )
ClearActiveID ( ) ;
}
if ( bs - > IsActive )
{
// Current frame absolute prev/current rectangles are used to toggle selection.
// They are derived from positions relative to scrolling space.
const ImRect scope_rect = window - > InnerClipRect ;
ImVec2 start_pos_abs = WindowPosRelToAbs ( window , bs - > StartPosRel ) ;
ImVec2 prev_end_pos_abs = WindowPosRelToAbs ( window , bs - > EndPosRel ) ; // Clamped already
ImVec2 curr_end_pos_abs = g . IO . MousePos ;
if ( ms - > Flags & ImGuiMultiSelectFlags_ScopeWindow ) // Box-select scrolling only happens with ScopeWindow
curr_end_pos_abs = ImClamp ( curr_end_pos_abs , scope_rect . Min , scope_rect . Max ) ;
bs - > LastSubmittedItem = ImGuiSelectionUserData_Invalid ;
bs - > BoxSelectRectPrev . Min = ImMin ( start_pos_abs , prev_end_pos_abs ) ;
bs - > BoxSelectRectPrev . Max = ImMax ( start_pos_abs , prev_end_pos_abs ) ;
bs - > BoxSelectRectCurr . Min = ImMin ( start_pos_abs , curr_end_pos_abs ) ;
bs - > BoxSelectRectCurr . Max = ImMax ( start_pos_abs , curr_end_pos_abs ) ;
// Box-select 2D mode detects horizontal changes (vertical ones are already picked by Clipper)
// Storing an extra rect used by widgets supporting box-select.
if ( flags & ImGuiMultiSelectFlags_BoxSelect2d )
if ( bs - > BoxSelectRectPrev . Min . x ! = bs - > BoxSelectRectCurr . Min . x | | bs - > BoxSelectRectPrev . Max . x ! = bs - > BoxSelectRectCurr . Max . x )
{
bs - > UnclipRect = bs - > BoxSelectRectPrev ;
bs - > UnclipRect . Add ( bs - > BoxSelectRectCurr ) ;
bs - > UnclipMode = true ;
}
//GetForegroundDrawList()->AddRect(ms->BoxSelectNoClipRect.Min, ms->BoxSelectNoClipRect.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f);
//GetForegroundDrawList()->AddRect(ms->BoxSelectRectPrev.Min, ms->BoxSelectRectPrev.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f);
//GetForegroundDrawList()->AddRect(ms->BoxSelectRectCurr.Min, ms->BoxSelectRectCurr.Max, IM_COL32(0,255,0,200), 0.0f, 0, 1.0f);
}
ms - > BoxSelectLastitem = ImGuiSelectionUserData_Invalid ;
if ( BeginBoxSelect ( window , ms - > BoxSelectId , flags ) )
request_clear | = bs - > RequestClear ;
}
if ( request_clear | | request_select_all )
@ -7247,24 +7285,10 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
storage - > NavIdSelected = - 1 ;
}
ImGuiBoxSelectState * bs = GetBoxSelectState ( ms - > BoxSelectId ) ;
if ( ( ms - > Flags & ImGuiMultiSelectFlags_BoxSelect ) & & bs ! = NULL )
if ( ( ms - > Flags & ImGuiMultiSelectFlags_BoxSelect ) & & GetBoxSelectState ( ms - > BoxSelectId ) )
{
// Box-select: render selection rectangle
bs - > EndPosRel = WindowPosAbsToRel ( window , ImClamp ( g . IO . MousePos , scope_rect . Min , scope_rect . Max ) ) ; // Clamp stored position according to current scrolling view
ImRect box_select_r = bs - > BoxSelectRectCurr ;
box_select_r . ClipWith ( scope_rect ) ;
window - > DrawList - > AddRectFilled ( box_select_r . Min , box_select_r . Max , GetColorU32 ( ImGuiCol_SeparatorHovered , 0.30f ) ) ; // FIXME-MULTISELECT: Styling
window - > DrawList - > AddRect ( box_select_r . Min , box_select_r . Max , GetColorU32 ( ImGuiCol_NavHighlight ) ) ; // FIXME-MULTISELECT: Styling
// Box-select: scroll
ImRect scroll_r = scope_rect ;
scroll_r . Expand ( - g . FontSize ) ;
//GetForegroundDrawList()->AddRect(scroll_r.Min, scroll_r.Max, IM_COL32(0, 255, 0, 255));
if ( ( ms - > Flags & ImGuiMultiSelectFlags_ScopeWindow ) & & ( ms - > Flags & ImGuiMultiSelectFlags_BoxSelectNoScroll ) = = 0 & & ! scroll_r . Contains ( g . IO . MousePos ) )
BoxSelectScrollWithMouseDrag ( window , scroll_r ) ;
bs - > UnclipMode = false ;
bool enable_scroll = ( ms - > Flags & ImGuiMultiSelectFlags_ScopeWindow ) & & ( ms - > Flags & ImGuiMultiSelectFlags_BoxSelectNoScroll ) = = 0 ;
EndBoxSelect ( scope_rect , enable_scroll ) ;
}
}
@ -7278,7 +7302,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
{
if ( ms - > Flags & ImGuiMultiSelectFlags_BoxSelect )
if ( ! g . BoxSelectState . IsActive & & ! g . BoxSelectState . IsStarting & & g . IO . MouseClickedCount [ 0 ] = = 1 )
BoxSelectStart ( ms - > BoxSelectId , ImGuiSelectionUserData_Invalid ) ;
BoxSelectStartDrag ( ms - > BoxSelectId , ImGuiSelectionUserData_Invalid ) ;
if ( ms - > Flags & ImGuiMultiSelectFlags_ClearOnClickVoid )
if ( IsMouseReleased ( 0 ) & & IsMouseDragPastThreshold ( 0 ) = = false & & g . IO . KeyMods = = ImGuiMod_None )
@ -7427,7 +7451,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
selected = pressed = true ;
}
// Box-select handling
// Box-select toggle handling
if ( ImGuiBoxSelectState * bs = GetBoxSelectState ( ms - > BoxSelectId ) )
{
const bool rect_overlap_curr = bs - > BoxSelectRectCurr . Overlaps ( g . LastItemData . Rect ) ;
@ -7437,12 +7461,12 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
selected = ! selected ;
ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange , selected , item_data , item_data } ;
ImGuiSelectionRequest * prev_req = ( ms - > IO . Requests . Size > 0 ) ? & ms - > IO . Requests . Data [ ms - > IO . Requests . Size - 1 ] : NULL ;
if ( prev_req & & prev_req - > Type = = ImGuiSelectionRequestType_SetRange & & prev_req - > RangeLastItem = = b s- > LastSubm ittedI tem & & prev_req - > RangeSelected = = selected )
if ( prev_req & & prev_req - > Type = = ImGuiSelectionRequestType_SetRange & & prev_req - > RangeLastItem = = m s- > BoxSelect Lastitem & & prev_req - > RangeSelected = = selected )
prev_req - > RangeLastItem = item_data ; // Merge span into same request
else
ms - > IO . Requests . push_back ( req ) ;
}
b s- > LastSubm ittedI tem = item_data ;
m s- > BoxSelect Lastitem = item_data ;
}
// Right-click handling: this could be moved at the Selectable() level.
@ -7471,7 +7495,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
ImGuiInputSource input_source = ( g . NavJustMovedToId = = id | | g . NavActivateId = = id ) ? g . NavInputSource : ImGuiInputSource_Mouse ;
if ( ms - > Flags & ImGuiMultiSelectFlags_BoxSelect )
if ( selected = = false & & ! g . BoxSelectState . IsActive & & ! g . BoxSelectState . IsStarting & & input_source = = ImGuiInputSource_Mouse & & g . IO . MouseClickedCount [ 0 ] = = 1 )
BoxSelectStart ( ms - > BoxSelectId , item_data ) ;
BoxSelectStartDrag ( ms - > BoxSelectId , item_data ) ;
//----------------------------------------------------------------------------------------
// ACTION | Begin | Pressed/Activated | End