Created
June 9, 2021 21:34
-
-
Save an01f01/d2143cd6061f96c8ae128abb343a3668 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "mfc_multi_select_ctree_ctr.h" | |
BEGIN_MESSAGE_MAP(CTreeCtrlX, CTreeCtrl) | |
ON_WM_LBUTTONDOWN() | |
ON_WM_KEYDOWN() | |
END_MESSAGE_MAP() | |
void CTreeCtrlX::OnLButtonDown(UINT nFlags, CPoint point) | |
{ | |
// Set focus to control if key strokes are needed. | |
// Focus is not automatically given to control on lbuttondown | |
m_dwDragStart = GetTickCount(); | |
if(nFlags & MK_CONTROL ) | |
{ | |
// Control key is down | |
UINT flag; | |
HTREEITEM hItem = HitTest( point, &flag ); | |
if( hItem ) | |
{ | |
// Toggle selection state | |
UINT uNewSelState = | |
GetItemState(hItem, TVIS_SELECTED) & TVIS_SELECTED ? | |
0 : TVIS_SELECTED; | |
// Get old selected (focus) item and state | |
HTREEITEM hItemOld = GetSelectedItem(); | |
UINT uOldSelState = hItemOld ? | |
GetItemState(hItemOld, TVIS_SELECTED) : 0; | |
// Select new item | |
if( GetSelectedItem() == hItem ) | |
SelectItem( NULL ); // to prevent edit | |
CTreeCtrl::OnLButtonDown(nFlags, point); | |
// Set proper selection (highlight) state for new item | |
SetItemState(hItem, uNewSelState, TVIS_SELECTED); | |
// Restore state of old selected item | |
if (hItemOld && hItemOld != hItem) | |
SetItemState(hItemOld, uOldSelState, TVIS_SELECTED); | |
m_hItemFirstSel = NULL; | |
return; | |
} | |
} | |
else if(nFlags & MK_SHIFT) | |
{ | |
// Shift key is down | |
UINT flag; | |
HTREEITEM hItem = HitTest( point, &flag ); | |
// Initialize the reference item if this is the first shift selection | |
if( !m_hItemFirstSel ) | |
m_hItemFirstSel = GetSelectedItem(); | |
// Select new item | |
if( GetSelectedItem() == hItem ) | |
SelectItem( NULL ); // to prevent edit | |
CTreeCtrl::OnLButtonDown(nFlags, point); | |
if( m_hItemFirstSel ) | |
{ | |
SelectItems( m_hItemFirstSel, hItem ); | |
return; | |
} | |
} | |
else | |
{ | |
// Normal - remove all selection and let default | |
// handler do the rest | |
ClearSelection(); | |
m_hItemFirstSel = NULL; | |
} | |
CTreeCtrl::OnLButtonDown(nFlags, point); | |
} | |
void CTreeCtrlX::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) | |
{ | |
if ( (nChar==VK_UP || nChar==VK_DOWN) && GetKeyState( VK_SHIFT )&0x8000) | |
{ | |
// Initialize the reference item if this is the first shift selection | |
if( !m_hItemFirstSel ) | |
{ | |
m_hItemFirstSel = GetSelectedItem(); | |
ClearSelection(); | |
} | |
// Find which item is currently selected | |
HTREEITEM hItemPrevSel = GetSelectedItem(); | |
HTREEITEM hItemNext; | |
if ( nChar==VK_UP ) | |
hItemNext = GetPrevVisibleItem( hItemPrevSel ); | |
else | |
hItemNext = GetNextVisibleItem( hItemPrevSel ); | |
if ( hItemNext ) | |
{ | |
// Determine if we need to reselect previously selected item | |
BOOL bReselect = | |
!( GetItemState( hItemNext, TVIS_SELECTED ) & TVIS_SELECTED ); | |
// Select the next item - this will also deselect the previous item | |
SelectItem( hItemNext ); | |
// Reselect the previously selected item | |
if ( bReselect ) | |
SetItemState( hItemPrevSel, TVIS_SELECTED, TVIS_SELECTED ); | |
} | |
return; | |
} | |
else if( nChar >= VK_SPACE ) | |
{ | |
m_hItemFirstSel = NULL; | |
ClearSelection(); | |
} | |
CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags); | |
} | |
void CTreeCtrlX::ClearSelection() | |
{ | |
// This can be time consuming for very large trees | |
// and is called every time the user does a normal selection | |
// If performance is an issue, it may be better to maintain | |
// a list of selected items | |
for ( HTREEITEM hItem=GetRootItem(); hItem!=NULL; hItem=GetNextItem( hItem, TVGN_NEXT ) ) | |
if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) | |
SetItemState( hItem, 0, TVIS_SELECTED ); | |
} | |
// SelectItems - Selects items from hItemFrom to hItemTo. Does not | |
// - select child item if parent is collapsed. Removes | |
// - selection from all other items | |
// hItemFrom - item to start selecting from | |
// hItemTo - item to end selection at. | |
BOOL CTreeCtrlX::SelectItems(HTREEITEM hItemFrom, HTREEITEM hItemTo) | |
{ | |
HTREEITEM hItem = GetRootItem(); | |
// Clear selection upto the first item | |
while ( hItem && hItem!=hItemFrom && hItem!=hItemTo ) | |
{ | |
hItem = GetNextVisibleItem( hItem ); | |
SetItemState( hItem, 0, TVIS_SELECTED ); | |
} | |
if ( !hItem ) | |
return FALSE; // Item is not visible | |
SelectItem( hItemTo ); | |
// Rearrange hItemFrom and hItemTo so that hItemFirst is at top | |
if( hItem == hItemTo ) | |
{ | |
hItemTo = hItemFrom; | |
hItemFrom = hItem; | |
} | |
// Go through remaining visible items | |
BOOL bSelect = TRUE; | |
while ( hItem ) | |
{ | |
// Select or remove selection depending on whether item | |
// is still within the range. | |
SetItemState( hItem, bSelect ? TVIS_SELECTED : 0, TVIS_SELECTED ); | |
// Do we need to start removing items from selection | |
if( hItem == hItemTo ) | |
bSelect = FALSE; | |
hItem = GetNextVisibleItem( hItem ); | |
} | |
return TRUE; | |
} | |
HTREEITEM CTreeCtrlX::GetFirstSelectedItem() | |
{ | |
for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextItem( hItem, TVGN_NEXT ) ) | |
if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) | |
return hItem; | |
return NULL; | |
} | |
HTREEITEM CTreeCtrlX::GetNextSelectedItem( HTREEITEM hItem ) | |
{ | |
for ( hItem = GetNextItem( hItem, TVGN_NEXT ); hItem!=NULL; hItem = GetNextItem( hItem, TVGN_NEXT ) ) | |
if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) | |
return hItem; | |
return NULL; | |
} | |
HTREEITEM CTreeCtrlX::GetPrevSelectedItem( HTREEITEM hItem ) | |
{ | |
for ( hItem = GetNextItem( hItem, TVGN_PREVIOUS ); hItem!=NULL; hItem = GetNextItem( hItem, TVGN_PREVIOUS ) ) | |
if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) | |
return hItem; | |
return NULL; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment