Click here to Skip to main content
15,896,111 members
Articles / Desktop Programming / MFC

Versatile Tree Control

Rate me:
Please Sign up or sign in to vote.
4.92/5 (16 votes)
18 Feb 2013CPOL12 min read 78.5K   5.9K   44  
Tree control with custom checkbox with several other features.
// CCustomTreeCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "CustomTreeCtrl.h"
#include "CCVersatileTreeCtrl.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include <algorithm>

enum ImagePosIndex
{
	//Image to represent an item with no check box and collapsed state
	IMAGE_NORMAL_INDEX = 0,

	//Image to represent an item with no check box and expanded state
	IMAGE_EXPAND_INDEX,

	//Image to represent an item in collapsed state with check box in checked state
	IMAGE_CHECKED_NORMAL_INDEX ,

	//Image to represent an item in collapsed state with check box in unchecked state
	IMAGE_UNCHECKED_NORMAL_INDEX ,

	//Image to represent an item in expanded state with check box in checked state
	IMAGE_CHECKED_EXPANDED_INDEX ,

	//Image to represent an item in expanded state with check box in unchecked state
	IMAGE_UNCHECKED_EXPANDED_INDEX,

	//Image to represet an item in collapsed and disabled state
	IMAGE_DISABLED_STATE

};


//###########################################################################
//								GLOBAL FUNCTIONS
//###########################################################################

//This function is used to export the given bitmap to a file specified by path.
//Internally used to verify the bimap scaling, prefixing a bitmap with another bitmap etc
BOOL SaveBitmap(HDC hDC,HBITMAP hBitmap,CString szPath)
{
    FILE * fp= NULL;
    fp = fopen(szPath.GetBuffer(1),"wb");
    if(fp == NULL)
        return false;
    
    BITMAP Bm;
    BITMAPINFO BitInfo;
    ZeroMemory(&BitInfo, sizeof(BITMAPINFO));
    BitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    BitInfo.bmiHeader.biBitCount = 0;

    if(!::GetDIBits(hDC, hBitmap, 0, 0, NULL, &BitInfo, DIB_RGB_COLORS))
        return (false);

    Bm.bmHeight = BitInfo.bmiHeader.biHeight;
    Bm.bmWidth  = BitInfo.bmiHeader.biWidth;

    BITMAPFILEHEADER    BmHdr;
    
    BmHdr.bfType        = 0x4d42;   // 'BM' WINDOWS_BITMAP_SIGNATURE
    BmHdr.bfSize        = (((3 * Bm.bmWidth + 3) & ~3) * Bm.bmHeight) 
                          + sizeof(BITMAPFILEHEADER) 
                          + sizeof(BITMAPINFOHEADER);
    BmHdr.bfReserved1    = BmHdr.bfReserved2 = 0;
    BmHdr.bfOffBits      = (DWORD) sizeof(BITMAPFILEHEADER) 
                          + sizeof(BITMAPINFOHEADER);
    
    BitInfo.bmiHeader.biCompression = 0;
    // Writing Bitmap File Header ////
    fwrite(&BmHdr,sizeof(BITMAPFILEHEADER),1,fp);

    fwrite(&BitInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);

    BYTE *pData = new BYTE[BitInfo.bmiHeader.biSizeImage + 5];
    if(!::GetDIBits(hDC, hBitmap, 0, Bm.bmHeight, 
                 pData, &BitInfo, DIB_RGB_COLORS))
        return (false);
    if(pData != NULL)
        fwrite(pData,1,BitInfo.bmiHeader.biSizeImage,fp);

    fclose(fp);
    delete (pData);
    return (true);
}

//***************************************************************************
//This is a callback function called for each item when the items are iterated
// from a given start item to end item.
int FindItemsInRect( LOOPINFO* pLoopInfo )
{
	if( !pLoopInfo->hItem )
		return -1;

	if( !pLoopInfo->pParent )
		return -1;

	CVersatileTreeCtrl* pCustomTree = pLoopInfo->pTree;

	//Get the rectangle which is passed as the user parameter
	CRect* rc = (CRect*)(pLoopInfo->m_param1);
	
	//Get the rect of the item
	CRect itemRect;
	pCustomTree->GetItemRect( pLoopInfo->hItem ,&itemRect,false);

	CString str = pCustomTree->GetItemText( pLoopInfo->hItem );
	pCustomTree->ClientToScreen( &itemRect );

	CRect resRect;

	bool bFound = false;
	if( itemRect.top >= rc->top &&  itemRect.bottom <= rc->bottom )
	{
		bFound = true;
	}
	if( bFound )
	{
		pCustomTree->m_aItemsInRect.Add( pLoopInfo->hItem  );	
	}
	return 0;
}


//***************************************************************************
//This is a call back function to called for each item when the items are iterated
// from a given start item to end item.Based on the pLoopInfo's param the item may
// be selected or deselected
int SelectItems( LOOPINFO* pLoopInfo )
{
	//Do the validity check on the item and parent
	if( !pLoopInfo->hItem )
		return -1;

	if( !pLoopInfo->pParent )
		return -1;

	//Get the tree control from the looping info
	CVersatileTreeCtrl* pCustomTree = pLoopInfo->pTree;

	//Just to check the items's label
	CString str;
	str = pCustomTree->GetItemText(pLoopInfo->hItem);

	//Get the flag which gives the selection state that user wants to set
	bool bFlag = false;
	if( pLoopInfo->m_param1 )
		bFlag = * ( (bool*)(pLoopInfo->m_param1) );
	
	//Set the item state of hItem as deselected
	if( bFlag )
	{
		pCustomTree->SetItemState( pLoopInfo->hItem,TVIS_SELECTED,TVIS_SELECTED );
	}
	else
	{
		pCustomTree->SetItemState( pLoopInfo->hItem,~TVIS_SELECTED,TVIS_SELECTED );
	}
	return 0;

}

//***************************************************************************
//This is a call back function to called for each item when the items are iterated
// from a given start item to end item.For each item custom draw is carried out by
//considering the state of the item [highlighted,selected],color of the item,bold/normal etc
int	DrawItem( LOOPINFO* pLoopInfo )
{
	//Do the validity check on the item and parent
	if( !pLoopInfo->hItem )
		return -1;

	//Get the tree control from the looping info
	CVersatileTreeCtrl* pCustomTree = pLoopInfo->pTree;

	//Get the label rectangle area of the item
	CRect labelRect;
	pCustomTree->GetItemRect( pLoopInfo->hItem,&labelRect,true );

	//GetItemRect works only for expanded items.So if it is not shown/collpased then the
	//rect will carry junk value
	if( labelRect.left < 0 || labelRect.right < 0 || labelRect.top < 0 || labelRect.bottom < 0 )
		return -1;
	
	//Set the black color as default
	COLORREF cItemColor = RGB(0,0,0 );

	//Set the font weight as normal
	bool bItemBold = false;

	//Get the all the attributes of the item like text color, bold etc from the custom data associated with the item
	PCUSTOMITEMDATA pCustomData  = (PCUSTOMITEMDATA) pCustomTree->GetItemData( pLoopInfo->hItem );
	if( pCustomData )
	{
		//If the item is in enabled state, the get the user specified color while inserting the item
		if( pCustomData->m_bEnable )
		{
			cItemColor = pCustomData->m_cItemColor;
		}
		//Set the color as gray
		else
		{
			cItemColor	=	::GetSysColor(COLOR_GRAYTEXT);
		}
		bItemBold  = pCustomData->m_bIsBold;
	}

	//Create client dc to draw
	CClientDC pDC( pCustomTree );

	//Set the text color to the item text color
	pDC.SetTextColor( cItemColor );

	//Check Whether the item is highlighted or selected
	UINT selflag				= TVIS_DROPHILITED | TVIS_SELECTED;
	UINT uItemSelState	  = pCustomTree->GetItemState(pLoopInfo->hItem,selflag);

	//Get the font of the tree control and use the same
	CFont* pFont = pCustomTree->GetFont();
	LOGFONT lf;
	pFont->GetLogFont(&lf );

	//If the item is set to BOLD then change the font weight to bold
	if( bItemBold )
	{
		lf.lfWeight = FW_BOLD;
	}

	//Create a new font with font data obtained from tree and set to DC
	CFont newFont;
	newFont.CreateFontIndirect( &lf );
	pDC.SelectObject(&newFont );

	//Get the text of the item to be drawn
	CString sItem = pCustomTree->GetItemText( pLoopInfo->hItem );

	//Check if the box has the check box or not
	if( !pCustomData->m_bChecked )
	{
		//Offset the labelrect to half of the image size to the left side.This is done because
		//if the item doesnt have checkbox means first we are copying the image bitmap and after
		//that empty bitmap [ as there is no check box ] is copied.so we will have a white space between
		//the image and the label which is equal to half of the image size.
		int imgW,imgH;
		ImageList_GetIconSize( pCustomTree->GetImageList(TVSIL_NORMAL)->GetSafeHandle(),&imgW,&imgH);
		labelRect.left = labelRect.left - (imgW/2);
	}


	//Delete the text drawn by the system by drawing a rectangle with the color of the 
	//tree control's background color and we are going to draw the label again
	CRect bkRect = labelRect;

	//Add some padding to completely cover the text which is drawn by default by the tree
	bkRect.right = bkRect.right +  bkRect.Width()/3;
	COLORREF bkColor = pCustomTree->GetBkColor();
	CBrush bkbrush( bkColor );
	CGdiObject* pOldBrush = pDC.SelectObject(&bkbrush);
	
	CPen bkPen( PS_SOLID,1,bkColor);
	CPen* pOldpen = pDC.SelectObject(&bkPen);

	pDC.Rectangle( labelRect );
	pDC.SelectObject(pOldBrush);
	pDC.SelectObject(pOldpen);


	if( uItemSelState & selflag )
	{
		//If so draw the highlighting rectangle.But already a highlighting rectangle is drawn
		//when CTreeCtrl::OnPaint() is being called.After that we are drawing the text for each
		//item.So the text is drawn over the highlighting rect.So we have to draw a new highlighting
		//rect.Inflate the rect by 1 or 2 pixlel so that it completely hides the highlighting
		//rectangle drawn by the system

			//If the item is selected, as the background goes to the COLOR_HIGHLIGHT the text
			//should be in COLOR_HIGHLIGHTTEXT to have clear visibility.
			pDC.SetTextColor( ::GetSysColor(COLOR_HIGHLIGHTTEXT) );

		
					
			//Get the extents [Width,Height] of the label of the item in pixels
			CSize sz = pDC.GetTextExtent(sItem);
				
			//Convert the ordinates of the label rectangle into screen coordinates
			pCustomTree->ClientToScreen( &labelRect );

			//Compute the bounding rectangle
			CRect rc;
			rc.left = labelRect.left;
			rc.top  = labelRect.top;

			//To give some cushioning i'm just adding quarter of its width
			rc.right = rc.left + labelRect.Width()  + labelRect.Width()/4;
			rc.bottom = rc.top + labelRect.Height() ;

			//Create a pen of highlight color to draw the border of the highlighting rectangle
			CPen highlightPen;
			highlightPen.CreatePen(PS_SOLID,1,::GetSysColor( COLOR_HIGHLIGHT ) );
			pDC.SelectObject( &highlightPen);
			
			//Create brush with highlighting color to draw the highlight rectangle
			CBrush highlightBrush( ::GetSysColor( COLOR_HIGHLIGHT ) );

			//If the tree has the focus then draw the background inthe highlight color
			if( GetFocus( ) == pCustomTree->GetSafeHwnd() )
			{
				//Select the brush with highlighting color
				 pOldBrush = pDC.SelectObject( &highlightBrush);
			}
			else
			{
				//Set the text color to the item text color
				pDC.SetTextColor( cItemColor );			
			}				 
		
			//We computed the rc using the cooridinates of the labelRect which is in screen 
			//coordinates.Convert  back to client coordinates.Draw the highlighting rectangle
			pCustomTree->ScreenToClient( &rc );
			pDC.Rectangle(rc);

			//Similarly conver the labelRect to client cooridnates
			pCustomTree->ScreenToClient( &labelRect );

			//Set the background mode to transparent so that highlighting rectangle
			//is not overwritten by bounding rectangle of the text while doing TextOut
			pDC.SetBkMode(TRANSPARENT);

			bool bIgnoreDrawText = false;
			if( pCustomTree->GetEditControl( ) )
			{
					bIgnoreDrawText = true;
			}

	
			//Draw the text
			if( !bIgnoreDrawText )
			{
				CString s = "****";
				s += sItem;
				//OutputDebugString(  s.GetBuffer() );
				//OutputDebugString("\n");
					labelRect.right +=labelRect.Width()/4;
				pDC.DrawText( sItem,labelRect,DT_SINGLELINE | DT_LEFT | DT_VCENTER);
			}
			//Restore the old objects
			pDC.SelectObject( &pOldpen);
			pDC.SelectObject( &pOldBrush);

	}
	else
	{
		labelRect.right +=labelRect.Width()/4;
		CString s = "+++";
		s += sItem;
		//OutputDebugString(  s.GetBuffer() );
		//OutputDebugString("\n");
		pDC.DrawText( sItem,labelRect,DT_SINGLELINE | DT_LEFT | DT_VCENTER);		
	}
	
	return 0;
}

//***************************************************************************
//DESCRIPTION:
//			This is a call back function to called for each item when the items are
//			iterated from a given start item to end item.Expand/Collapse the items
//			recursively

int ExpandItem( LOOPINFO* pLoopInfo )
{
	//Do the validity check on the item and parent
	if( !pLoopInfo->hItem )
		return -1;

	//Get the tree control from the looping info
	CVersatileTreeCtrl* pCustomTree = pLoopInfo->pTree;

	//Get the flag which gives the expand state that user wants to set
	bool bExpand = false;
	if( pLoopInfo->m_param1 )
		bExpand = * ( (bool*)(pLoopInfo->m_param1) );

	if( bExpand )
		pCustomTree->Expand(pLoopInfo->hItem,TVE_EXPAND ) ;
	else
		pCustomTree->Expand(pLoopInfo->hItem,TVE_COLLAPSE ) ;
	
	return 0;
}
//***************************************************************************
//DESCRIPTION:
//			This is a call back function to called for each item when the items are
//			iterated from a given start item to end item.Check the items data with
//			the user given data.If matches stop iterating and return
int SearchItemData( LOOPINFO* pLoopInfo )
{

	//Do the validity check on the item and parent
	if( !pLoopInfo->hItem )
		return -1;

	//Get the tree control from the looping info
	CVersatileTreeCtrl* pCustomTree = pLoopInfo->pTree;

	//Get the data to be searched
	void* pUserData = pLoopInfo->m_param1;

	//Get the item data
	void* pItemData = (void*)pCustomTree->GetItemData(pLoopInfo->hItem);

	//Item found
	if( pItemData == pUserData )
	{
		if( pLoopInfo->m_pResult )
		{
			HTREEITEM* hResItem    =  (HTREEITEM*)pLoopInfo->m_pResult;
			*hResItem = pLoopInfo->hItem;
			return 1;
		}
	}
	return 0;
}



//###########################################################################
//								CVersatileTreeCtrl
//###########################################################################

/////////////////////////////////////////////////////////////////////////////
// CVersatileTreeCtrl

CVersatileTreeCtrl::CVersatileTreeCtrl()
{
	m_hDragSourceItem = NULL;
	m_hDragTargetItem = NULL;
	m_pDragImageList  = NULL;
		
	m_defaultCursor = ::LoadCursor(NULL,IDC_ARROW);
	m_noCursor = ::LoadCursor(NULL,IDC_NO);
	m_bIsBandingON = false;
	m_bIsDragging = false;
	m_pImgList = NULL;
	m_hRClickItem = NULL;
	m_bMoveItem = true;
	m_cMaskColor = RGB(0,128,128);
	m_bContinueScan = true;
}

CVersatileTreeCtrl::~CVersatileTreeCtrl()
{
	if( m_pImgList )
	{
		m_pImgList->DeleteImageList();
		delete m_pImgList;
	}

	if( m_pDragImageList )
	{
		m_pDragImageList->DeleteImageList();
		delete m_pDragImageList;
	}
}


BEGIN_MESSAGE_MAP(CVersatileTreeCtrl, CTreeCtrl)
	//{{AFX_MSG_MAP(CVersatileTreeCtrl)
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndlabeledit)
	ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnBeginlabeledit)
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)
	ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
	ON_WM_LBUTTONUP()
	ON_NOTIFY_REFLECT(NM_CLICK, OnClickLButton)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	ON_NOTIFY_REFLECT(TVN_SELCHANGING, OnSelchanging)
	ON_NOTIFY_REFLECT(TVN_KEYDOWN, OnKeydown)
	ON_MESSAGE(TVN_STATEICON_CLICKED, OnChkBoxClicked )	
	ON_WM_PAINT()			
	//ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVersatileTreeCtrl message handlers



/***************************************************************************
/DESCRIPTION:
/-----------
/		To set the background color for the tree control
/
/PARAM
/------
/		bkColor[IN]	-	New background color to be set
/
/RESULT:
/-------
/		old background color of the control
*/
void CVersatileTreeCtrl::SetBackgroundColor( COLORREF bkColor )
{
	//SetBkColor function can also be used
	//	SetBkColor( bkColor );

	//TVM_SETBKCOLOR can also be used by passing the color as the lparam
	//	SendMessage( TVM_SETBKCOLOR,0, (LPARAM)bkColor );

	TreeView_SetBkColor( GetSafeHwnd(),bkColor );    
	
}

/***************************************************************************
/DESCRIPTION:
/-----------
/		To set the bold font for the label
/
/PARAM
/------
/		hItem[in]	-	Item to which the font to be set as bold
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::SetBoldFont(HTREEITEM hItem )
{
	if( !hItem )
		return;
	//SetItemState( hItem,TVIS_BOLD,TVIS_BOLD );
	Expand(hItem,TVE_EXPAND);
	 
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		To set the color for the item text
/
/PARAM
/------
/		hItem[in]	-	Item to which the color to be set
/		col[in]		-	New color of the item
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::SetItemColor( HTREEITEM hItem,	COLORREF col )
{
	if( !hItem )
		return;

	//Get the item data
	PCUSTOMITEMDATA pCustomData  = (PCUSTOMITEMDATA) GetItemData( hItem );
	if( pCustomData )
		pCustomData->m_cItemColor = col;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To set checkbox for a given item
/
/PARAM
/------
/		hItem[in]	-	Item to be set
/		col[in]		-	TRUE to set the checkbox,false to remove
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::SetCheckBox( HTREEITEM hItem,bool bCheck  )
{
	if( !hItem )
		return;
	
	//Get the item data
	PCUSTOMITEMDATA pCustomData  = (PCUSTOMITEMDATA) GetItemData( hItem );

	//If it already has the checkbox dont do it
	if( bCheck )
	{	
		if( pCustomData->m_bChecked )
			return;
		pCustomData->m_bChecked		= bCheck;
		pCustomData->m_bCheckState	= true;
	}
	else if ( !bCheck )
	{
		if( !pCustomData->m_bChecked )
			return;
		pCustomData->m_bChecked		= bCheck;
	}

	if( bCheck )
	{
		//Add the checkbox image 
		//Check the state of the item expanded/collapsed
		bool bItemExpanded = false;
		if( GetItemState( hItem,TVIS_EXPANDED) & TVIS_EXPANDED) 
			bItemExpanded = true;

		UINT ChkBmpID		= IDB_BITMAP_CHECK_16; 
		UINT unChkBmpID		= IDB_BITMAP_UNCHECK;
		UINT uBmpID		= pCustomData->m_uNormalImage;
		UINT uExpBmpID  = pCustomData->m_uExpandedImage;

		AddCheckStateImages( uBmpID,ChkBmpID,unChkBmpID,pCustomData );
		AddExpStateImages( uBmpID,uExpBmpID,ChkBmpID,unChkBmpID,pCustomData );			
	}
	SetImage( hItem );
	GetParent()->SendMessage( TVN_ITEM_CHECK_TOGGLE,(WPARAM)(&m_vecCheckedItems),NULL ); 


}
/****************************************************************************
/DESCRIPTION:
/-----------
/			To check/uncheck a checkboxed item
/
/PARAM
/------
/		hItem[in]	-	Item to be set
/		bCheck[in]	-	TRUE to set the checkbox,false to remove
/
/RESULT:
/-------
/		void
*/
void	CVersatileTreeCtrl::SetCheck( HTREEITEM hItem,bool bCheck )
{
	//Check for item
	if( !hItem )
		return;

	//Get the item data
	PCUSTOMITEMDATA pCustomData  = (PCUSTOMITEMDATA) GetItemData( hItem );

	//Check the item is a checkboxed one
	if( !pCustomData->m_bChecked )
		return;

	//Check the state of the check box is same as of bCheck
	if( pCustomData->m_bCheckState == bCheck )
		return;

	//Set the appropriate the image 
	if( bCheck )
	{
		//Add to the list of checked items
		m_vecCheckedItems.insert( hItem );	
	}
	else
	{
		//Remove from the list of checked items
		m_vecCheckedItems.erase(hItem);

	}

	//Set the image for the item based on its state
	SetImage( hItem );

	//Notify the dialog about the checked item
	GetParent()->SendMessage( TVN_ITEM_CHECK_TOGGLE,(WPARAM)hItem,(LPARAM)bCheck ); 
}

/***************************************************************************
/DESCRIPTION:
/-----------
/			To enable/disable the item
/
/PARAM
/------
/		hItem[in]		-	Item to be enabled/disabled
/		bEnable[in]		-	True for enable,false for disable
/
/RESULT:
/-------
/		void
*/
void	CVersatileTreeCtrl::EnableItem( HTREEITEM hItem,bool	bEnable	)
{
	if( !hItem )
		return;
	
	//Get the item data
	PCUSTOMITEMDATA pCustomData  = (PCUSTOMITEMDATA) GetItemData( hItem );
	
	//Already the item is enabled. Dont proceed further
	if( pCustomData->m_bEnable == bEnable )
		return;

	//Store the enable/disable state
	pCustomData->m_bEnable = bEnable;

	//Item to disabled.If the disable image is not there generate it
	if( !bEnable )
	{
		//Store the expand state of the item before collapsing
		pCustomData->m_bExpStateBefDisable =(  GetItemState( hItem, TVIS_EXPANDED ) & TVIS_EXPANDED );

		//Before disabling the item, collpase it
		Expand( hItem,TVE_COLLAPSE );
		
		//Disabled image is not being generated yet.
		if( pCustomData->m_iDisableIndex == -1 )
		{
			//I THOUGHT OF USING GetImageInfo by passing the image index and using the
			//HBITMAP INFO AVAILABLE IN THE IMAGEINFO.BUT SOMEHOW IT DOESNT WORK

			//Check whether the disabled image for the normal image of the item
			//is generated already or not
			map<UINT, vector<int> >::iterator it = m_mapBitmapID.find(pCustomData->m_uNormalImage);
			if( it != m_mapBitmapID.end( ) && it->second.size() == 7)
			{
				//Already there is a disabled image corresponding to pCustomData->m_uNormalImage
				pCustomData->m_iDisableIndex = it->second.at(IMAGE_DISABLED_STATE);		
			}
			else
			{
				//Get the index of the normal image of the item from the imagelist
				int normalImgIndex,selImageIndex;
				GetItemImage(hItem,normalImgIndex,selImageIndex);

				//Get the bitmap of the item
				CBitmap disableBmp;
				bool res = GetBitampFromImageList( normalImgIndex,disableBmp );

				//Generate the disabled image
				GenerateDisableImage( disableBmp);

				//Add it to the image list
				int index = m_pImgList->Add( &disableBmp,m_cMaskColor );

				//Add the index to the disabled index array
				int iBmpFound = -1;
				iBmpFound = GetBitmapIndexFromImgList( pCustomData->m_uNormalImage );
				pCustomData->m_iDisableIndex = index;		
				it->second.push_back( index );
			}
		}		
	}
	//Restore the normal position of the item
	else
	{
		//Before disabling, if the item was in expanded state, restore it back
		if( pCustomData->m_bExpStateBefDisable )
		{
			Expand(hItem,TVE_EXPAND);
		}				
	}

	//Set the image for the item based on its state
	SetImage( hItem );

}

/***************************************************************************
/DESCRIPTION:
/-----------
/		To expand the given item [ All the items under the given items are expanded]
/
/PARAM
/------
/		hItem[in]	-	Item to be expanded
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::ExpandTree(HTREEITEM hItem,bool bExpand /*= true*/ )
{
	IterateItems( ExpandItem,hItem,NULL,&bExpand );

}
/***************************************************************************
/DESCRIPTION:
/-----------
/		Called when the user starts its label editing
/
/PARAM
/------
/		pNMHDR[in]		-	Contains the data about the item edited
/		pResult[in/out]	-	Result of the edition
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
	// TODO: Add your control notification handler code here

	
	//Get the custom data and check whether item is editbale 
	HTREEITEM hItem = pTVDispInfo->item.hItem;

	if( hItem )
	{
		//Get the custom data from the item
		PCUSTOMITEMDATA pCustomData  = (PCUSTOMITEMDATA) GetItemData( hItem );

		if( pCustomData )
		{
			//If the item is not editable or disabled dont allow the renaming
			if( !pCustomData->m_bEditable || !pCustomData->m_bEnable )
			{
	   		  *pResult = 1;
				return;
			} 
		}
	}
	Invalidate( );
	
	*pResult = 0;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		Called when the user completes its label editing
/
/PARAM
/------
/		pNMHDR[in]		-	Contains the data about the item edited
/		pResult[in/out]	-	Result of the edition
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
	// TODO: Add your control notification handler code here

	//Set the new text received from dispinfo structure to the item
	if( pTVDispInfo->item.pszText != NULL)
	{
		SetItemText( pTVDispInfo->item.hItem,pTVDispInfo->item.pszText);
		m_vecSelectedItems.clear( );
		m_vecSelectedItems.push_back( pTVDispInfo->item.hItem );
		GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 
	}

	*pResult = 0;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To insert a item in the tree using the custom data
/
/PARAM
/------
/		lpInsertStruct[in]		-	Custom data of item to be inserted
/
/RESULT:
/-------
/		void
*/
HTREEITEM CVersatileTreeCtrl::InsertItem(PCUSTOMINSERTSTRUCT lpInsertStruct )
{
	//Add the image to the imagelist
	//------------------------------
	int res = AddImageToList( lpInsertStruct );	

	//Insert the item
	HTREEITEM hItem = CTreeCtrl::InsertItem( &lpInsertStruct->m_tvIS );

	//Set the custom data as the item data
	SetItemData( hItem,(DWORD)(lpInsertStruct->m_pCustomData));

	bool flag = ItemHasChildren(lpInsertStruct->m_tvIS.hParent);

	if( lpInsertStruct->m_pCustomData->m_bChecked )
	{
		if( lpInsertStruct->m_pCustomData->m_bCheckState )
		{
			m_vecCheckedItems.insert( hItem );
		}

		GetParent()->SendMessage( TVN_ITEM_CHECK_TOGGLE,(WPARAM)(&m_vecCheckedItems),NULL ); 
	}

	SetImage(hItem);
	return hItem;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		Called when the item is expanding
/
/PARAM
/------
/		pNMHDR[in]		-	Contains the data about the item edited
/		pResult[in/out]	-	Result of the edition
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here

	//If the click is on the checkbox then dont allow expand/collpase
	if( !m_bAllowExpand )
	{
		*pResult = 1;

		CUSTNMHDR chdr;
		chdr.m_hdr.hwndFrom	=  m_hWnd;
		chdr.m_hdr.idFrom		=  ::GetDlgCtrlID(m_hWnd);
		chdr.m_hdr.code			=  TVN_STATEICON_CLICKED;
		chdr.m_hItem					=  pNMTreeView->itemNew.hItem;
		chdr.m_data 					=  (PCUSTOMITEMDATA) GetItemData(pNMTreeView->itemNew.hItem);
		SendMessage(TVN_STATEICON_CLICKED, (WPARAM)&chdr, (LPARAM)chdr.m_hdr.idFrom );			
		return;
	}

	//Get the item data
	PCUSTOMITEMDATA pData = (PCUSTOMITEMDATA) GetItemData(pNMTreeView->itemNew.hItem);

	//Similarly if the item is disabled dont allow expand
	if( !pData->m_bEnable && pNMTreeView->action == TVE_EXPAND)
	{
		*pResult = 1;
		return;
	}

	bool bItemExpanded = false;
	if( pNMTreeView->action == TVE_EXPAND )
		bItemExpanded = true;


	//Set image based on expand/collpase state
	SetExpandImage( pNMTreeView->itemNew.hItem,bItemExpanded );
	*pResult = 0;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		Called when the item is dragged
/
/PARAM
/------
/		pNMHDR[in]		-	Contains the data about the item edited
/		pResult[in/out]	-	Result of the edition
/
/RESULT:
/-------
/		void
*/


void CVersatileTreeCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;

	//Get the item being clicked for dragging
	LPNMTREEVIEW  lpnmTreeView = (LPNMTREEVIEW )pNMHDR;

	//Check the clicked point lies in one of the selected item.
	//1. If so, drag all the selected items
	//2. Drag only the item where left mouse button is clicked
	CollectSelectedItems();

	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	//Clear the dragged items vector
	m_vecDraggedItems.clear( );

	//If the item being dragged in one of the selected items, then user intention
	//is to drag all the selected items
	int iSelItemCtr = 0;
	bool bDragSelectedItems = false;
	for( ; iSelItemCtr < m_vecSelectedItems.size( ); iSelItemCtr++ )
	{
		RECT rc;
		GetItemRect( m_vecSelectedItems[iSelItemCtr],&rc,FALSE );
		CRect crc;
		crc.left = rc.left; crc.bottom=rc.bottom;crc.top=rc.top; crc.right=rc.right;
		if( crc.PtInRect( pNMTreeView->ptDrag ) )
		{
			bDragSelectedItems = true;
			m_vecDraggedItems =  m_vecSelectedItems;
			break;
		}	
	}	
	//If not, the user is willing drag the item he is clicked
	if( !bDragSelectedItems )
	{
		m_vecDraggedItems.push_back( pNMTreeView->itemNew.hItem );
	}
	

	//Find out the node to be dragged
	//-------------------------------
		CPoint pt;
		pt = pNMTreeView->ptDrag;

		//Find out the item to dragged using hit test
		m_hDragSourceItem =pNMTreeView->itemNew.hItem;
		m_hDragTargetItem = NULL;

		//Mark that dragging  in progress
		m_bIsDragging = true;

		//If already the drag image list exists then delete it
		if( m_pDragImageList )
		{
			m_pDragImageList->DeleteImageList();
			delete m_pDragImageList;
		}
		
		//Create the drag image for the selected items which are to be dragged
		m_pDragImageList = GetImageListForDrag( m_vecDraggedItems );

		if( m_pDragImageList )
		{
			//Start dragging the image
			m_pDragImageList->BeginDrag( 0,CPoint(0,0));
			
			//Lock updates to the window specified by first parameter (this)
			//and displays the drag image at the position specified by pt.
			m_pDragImageList->DragEnter( this,pt );
			
			 //Capture the mouse
			SetCapture();
						
		}
		else
			m_bIsDragging = true;


	*pResult = 0;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		To copy an item to another item
/
/PARAM
/------
/		hSourceItem[in]		-	Item to be copied
/		hTargetItem[in]			-	Target where the source to be copied
/		bMoveSibling[in]		-	Whether the sibling has to be moved or not.When this function
												called for first time from some other function this is false.
												Where as when it calls itself recursively this will be true.
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::CopyItem(HTREEITEM hSourceItem,HTREEITEM hTargetItem,bool bMoveSibling /*=false*/)
{
	if( !hSourceItem || !hTargetItem )
		return;

	if( hSourceItem == hTargetItem )
		return;

		//Get the info about the child item
		TVITEM tvItem;
		tvItem.mask = TVIF_IMAGE | TVIF_STATE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT |  TVIF_HANDLE;

		char buf[128];
		tvItem.pszText = buf;
		tvItem.cchTextMax = 128;
		tvItem.hItem = hSourceItem;
	
		GetItem(&tvItem);

		CUSTOMINSERTSTRUCT tvIS;
		tvIS.m_tvIS.hParent			=	hTargetItem;
		tvIS.m_tvIS.hInsertAfter	=	TVI_LAST; 
		tvIS.m_tvIS.item					 =	tvItem;

		//Get the item data of the hSourceItem
		PCUSTOMITEMDATA pData = (PCUSTOMITEMDATA) GetItemData(hSourceItem);
		tvIS.m_pCustomData    = pData;

		CString str1 = GetItemText( hSourceItem );
		CString str2 = GetItemText( hTargetItem );
		
		HTREEITEM hInsertedItem     =	InsertItem(&tvIS);

		if( GetItemState( hSourceItem,TVIS_SELECTED ) & TVIS_SELECTED )
		{
			SetItemState( hInsertedItem,TVIS_SELECTED,TVIS_SELECTED );

			//Add the inserted item to the m_vecSelectedItems as well
			m_vecSelectedItems.push_back(hInsertedItem);
		}

		//This is quite important.Say When source item becomes the parent to the target item
		//the copy will be called recursively.Comment this line and try to drag a item onto its
		//one of the child item.
		if( hSourceItem == m_hOrigTgt )
			return;

		HTREEITEM hChildItem, hSiblingItem ;
		hChildItem = GetChildItem(hSourceItem);
		while( hChildItem )
		{
			//Get the sibling of the given child item
			hSiblingItem = GetNextSiblingItem( hChildItem );

			str1 = GetItemText( hChildItem );
			str2 = GetItemText( hSiblingItem );

			CopyItem( hChildItem, hInsertedItem );
			hChildItem = hSiblingItem;
				
		} 

}
/***************************************************************************
/DESCRIPTION:
/-----------
/		To delete an items and all its children recursively and remove the item to 
/		be deleted from the vector holding the selected items and the vector holding
//	the checked items
/
/PARAM
/------
/		hTreeItem[in]	-	Item to be deleted
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::DeleteItem( HTREEITEM hTreeItem )
{
	if( !hTreeItem )
		return;

	//If it is there in selected items array then remove it
	int iSelItemCnt = 0;
	for( ; iSelItemCnt < m_vecSelectedItems.size(); iSelItemCnt++ )
	{
		if( m_vecSelectedItems[iSelItemCnt] == hTreeItem )
		{
			m_vecSelectedItems.erase( m_vecSelectedItems.begin( ) + iSelItemCnt );

			//Inform the dialog
			GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 
		}
	}

	//Similarly from the checked items array
	set<HTREEITEM>::iterator it = m_vecCheckedItems.find( hTreeItem );
	if( it != m_vecCheckedItems.end( ) )
	{
		m_vecCheckedItems.erase( it );

		//Inform the dialog
		GetParent()->SendMessage( TVN_ITEM_CHECK_TOGGLE,(WPARAM)(&m_vecCheckedItems),NULL ); 
	}
	CTreeCtrl::DeleteItem( hTreeItem );
}


//***************************************************************************
void CVersatileTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	TV_HITTESTINFO tvHitInfo;
	tvHitInfo.pt = point;
	HTREEITEM hClickedItem = HitTest(&tvHitInfo );
	
	m_bAllowExpand = true;

	//Handling the click on the check box. 
	//If the click is ON the item icon find out whethere it is ON the check box
	//or on the image
	if(  hClickedItem )
	{
		PCUSTOMITEMDATA pCustData = (PCUSTOMITEMDATA) GetItemData(hClickedItem);

		if( pCustData && pCustData->m_bChecked && pCustData->m_bEnable )
		{			
			if( tvHitInfo.flags & TVHT_ONITEMICON )
			{
				CPoint pt = point;

				//Convert the point from client to screen coordinate
				ClientToScreen(&pt );

				//Get the full rect area
				CRect fullRect;
				GetItemRect( hClickedItem,&fullRect,FALSE );

				//Convert the rect into screen ordinates
				ClientToScreen( &fullRect );

				//Get the rect area of the label
				CRect labelRect;
				GetItemRect( hClickedItem,&labelRect,TRUE );

				//Convert the rect into screen ordinates
				ClientToScreen( &labelRect );

				//Get the rect of the image
				CRect imgRect;
				imgRect.left   = fullRect.left;
				imgRect.top    = fullRect.top;
				imgRect.right  = imgRect.left + ( labelRect.left - fullRect.left );
				imgRect.bottom = fullRect.bottom;

				//ImgRect contains both the check box image and image of the button
				//We want to know whether the check box is clicked or not. So get
				//the left half of the ImgRect which is nothing but the check box rect.
				int imgW,imgH;
				ImageList_GetIconSize( m_pImgList->GetSafeHandle(),&imgW,&imgH);
				imgRect.right -= imgW/2;

				//Now check the click point is there in this rect. If so the click is on the
				//check box of the item
				if( imgRect.PtInRect( pt ) )
				{
					m_bAllowExpand = false;
					CUSTNMHDR chdr;
					chdr.m_hdr.hwndFrom	=  m_hWnd;
					chdr.m_hdr.idFrom		=  ::GetDlgCtrlID(m_hWnd);
					chdr.m_hdr.code			=  TVN_STATEICON_CLICKED;
					chdr.m_hItem					=  hClickedItem;
					chdr.m_data 					=  (PCUSTOMITEMDATA) GetItemData(hClickedItem);
					SendMessage(TVN_STATEICON_CLICKED, (WPARAM)&chdr, (LPARAM)chdr.m_hdr.idFrom );														
					return;					
				}
			}		
		}
	}


	//If the click is not on the item and not on the item button means enable the
	//banding
	if( !(tvHitInfo.flags & TVHT_ONITEM) && !(tvHitInfo.flags & TVHT_ONITEMBUTTON) )
	{
		if( GetEditControl( ) )
		{
			CTreeCtrl::OnLButtonDown(nFlags, point);
			return;
		}

		//if there is no selected item then ON the banding
		m_bIsBandingON = true;

		//Store the starting point
		m_startPt = m_endPt = point;

		//Remove the selection
		int i = 0;
		for( ; i < m_vecSelectedItems.size(); i++ )
		{
			HTREEITEM hItem	=	m_vecSelectedItems[i];
			SetItemState( m_vecSelectedItems[i],~TVIS_SELECTED,TVIS_SELECTED );
		}

		//This is important.If you dont select the NULL item, the GetSelectedItem will
		//always return the previous selected item.For example,select item1.Click the mouse
		//button somewhere on the tree and not on any of the tree item. So in previous loop
		//we have removed the selection flag of item1 [ highlighting of the items goes].
		//Now again click on item1.But the tree gives the item1 as selected [eventhough it is
		//not highlighted ]item1 and because of this we are not able to select item1.So make
		//forcefully that no item is selected by calling SelectItem(NULL ).Now it works.Great!!!!
		SelectItem( NULL );
			
		//Send the notification to the parent dialog about the selected items.
		//Collect the selected items. May be parent may seek this data.
		CollectSelectedItems();
		GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 
		SetCapture();
		return;		
	}

	
	//Capture the mouse
	SetCapture();
	Invalidate();
	CTreeCtrl::OnLButtonDown(nFlags, point);

}
//***************************************************************************
void CVersatileTreeCtrl::ShowItemInfo(HTREEITEM hItem )
{
	if( !hItem )
		return;
	CString str = GetItemText( hItem );

	TVITEM infoItem;
	infoItem.hItem = hItem;
	infoItem.mask = TVIF_TEXT ;

	char label[128];
	infoItem.pszText = label;
	infoItem.cchTextMax = 128;
	GetItem( &infoItem );
	MessageBox( infoItem.pszText);
}
//***************************************************************************
void CVersatileTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	//If dragging is enabled then drag image
	if( m_bIsDragging )
	{
		m_hDragTargetItem = NULL;

		if( m_pDragImageList )
		{
			// Move the drag image to the next position 
			m_pDragImageList->DragMove(point);
			
			//DragShowNolock:Shows or hides the drag image during a drag operation,
			//without locking the window.
			//As the window is locked during the BeginDrag,if you dont unlock
			//using DragShowNoLock(), the previosly highlighted target wont be
			//refreshed.So it will remain in highlighted state.
			m_pDragImageList->DragShowNolock(false );

			//Based on the mouse position keep updating the target node for the drop operation
			UINT flags;
			m_hDragTargetItem = HitTest( point,&flags );

			//If the target is not a valid one for dropping the show the nocursor
			PCUSTOMITEMDATA pTargetData = NULL;

			::SetCursor( m_defaultCursor);

			if( m_hDragTargetItem )
			{
				pTargetData = (PCUSTOMITEMDATA) GetItemData(m_hDragTargetItem);
			
				//if both source and target are same,show invalid cursor
				if( m_hDragSourceItem == m_hDragTargetItem )
				{
					::SetCursor( m_noCursor );								
				}

				if( !pTargetData->m_bDropTarget )
					::SetCursor( m_noCursor );								
			}
		
								
			if( m_hDragTargetItem )
			{
				//Highlight the target item
				SelectDropTarget( m_hDragTargetItem );

				//Expand the target item if it is not in the disbaled state
				if( pTargetData )
					if( pTargetData->m_bEnable )
						Expand( m_hDragTargetItem,TVE_EXPAND);

				//Again lock the window
				m_pDragImageList->DragShowNolock(true );				
			
			}
			
		}
	}
	else if( m_bIsBandingON )
	{
		CClientDC dc(this);
		InvertRectangle( &dc,m_startPt,m_endPt );
		InvertRectangle( &dc,m_startPt,point );
		m_endPt = point;
	}

	CTreeCtrl::OnMouseMove(nFlags, point);
}
//***************************************************************************
void CVersatileTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if( m_bIsDragging )
	{
		//Unlock the window
		m_pDragImageList->DragLeave(this);

		//End the drag operation
		m_pDragImageList->EndDrag();

		//Get the data associated with the drop target		
		PCUSTOMITEMDATA pTargetData = NULL;
		if(m_hDragTargetItem )
		{
			if( m_hDragTargetItem )
				pTargetData = (PCUSTOMITEMDATA) GetItemData(m_hDragTargetItem);
		}

		//Check whether the target is a valid one for drop operation
		if( pTargetData && pTargetData->m_bDropTarget )
		{
				
				//Drop the selected items one by one over the target item
				int iSelItemCnt = 0;

				//Target should not be in the dragged item collection
				if( std::find(m_vecDraggedItems.begin( ),m_vecDraggedItems.end( ), m_hDragTargetItem ) == m_vecDraggedItems.end( ) )
				{
						//Take a copy of selected items in a temp array and manipulate it.Because
						//when an item is deleted OnSelChanged is called which inturn collects the
						//list of selected items in m_vecSelectedItems.So it is being overwritten and
						//causes chaos.			
						for( ; iSelItemCnt < m_vecDraggedItems.size(); iSelItemCnt++ )
						{
							//Dont allow to drop the root item.IF the parent is NULL then
							//its a root item
							HTREEITEM hDragParentItem = GetParentItem( m_vecDraggedItems[iSelItemCnt] );
							if( !hDragParentItem )
							{
								//If the parent item of this item is already being deleted, we wont process further
								//But it has to be removed from the 	m_vecDraggedItems and m_vecSelectedItems
								vector<HTREEITEM>::iterator itSel = std::find( m_vecSelectedItems.begin( ), m_vecSelectedItems.end( ), m_vecDraggedItems[iSelItemCnt]  );
								if( itSel != m_vecSelectedItems.end( ) )
								{
									m_vecSelectedItems.erase( itSel );
								}
								set<HTREEITEM>::iterator itDrag = std::find( m_vecCheckedItems.begin( ), m_vecCheckedItems.end( ), m_vecDraggedItems[iSelItemCnt] );
								if( itDrag != m_vecCheckedItems.end( ) )
								{
									m_vecCheckedItems.erase( itDrag );
								}
								continue;
							}

							//If the target is the child of the dragged item, then dont allow
							if( GetParentItem(m_hDragTargetItem) == m_vecDraggedItems[iSelItemCnt]  )
								continue;

							//If target and source both are same then dont allow
							if( m_vecDraggedItems[iSelItemCnt] == m_hDragTargetItem )
								continue;

							PCUSTOMITEMDATA pSourceData = NULL;
							if( m_vecDraggedItems[iSelItemCnt] )
							pSourceData = (PCUSTOMITEMDATA) GetItemData(m_vecDraggedItems[iSelItemCnt]);

						
							//Check the hierarchy of the source and target matches
							if( pSourceData && pTargetData)
							{						
									//If the parent of the source is same as the target 
									//item then dont allow.Because already the source is in the target
									HTREEITEM hSourceParent = GetParentItem( m_vecDraggedItems[iSelItemCnt] );

									if( hSourceParent != m_hDragTargetItem )
									{
										//delete the drage image list
										if( m_pDragImageList )
										{
											m_pDragImageList->DeleteImageList();
											delete m_pDragImageList;
											m_pDragImageList = NULL;
										}
										
										m_hOrigTgt = m_hDragTargetItem;
										CopyItem( m_vecDraggedItems[iSelItemCnt],m_hDragTargetItem);
										m_hOrigTgt = NULL;

										//It the item has to be moved then delete the source item after
										//copyiing into target
										if( m_bMoveItem )
										{
											//Remove the item from the selection array
											HTREEITEM hItem = m_vecDraggedItems.at( iSelItemCnt );
											m_vecDraggedItems.erase( m_vecDraggedItems.begin( ) + iSelItemCnt);

											DeleteItem( hItem );
											iSelItemCnt--;
										}
										UpdateWindow();													
									}
								}
							}
							GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 	
							}		
			}		
	}

	//if the banding is ON then remove the banding flag and rectangle drawn
	if( m_bIsBandingON )
	{
		m_bIsBandingON = false;
		CClientDC dc(this);
		InvertRectangle( &dc,m_startPt,m_endPt );

		if( m_startPt != m_endPt )
		{
				CRect rect;
			if( m_startPt.y < m_endPt.y )
			{
				rect.left = m_startPt.x;
				rect.top  = m_startPt.y;
				rect.right = m_endPt.x;
				rect.bottom = m_endPt.y;
				
			}
			else
			{
				rect.left = m_endPt.x;
				rect.top  = m_endPt.y;
				rect.right = m_startPt.x;
				rect.bottom = m_startPt.y;				

			}
			//Find the items inside the rectangle
			ItemsInRect( rect );
		}	

	}
	
	if( m_pDragImageList )
			m_pDragImageList->DragShowNolock(FALSE );

	m_bIsDragging = false;					
	SelectDropTarget(NULL);

	//Release the mouse
	ReleaseCapture();
	ShowCursor( true );
	CTreeCtrl::OnLButtonUp(nFlags, point);

}


/***************************************************************************
/DESCRIPTION:
/-----------
/		To iterate all the items and call the callback function for each item
/
/PARAM
/------
/		func[in]	-	Call back function to be called on each item
/		hStart[in]	-	Start node for the iteration
/		hEnd[in]	-	End node to stop the iteration
/		pInfo[in]	-	User parameter
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::IterateItems( ScanCallBackFunc func,
							HTREEITEM hIterStart /*= NULL*/,
							HTREEITEM hIterEnd, /*= NULL*/
							void* pInfo /*=NULL*/
							)
{
	//If there is no start then take the root item
	HTREEITEM hStart =	GetRootItem(); 
	if( !hIterStart )
		hIterStart = hStart;

	m_bContinueScan = true;
	m_bStartFound = false;
	ScanItems( func,hStart,hIterStart,hIterEnd,pInfo );
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		To iterate all the items and call the callback function for each item
/
/PARAM
/------
/		func[in]		-	Call back function to be called on each item
/		hStart[in]		-	Start node of the tree
/		hIterStart[in]	-	Start node for the iteration
/		hIterEnd[in]	-	End node to stop the iteration
/		pInfo[in]		-	User parameter
/
/RESULT:
/-------
/		void
*/
void CVersatileTreeCtrl::ScanItems( ScanCallBackFunc func,
							HTREEITEM hStart,
							HTREEITEM hIterStart /*= NULL*/,
							HTREEITEM hIterEnd, /*= NULL*/
							void* pInfo /*= NULL*/
							)
{
	
	//Loop from start till the end is reached
	while( hStart && m_bContinueScan  )
	{
		//Check whether we have reached the start.Till you reach the start dont 
		//call the CB Function for the intermediate items
		if( hStart == hIterStart )
			m_bStartFound = true;

	
		LOOPINFO lInfo;
		lInfo.pTree =  this;
		lInfo.hItem = hStart;
		lInfo.pParent = GetParent();
		lInfo.m_param1   = pInfo;
		
		CString str = GetItemText( hStart );

		CRect rc;
		GetItemRect( hStart,&rc,true );

		//Callback is called for the current item
		int bRes = 0;
		if( m_bStartFound )
		{
			bRes = func( &lInfo );
		}

		if( bRes == 1 )
		{
			m_bContinueScan = false;
			return;
		}

		//Check whether we have reached iterating upto the end node.If reached
		//then dont call the CB function.
		if( hStart == hIterEnd )
			m_bStartFound = false;

		//Get the childern of the current item and call recursively
		HTREEITEM hChild = NULL;
		if( ItemHasChildren( hStart ) )
		{
			hChild = GetChildItem( hStart );
			ScanItems( func,hChild,hIterStart,hIterEnd,pInfo);
		}

		HTREEITEM hNext;
		hNext = GetNextSiblingItem( hStart );
		hStart = hNext;
	}

}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To invert the rectangle being drawn
/
/PARAM
/------
/		pDC[in]		-	Device context used for drawing
/		startPt[in]	-	Start point of the rectangle
/		endPt[in]	-	End point of the rectangle
/RESULT:
/-------
/		void
*/
void	CVersatileTreeCtrl::InvertRectangle( CDC* pDC,CPoint startPt,CPoint endPt )	
{
	//CBrush brush;
	//brush.CreateSolidBrush (RGB (49, 106, 197));
	//CBrush* pOldBrush = pDC->SelectObject(&brush );
	CGdiObject* pOldBrush = pDC->SelectStockObject(NULL_BRUSH );

	//CPen pen (PS_SOLID, 1, RGB (49, 106, 197));
	CPen pen (PS_DOT, 1, RGB (49, 106, 197));
	CPen* pOldPen = pDC->SelectObject (&pen);


	int nOldMode = pDC->SetROP2( R2_NOTXORPEN );
	pDC->Rectangle( startPt.x,startPt.y,endPt.x,endPt.y);
	pDC->SetROP2(nOldMode);

	pDC->SelectObject(pOldBrush );
	pDC->SelectObject (pOldPen);
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To find the items inside the given rectangle
/
/PARAM
/------
/		rect[in]		-	Bounding rectangle area
/RESULT:
/-------
/		void
*/
bool	CVersatileTreeCtrl::ItemsInRect(CRect rect)
{
	
	//First deselect all the items
	bool bFlag = false;
	IterateItems( SelectItems,NULL,NULL,&bFlag );
	UpdateWindow();

	ClientToScreen(&rect);
	m_aItemsInRect.RemoveAll();
	IterateItems( FindItemsInRect,NULL,NULL,&rect );

	int i = 0;
	for( ; i < m_aItemsInRect.GetSize(); i++ )
	{
		SetItemState( m_aItemsInRect[i],TVIS_SELECTED,TVIS_SELECTED);
	}
	//Send the notification to the parent dialog about the selected items
	CollectSelectedItems();
	GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 

	return true;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To get the first selected item in the tree
/
/PARAM
/------
/		void
/RESULT:
/-------
/		First selected item if any,otherwise NULL
*/

HTREEITEM CVersatileTreeCtrl::GetFirstSelectedItem() const 
{
	for(HTREEITEM hItem = GetRootItem(); hItem; hItem = GetNextVisibleItem(hItem))
		if(GetItemState(hItem, UINT(TVIS_SELECTED)) & TVIS_SELECTED)
			return hItem;
	return 0;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To get the next selected item in the tree
/
/PARAM
/------
/		void
/RESULT:
/-------
/		Selected item if any,otherwise NULL
*/

HTREEITEM CVersatileTreeCtrl::GetNextSelectedItem(HTREEITEM hItem) const 
{
	if( !hItem )
		return 0;

	for( hItem = GetNextVisibleItem(hItem); hItem; hItem = GetNextVisibleItem(hItem))
	{
		if(GetItemState(hItem, UINT(TVIS_SELECTED)) & TVIS_SELECTED)
			return hItem;
	}
	return 0;
}

/***************************************************************************
/DESCRIPTION:
/-----------
/			To Collect the selected items in an array
/
/PARAM
/------
/		void
/RESULT:
/-------
/		void
*/
void	CVersatileTreeCtrl::CollectSelectedItems()
{
	m_vecSelectedItems.clear();
	for(HTREEITEM hItem = GetFirstSelectedItem(); hItem != 0; hItem = GetNextSelectedItem(hItem)) 
	{
		m_vecSelectedItems.push_back(hItem);		
	}

}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To generate the imagelist for the dragging. If multiple items are being dragged
/			we have to pile up all the image of the selected items as single drag image
/
/PARAM
/------
/		void
/RESULT:
/-------
/		Create imagelist if any,otherwise NULL
*/
CImageList* CVersatileTreeCtrl::GetImageListForDrag(vector<HTREEITEM>& cArrDragItems )
{
	//If there is no selected item for the drag return NULL
	CImageList* pNewImageList = NULL;

	if( cArrDragItems.size() == 0 )
		return NULL;

	//Get the imagelist of the tree
	CImageList* pTreeImgList = GetImageList(TVSIL_NORMAL );

	CClientDC dc(this);
	CDC		  cMemDC;
	CBitmap   cBitmap;


	int ImgWidth,ImgHeight;

	//Loop through all the selected items and get the size of the bitmap to be created
	int iDragItemCount = 0;
	CRect rc;
	for( ; iDragItemCount <  cArrDragItems.size(); iDragItemCount++ )
	{
		HTREEITEM hSelItem = cArrDragItems[iDragItemCount];
		CRect itemRect;
		GetItemRect( hSelItem ,&itemRect,false);

		CImageList* pImgList = GetImageList( TVSIL_NORMAL );
		ImageList_GetIconSize( pImgList->GetSafeHandle(),&ImgWidth,&ImgHeight );

		if( iDragItemCount == 0 )
		{
			rc.left = 0;
			rc.top  = 0;
			rc.right = ImgWidth + itemRect.Width();
			rc.bottom = ImgHeight;
		}
		else
		{
			if( rc.Width() < (itemRect.Width()+ImgWidth) )	
			{
					rc.right = itemRect.Width()+32;
			}
			rc.bottom += itemRect.Height();
		}

	}

	//Create the memory dc
	if(!cMemDC.CreateCompatibleDC(&dc))
		return NULL;

	//Create the bitmap of the required size
	if(!cBitmap.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height()))
		return NULL;

	CBitmap* pOldMemDCBitmap = cMemDC.SelectObject( &cBitmap );

	//Fill the bitmap with green color which is used as the mask
	cMemDC.FillSolidRect(0,0,rc.Width(), rc.Height(), RGB(0, 255, 0));

	CFont * pFontOld = cMemDC.SelectObject(GetFont());

	//Loop through all the selected items and get their image
	iDragItemCount = 0;
	CImageList* pSelImageList = NULL;
	CImageList * pImageList = GetImageList(TVSIL_NORMAL);

	CRect imgRect,textRect,itemRect;

	for( ; iDragItemCount <  cArrDragItems.size(); iDragItemCount++ )
	{
		HTREEITEM hSelItem = cArrDragItems[iDragItemCount];
		PCUSTOMITEMDATA pData = (PCUSTOMITEMDATA) GetItemData(hSelItem);

		CString str;
		str = GetItemText( hSelItem );

		//if( iDragItemCount == 0 )
			GetItemRect( hSelItem,&itemRect,true ); 

		if( iDragItemCount == 0 )
		{
			imgRect.left = 0;
			imgRect.top  = 0;
			imgRect.right = ImgWidth;
			imgRect.bottom = ImgHeight;

			//If the item has check box 
			if( pData->m_bChecked )
			{
				textRect.left = ImgWidth;				
			}
			else
			{
				//Left shift the textRect by half the width of the imageRect width as 
				//there is an empty space between the image of the item and the text
				textRect.left = ImgWidth/2;		
			}
			textRect.top  = 0;
			textRect.right = textRect.left  + itemRect.Width();
			textRect.bottom = itemRect.Height();
		}
		else
		{
			imgRect.top += ImgHeight;
			imgRect.bottom += ImgHeight;

			//If the item has check box 
			if( pData->m_bChecked )
			{
				textRect.left = ImgWidth;				
			}
			else
			{
				//Left shift the textRect by half the width of the imageRect width as 
				//there is an empty space between the image of the item and the text
				textRect.left = ImgWidth/2;		
			}
			textRect.top  = textRect.bottom;
			textRect.right = textRect.left + itemRect.Width();
			textRect.bottom = textRect.top + itemRect.Height();

		}
	
		if( hSelItem )
		{
			//Get the image of the selected item
			int nImg, nSelImg;
			GetItemImage(hSelItem,nImg,nSelImg);
			HICON hIcon = pImageList->ExtractIcon(nImg);
			
			//Draw this icon on to the memory dc
			::DrawIconEx(cMemDC.m_hDC, imgRect.left, imgRect.top, hIcon, ImgWidth, ImgHeight, 0, 0, DI_NORMAL);
		
			//Next draw the text
			cMemDC.DrawText(str, textRect, DT_LEFT| DT_VCENTER | DT_SINGLELINE|DT_NOPREFIX);
			DestroyIcon(hIcon);
							
		}
	}

	cMemDC.SelectObject( pOldMemDCBitmap );

	pNewImageList = new CImageList;
	BITMAP bm;
	cBitmap.GetBitmap(&bm);

	CBitmap bmp;
	pNewImageList->Create( bm.bmWidth,bm.bmHeight,ILC_COLOR32 | ILC_MASK,1,1);

	// Here green is used as mask color
	pNewImageList->Add(&cBitmap, RGB(0, 255, 0));

	return pNewImageList;
}
///***************************************************************************
void CVersatileTreeCtrl::OnClickLButton(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;

	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

//TODO: Add your control notification handler code here
	
	//Do the hittest to find out which item is being clicked
		CPoint pt;
		//Get the current position of the cursor
		::GetCursorPos(& pt );

		//Cursor position is in screen coordiantes.Convert it to the client
		//Systen
		ScreenToClient(&pt );

		HTREEITEM hClickItem = HitTest(pt);

		if( !hClickItem )
			return;

	//Get the control and shift key states
		bool bCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
		bool bShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
		
		HTREEITEM hSelItem = GetSelectedItem() ;

	//If the Control Key is ON
	if( bCtrl )
	{
		//NOTE1: If the clicked item was already has the focus then no TVN_SELCHANGE
		//message will be genereated.So I'm handling this situation here;
		//If the item was selected already deselect it otherwise select it
		//if( (hSelItem==hClickItem) && GetItemState( hClickItem,TVIS_SELECTED) & TVIS_SELECTED )
		if( GetItemState( hClickItem,TVIS_SELECTED) & TVIS_SELECTED )
		{
			SetItemState( hClickItem,~TVIS_SELECTED,TVIS_SELECTED);

			//Once after deselecting the item, it goes into edit mode.To avoid this
			//I'm just setting the *pResult = 1 which avoids editing the label
			*pResult = 1;
			
			//Send the notification to the parent dialog about the selected items
			CollectSelectedItems();
			GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL );
			

		}
		UpdateWindow();
	}
	

}
//***************************************************************************
void CVersatileTreeCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here

	//Get the old selected item and new item
	HTREEITEM hOldSelItem = pNMTreeView->itemOld.hItem;
	HTREEITEM hNewSelItem = pNMTreeView->itemNew.hItem;

	CString str1,str2;
	str1 = GetItemText( hOldSelItem );
	str2= GetItemText( hNewSelItem );

	//Get the action by which the selection is generated
	UINT& action = pNMTreeView->action;

	//Get the shift and control key state
	bool bCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
	bool bShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;

	//If control key is ON then select the old item also.Anyhow the new item is selected
	//OnSelchanging
	if((action == TVC_BYMOUSE && bCtrl) ) 
	{
		//Select the old item
		if( hOldSelItem && m_bOldItemSelected )
		{
			SetItemState(hOldSelItem, UINT(TVIS_SELECTED), UINT(TVIS_SELECTED));			
		}

	}
	//Similary if already item1 is in selection.Now SHift + Down arrow key is pressed
	//Old = item1 and new = item2 and i have to select both item1 and item2
	else if ( (action == TVC_BYKEYBOARD) && bShift )
	{
		//Select the old item
		if( hOldSelItem && m_bOldItemSelected )
		{
			SetItemState(hOldSelItem, UINT(TVIS_SELECTED), UINT(TVIS_SELECTED));
		}
	}
	//If the selection is by mouse and shfit key is also used then select all the items
	//starting from old to new.All the intermediate items between old to new is selected
	else if( (action == TVC_BYMOUSE) && bShift )
	{
		bool bSelect = true;

		//Suppose if the hOldSelItem is down in the hierarchy than the hNewSelItem
		//swap the items for looping
		CRect rc1 ,rc2;
		GetItemRect(hOldSelItem,&rc1,true );
		GetItemRect(hNewSelItem,&rc2,true );

		if( rc2.top < rc1.top )
			IterateItems( SelectItems,hNewSelItem,hOldSelItem,&bSelect );
		else
			IterateItems( SelectItems,hOldSelItem,hNewSelItem,&bSelect );
	}
	//If control and shift key is in off state and user clicked on an item.Means he wants to
	//remove whatever the previous selected items and wants to select only the clicked item
	if( !bCtrl && !bShift && hNewSelItem )
	{
		//Remove all the old selection
		bool bSelect = false;
		IterateItems( SelectItems,NULL,NULL,&bSelect );

		//Select only the new item
		SetItemState(hNewSelItem, UINT(TVIS_SELECTED), UINT(TVIS_SELECTED));

	}
	//May be the developer who uses the control programatically sets the selection.
	//He wants to retain the old selection in addition to the new item
	if( action == TVC_UNKNOWN && m_bOldItemSelected && hOldSelItem  ) 
	{
		SetItemState(hOldSelItem, UINT(TVIS_SELECTED), UINT(TVIS_SELECTED));		
	}
	UpdateWindow() ;
	*pResult = 0;

	//Send the notification to the parent dialog about the selected items
	CollectSelectedItems();
	GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 
	//Invalidate();


}
//***************************************************************************
void CVersatileTreeCtrl::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	
	//Get the old selected item and new item
	HTREEITEM hOldSelItem = pNMTreeView->itemOld.hItem;
	HTREEITEM hNewSelItem = pNMTreeView->itemNew.hItem;

	//-------------------------------------------------------------------------------------------------------------------------
	//Get the seletion state of the old item.This will become false in the following 2 cases.
	//CASE1: when the user does the first selection ie., there is no selection at all in the tree,
	//		 and user clicks an item for selection.In this case olditem = NULL
	//		 and newitem=clickeditem.

	//CASE2: Select item1 first [ newitem=clickeditem[!TVIS_SELECTED] olditem = NULL].
	//		 Press ctrl key and select item2[ newitem=clickeditem[!TVIS_SELECTED] olditem = item1[TVIS_SELECTED]].
	//	     Press ctrl key and deselect item2.Now in this case we wont get control here.It will be
	//	     handled by OnClickLButton which deselects item2.Again press ctrl key and deselect the
	//		 item1 [ newitem=item[TVIS_SELECTED] olditem = item2[!TVIS_SELECTED]].

	 m_bOldItemSelected = hOldSelItem && (GetItemState(hOldSelItem, UINT(TVIS_SELECTED)) & TVIS_SELECTED);

	//-----------------------------------------------------------------------------------------------------------------------------


	//Get the shift and control key state
	bool bCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
	bool bShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;

	//Get the action by which the selection is generated
	UINT& action = pNMTreeView->action;

	//If the action is by mouse and ctrl is key on at the same time
	if((action == TVC_BYMOUSE && bCtrl) ) 
	{
		//If the new item was already in selected state, then deselect it.This may happen say for example
		//item1 is first selected and by pressing ctrl key item2 is selected.Now we have 2 items in selection
		//Now if the user presses ctrl key and clicks on item1.Now our olditem is item2[TVIS_SELECTED] and new item is
		//item1[TVIS_SELECTED] and at the same time item1 is in the selected state and our ctrl key is ON
		if( hNewSelItem )
		{
			if( (GetItemState(hNewSelItem,TVIS_SELECTED)&TVIS_SELECTED) )
			{
				//Deselect the new item
				SetItemState(hNewSelItem, UINT(~TVIS_SELECTED), UINT(TVIS_SELECTED));
				UpdateWindow() ;

				//abort change of selection.Otherwise TVN_SELCHANGED message will be generated.
				*pResult = 0 ;	 
			}
		
		}
	}
	//If say item1 and item2 is already selected.Now the user presses shift + UP arrow key.
	//Now our olditem = item2[TVIS_SELECTED] and newitem = item1[TVIS_SELECTED].So we have
	//to keep the item1 as selected and item2 as deselected one.
	if( (action== TVC_BYKEYBOARD) && bShift )
	{
		//If the new item is in selected state then remove the selection of the old item
		//i.e, the selection of item2
		if( GetItemState(hNewSelItem,TVIS_SELECTED)&TVIS_SELECTED )
			m_bOldItemSelected = false;
	}
	
	*pResult = 0;
}
//***************************************************************************
void CVersatileTreeCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_KEYDOWN* pTVKeyDown = (TV_KEYDOWN*)pNMHDR;
	// TODO: Add your control notification handler code here

	CollectSelectedItems();

	if( pTVKeyDown->wVKey == VK_DELETE )
	{
		//Delete the selected items
		int iSelItemCnt = 0;
		for( ; iSelItemCnt < m_vecSelectedItems.size(); iSelItemCnt++ )
		{
			SetItemData( m_vecSelectedItems[iSelItemCnt],0 );
			DeleteItem( m_vecSelectedItems[iSelItemCnt] );
		}
	}
	if( pTVKeyDown->wVKey == VK_F2 )
	{
		if( m_vecSelectedItems.size() == 1 )
			EditLabel( m_vecSelectedItems[0] );
	}

	UpdateWindow();

	*pResult = 0;
}
/*****************************************************************************
/DESCRIPTION:
/-----------
/		To add the image prepared with the checkbox into the list
/
/PARAM
/------
/		lpInsertStruct[in]		-	Custom data of item to be inserted
/
/RESULT:
/-------
/		Index of the image in the imagelist
*/

int	CVersatileTreeCtrl::AddImageToList( PCUSTOMINSERTSTRUCT lpInsertStruct )
{
	//HERE WE HAVE 8 BITMAPS TOTALLY.LETS SEE
	//	1.	CHECK IMAGE
	//  2.  MASK FOR THE CHECK
	//	3.	NORMAL IMAGE OF ITEM
	//	4.  MASK IMAGE OF THE ITEM
	//	5.	UNCHECK IMAGE
	//	6.	MASK FOR THE UNCHCKED.THIS IS SAME AS #2
	//	7.	EXPANDED IMAGE [SOME ITEMS DOESNT HAVE EXPANDED IMAGE.IN THIS CASE THIS IS SAME AS #3]
	//	8.	MASK FOR THE EXPANDED IMAGE

	
	//Resource ID for the normal image
	int		iBmpID				= lpInsertStruct->m_pCustomData->m_uNormalImage;
	
	//Resource ID for the expanded image
	int		iExpandedBmpID		= lpInsertStruct->m_pCustomData->m_uExpandedImage;
	
	//Get checkbox is needed for the item and state of the checkbox
	bool	bNeedChkBox	= lpInsertStruct->m_pCustomData->m_bChecked;
	bool	bCheckState	= lpInsertStruct->m_pCustomData->m_bCheckState;

	//Index of the inserted image from the image list
	int index = 0;

	//Resource ID's of the prefixing bitmaps [CHECKED/UNCHECKED/AND MASK FOR THE TWO]
	int noPrefixBmpID,ChkBmpID,unChkBmpID;

	//If check box is needed then assign the resource for the CHECK,UNCHECK AND MASK
	if( bNeedChkBox )
	{
		noPrefixBmpID	= IDB_BITMAP_EMPTY;	
		ChkBmpID		= IDB_BITMAP_CHECK_16;
		unChkBmpID		= IDB_BITMAP_UNCHECK;
	
	}
	//Otherwise all the check/uncheck and their mask are empty
	else
	{
		noPrefixBmpID = ChkBmpID = unChkBmpID =   IDB_BITMAP_EMPTY;
	}

	//Add the normal state image
	index = AddNoramlStateImages( iBmpID,iExpandedBmpID,lpInsertStruct);
	if( index )
		return 0;

	//Add the images for the check state
	AddCheckStateImages( iBmpID,ChkBmpID,unChkBmpID,lpInsertStruct->m_pCustomData );

	//Add the expanded state images
	AddExpStateImages( iBmpID,iExpandedBmpID,ChkBmpID,unChkBmpID,lpInsertStruct->m_pCustomData );
	
	if( iBmpID == iExpandedBmpID )
	{
		lpInsertStruct->m_pCustomData->m_iCheckedExpandedIndex = lpInsertStruct->m_pCustomData->m_iCheckedNormalIndex;
		lpInsertStruct->m_pCustomData->m_iUnCheckedExpandedIndex = lpInsertStruct->m_pCustomData->m_iUnCheckedNormalIndex;
	}
	

	return 0;

}
/*****************************************************************************
/DESCRIPTION:
/-----------
/			To add the images for normal and expanded state [ WITHOUT CHECKBOX ]
/
/PARAM
/------
/		uBmpID[in]			-	ID for the normal image
/		uExpBmpID[in]		-	ID for the expanded image
/		lpInsertStruct[in]	-	Custom Insert structure
/
/RESULT:
/-------
/		Index of the normal image
*/
int	CVersatileTreeCtrl::AddNoramlStateImages( UINT uBmpID,UINT  uExpBmpID,PCUSTOMINSERTSTRUCT lpInsertStruct )
{
	if( !lpInsertStruct )
		return -1;

	//if already the image is there
	int iBmpFound = -1;
	iBmpFound = GetBitmapIndexFromImgList( uBmpID );

	//If bitmap is found then return
	int addIndex = 0;
	if( iBmpFound > -1 )
	{
		vector<int>  &vecExistingImages	= m_mapBitmapID[uBmpID];
		lpInsertStruct->m_pCustomData->m_iNormalIndex							=  vecExistingImages[IMAGE_NORMAL_INDEX ];
		lpInsertStruct->m_pCustomData->m_iExpandedIndex						=	vecExistingImages[IMAGE_EXPAND_INDEX];
		lpInsertStruct->m_pCustomData->m_iCheckedNormalIndex			=	vecExistingImages[IMAGE_CHECKED_NORMAL_INDEX ];
		lpInsertStruct->m_pCustomData->m_iUnCheckedNormalIndex		=	vecExistingImages[IMAGE_UNCHECKED_NORMAL_INDEX ];	
		lpInsertStruct->m_pCustomData->m_iCheckedExpandedIndex		=	vecExistingImages[IMAGE_CHECKED_EXPANDED_INDEX ];		
		lpInsertStruct->m_pCustomData->m_iUnCheckedExpandedIndex=	vecExistingImages[IMAGE_UNCHECKED_EXPANDED_INDEX ];

		if( !lpInsertStruct->m_pCustomData->m_bChecked )
		{
			lpInsertStruct->m_tvIS.item.iImage							= lpInsertStruct->m_pCustomData->m_iNormalIndex;
			lpInsertStruct->m_tvIS.item.iSelectedImage			= lpInsertStruct->m_pCustomData->m_iNormalIndex;
		}
		else
		{
			lpInsertStruct->m_tvIS.item.iImage							= lpInsertStruct->m_pCustomData->m_iCheckedNormalIndex;
			lpInsertStruct->m_tvIS.item.iSelectedImage			=lpInsertStruct->m_pCustomData->m_iCheckedNormalIndex;
		}
		return 1;		
	}

	vector<int> vecImages;

	//PREPARE NORMAL IMAGE
	int iNormndex = AddImage( uBmpID,IDB_BITMAP_EMPTY );

	lpInsertStruct->m_pCustomData->m_iNormalIndex		= iNormndex;
	lpInsertStruct->m_pCustomData->m_iExpandedIndex = iNormndex;


	//If the item is given expansion image also
	if( uBmpID != uExpBmpID )
	{
		//Prepare expanded image with out any checkbox
		int iExpIndex = AddImage( uExpBmpID,IDB_BITMAP_EMPTY );
		lpInsertStruct->m_pCustomData->m_iExpandedIndex = iExpIndex;
	}

	vecImages.push_back( lpInsertStruct->m_pCustomData->m_iNormalIndex	);
	vecImages.push_back( lpInsertStruct->m_pCustomData->m_iExpandedIndex	);
	m_mapBitmapID.insert( make_pair(uBmpID,vecImages) );

	return 0;
}									  

/*****************************************************************************
/DESCRIPTION:
/-----------
/			To add the images for the check,uncheck images for normal state
/
/PARAM
/------
/		uBmpID[in]			-	ID for the normal image
/		uCheckBmpID[in]		-	ID of the check image
/		uUnCheckBmpID[in]	-	ID of the uncheck image
/		pCustData[in]		-	Custom data where the image index is stored
/
/RESULT:
/-------
/		Index of the image
*/
int	CVersatileTreeCtrl::AddCheckStateImages(UINT uBmpID,UINT uCheckBmpID,UINT uUnCheckBmpID,PCUSTOMITEMDATA pCustData )
{
	if( !pCustData )
		return -1;

	//Get the index of the normal image
	int iBmpFound = -1;
	iBmpFound = GetBitmapIndexFromImgList( uBmpID );
	if( iBmpFound == -1 )
		return -1;

	vector<int>  &vecExistingImages = m_mapBitmapID[uBmpID];
	if( !pCustData->m_bChecked )
	{
		vecExistingImages.push_back( -1 );
		vecExistingImages.push_back( -1 );
		return -1;
	}
	
	//Prepare the  normal state image for the item with check box ON
	//1. Append checkbox image with the image represeting the item
	//2. If the item does not have check box, then add an empty image with the image represeting the item
	int iNormCheckIndex = AddImage( uBmpID,uCheckBmpID);
	pCustData->m_iCheckedNormalIndex		= iNormCheckIndex;
	

	int iNormUnCheckIndex = -1;
	//Prepare NORMALIMAGE with UNCHECK.Add the UNCHECK with NORMAL IMAGE.In case if the
	//item doesn't have check box CHECK is replaced by EMPTY
	if( uUnCheckBmpID != uCheckBmpID )
		iNormUnCheckIndex = AddImage( uBmpID,uUnCheckBmpID );
	pCustData->m_iUnCheckedNormalIndex		= iNormUnCheckIndex;

	vecExistingImages.push_back( 	pCustData->m_iCheckedNormalIndex );
	vecExistingImages.push_back( 	pCustData->m_iUnCheckedNormalIndex );

	return iNormCheckIndex;
	
}
/*****************************************************************************
/DESCRIPTION:
/-----------
/			To add the images for the check,uncheck images for normal state
/
/PARAM
/------
/		uBmpID[in]			-	ID for the normal image
/		uExpBmpID[in]		-	ID for the expanded image
/		uCheckBmpID[in]		-	ID of the check image
/		uUnCheckBmpID[in]	-	ID of the uncheck image
/		pCustData[in]		-	Custom data where the image index is stored
/
/RESULT:
/-------
/		Index of the image
*/
int	CVersatileTreeCtrl::AddExpStateImages(UINT uBmpID,UINT  uExpBmpID,UINT uCheckBmpID,UINT uUnCheckBmpID,PCUSTOMITEMDATA pCustData )
{
	if( !pCustData )
		return -1;

	vector<int>  &vecExistingImages = m_mapBitmapID[uBmpID];

	//If there is no specific expanded image given to the item, the image representing normal and expanded
	//states are used to represet expanded state as well
	if( uBmpID == uExpBmpID )
	{
		m_mapBitmapID[uBmpID].push_back(  m_mapBitmapID[uBmpID].at(IMAGE_CHECKED_NORMAL_INDEX ) );
		m_mapBitmapID[uBmpID].push_back(  m_mapBitmapID[uBmpID].at(IMAGE_UNCHECKED_NORMAL_INDEX ) );
		return  -1;
	}

	//Get the index of the normal image
	int iBmpFound = -1;
	iBmpFound = GetBitmapIndexFromImgList( uBmpID );
	if( iBmpFound == -1)
		return -1;

	//Prepare the expanded image for the item with check box ON
	//1. Append checkbox image with the image represeting the item
	//2. If the item does not have check box, then add an empty image with the image represeting the item
	int iExpCheckndex = AddImage( uExpBmpID,uCheckBmpID );
	pCustData->m_iCheckedExpandedIndex = iExpCheckndex;

	//Prepare the expanded image for the item with check box OFF
	//1. Append checkbox OFF image with the image represeting the item.
	//2. If the item does not have check box, then add an empty image with the image represeting the item
	int iExpUncheckIndex = AddImage( uExpBmpID,uUnCheckBmpID );
	pCustData->m_iUnCheckedExpandedIndex = iExpUncheckIndex;

	//Add the images to the vector holding all the images associated with the item
	vecExistingImages.push_back( 	pCustData->m_iCheckedExpandedIndex );
	vecExistingImages.push_back( 	pCustData->m_iUnCheckedExpandedIndex );

	return iExpCheckndex;

}								

/*****************************************************************************
/DESCRIPTION:
/-----------
/		To prepare the bitmap along with the check box
/
/PARAM
/------
/		nBmpID[in]			-	ID of the bitmap
/		resBmp[in]			-	Prepared Bitmap object
/		newBmpW[out]		-	Width of the new bitmap
/		newBmpH[out]		-	Height of the newbitmap
/		iPrefixBmpID[in]	-	ID of the bitmap to be prefixed [ CHECK/UNCHECK/EMPTY]
/
/RESULT:
/-------
/		Index of the image if it is already in the image list,otherwise 0
*/
int	CVersatileTreeCtrl::PrepareImageWithPrefixBmp( UINT nBmpID,CBitmap& resBmp,int& newBmpW,int& newBmpH,UINT iPrefixBmpID /*= -1*/ )
{
	CBitmap bmp;

	//Create the dc
	CClientDC dc( this );

	//Load the given bimap resource
	bmp.LoadBitmap( nBmpID );

	BITMAP bm,chkbm;
	//res is Nonzero if successful; otherwise 0.
	int res = bmp.GetBitmap(&bm);

	//Get the size of the checkbox bitmap
	CBitmap chkBmp;
	chkBmp.LoadBitmap( iPrefixBmpID );
	res = chkBmp.GetBitmap(&chkbm);

	newBmpW = 2* bm.bmWidth;
	newBmpH = bm.bmHeight;

	//If prefix bitmap is empty then add the image first and empty bitmap viceversa
	bool prefixFirst = true;
	if( IDB_BITMAP_EMPTY == iPrefixBmpID )
		prefixFirst = false;
	
	if( chkbm.bmWidth != bm.bmWidth || chkbm.bmHeight != bm.bmHeight )
	{
		//Get the size of the bitmap according to that checkbox bitmap has to be
		//scaled
		CBitmap scaledBmp;
		ScaleBitmap( chkBmp, chkbm.bmWidth,chkbm.bmHeight, bm.bmWidth,bm.bmHeight,scaledBmp);		
		
		if( prefixFirst )
		{
			AddBitamps( &scaledBmp,&bmp,&resBmp,newBmpW,newBmpH );			
		}
		else
		{
			AddBitamps( &bmp,&scaledBmp,&resBmp,newBmpW,newBmpH );			
	}	
	}
	else
	{
		if( prefixFirst )
		{
			AddBitamps( &chkBmp,&bmp,&resBmp,newBmpW,newBmpH );			
		}
		else
		{
			AddBitamps( &bmp,&chkBmp,&resBmp,newBmpW,newBmpH );	
		}
	}

	return -1;
	
}
/*****************************************************************************
/DESCRIPTION:
/-----------
/		To scale a given bitmp
/
/PARAM
/------
/		bmp[in]			-	Bitmap to be scaled
/		Width[in]		-	width of the  bitmap
/		Height[in]		-	Height of the bitmap
/		newWidth[in]	-	New width of the  bitmap
/		newHeight[in]	-	New Height of the bitmap
/		resBmp[out]		-	Resulting scaled bitmap
/
/RESULT:
/-------
/		void
*/
void	CVersatileTreeCtrl::ScaleBitmap( CBitmap& bmp,int Width,int Height,int newWidth,int newHeight,CBitmap& resBmp  )
{
	CClientDC dc( this );

	//Create the memory dc
	CDC cMemDC1,cMemDC2;
	cMemDC1.CreateCompatibleDC(&dc );
	cMemDC2.CreateCompatibleDC(&dc );

	//Select the bitmap into the memdc
	CBitmap* pOldBmp1 = cMemDC1.SelectObject(&bmp);

	//Create a bitmap to the new size and width
	resBmp.CreateCompatibleBitmap(&dc,newWidth,newHeight );
	CBitmap* pOldBmp2 = cMemDC2.SelectObject(&resBmp );

	//Now copy the bitmap from memdc1 to memdc2
	cMemDC2.StretchBlt(0,0,newWidth,newHeight,&cMemDC1,0,0,Width,Height,SRCCOPY);

	cMemDC1.SelectObject(pOldBmp1);
	cMemDC2.SelectObject(pOldBmp2);
	
}


/***************************************************************************
/DESCRIPTION:
/-----------
/		To combine to given bitmaps
/
/PARAM
/------
/		pBmp1[in]	-	First bitmap Reference
/		pBmp2[in]	-	Second bitmap Reference
/		resBmp[in]	-	Resulting bitmap
/		W[in]		-	New height of the bitmap.If -1 then autocomputation is done
/		H[in]		-	New height of the bitmap.If -1 then autocomputation is done
/
/RESULT:
/-------
/		void
*/
bool CVersatileTreeCtrl:: AddBitamps( CBitmap*  pBmp1,CBitmap* pBmp2,CBitmap* resBmp,int W /*=-1*/,int H/*=-1*/ )
{
	int newBmpW = W;
	int newBmpH = H;

	CClientDC dc(this);

	BITMAP bm1,bm2;
	pBmp1->GetBitmap(&bm1);
	pBmp2->GetBitmap(&bm2);


	//If the user doesnt know the new size of the bitamp then compute it
	if( newBmpW == -1 || newBmpH == - 1)
	{   
		newBmpW = bm1.bmWidth + bm2.bmWidth;
		newBmpH = bm1.bmHeight + bm2.bmHeight;
	}
	
	//Create the 3 memory DCs.
	CDC cMemDC1,cMemDC2,CMemDCTgt;

	//This memory dc is used to copy the checkbox bitmap
	if(!cMemDC1.CreateCompatibleDC(&dc))
		return false;

	//This memory dc is used to copy the image bitmap of the item
	if(!cMemDC2.CreateCompatibleDC(&dc))
		return false;

	//This dc is used to create and copy the combined bitmap [ checkbox bmp + image bmp ]
	if(!CMemDCTgt.CreateCompatibleDC(&dc))
		return false;

	//First copy the check box bitmap into memDC1
	 CBitmap* oldBmp1 = cMemDC1.SelectObject( pBmp1 );

	 //Copy the image bitmap into memDC2
	 CBitmap* oldBmp2 = cMemDC2.SelectObject( pBmp2 );

	//Create the bitmap of the required size [ Combine both the bitmaps ]
	if(!resBmp->CreateCompatibleBitmap(&dc, newBmpW, newBmpH ))
		return false;

	//Now select the combined bitmap into the CMemDCTgt
	CBitmap* oldBmp3 = CMemDCTgt.SelectObject( resBmp );
	
	//Then first copy the checkbox bitmap from the position 0,0 on the target
	CMemDCTgt.BitBlt( 0,0,bm1.bmWidth,bm1.bmHeight,&cMemDC1,0,0,SRCCOPY );

	//Next copy the image bitmap from the position (chkbm.bmWidth,chkbm.bmHeight ) on the
	//target.Because already we have copied checkbox.
	CMemDCTgt.BitBlt( bm1.bmWidth,0,bm2.bmWidth,bm2.bmHeight,&cMemDC2,0,0,SRCCOPY );

	//Now restore the oldbitmaps
	cMemDC1.SelectObject( oldBmp1 );
	cMemDC2.SelectObject( oldBmp2 );
	CMemDCTgt.SelectObject( oldBmp3 );

	//SaveBitmap( dc.GetSafeHdc(),*resBmp,"D:\\chk.bmp");
	return true;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/		Message handler for the check box click
/
/PARAM
/------
/		pNMHDR[in]	-	Custom data structure
/
/RESULT:
/-------
/		void
*/
LRESULT CVersatileTreeCtrl::OnChkBoxClicked(  WPARAM wp, LPARAM lp)
{
	LPCUSTNMHDR pNMHDR = ( LPCUSTNMHDR)wp;
	PCUSTOMITEMDATA pCustData = (PCUSTOMITEMDATA)( pNMHDR->m_data );

	if( !pCustData )
		return 1;
	if( pCustData->m_bChecked  )
	{
			
		//Set the new state
		pCustData->m_bCheckState = !pCustData->m_bCheckState;	
				
		if( pCustData->m_bCheckState )
		{
			m_vecCheckedItems.insert( pNMHDR->m_hItem );
		}
		else
		{
			m_vecCheckedItems.erase( pNMHDR->m_hItem );
		}
		
		bool bItemExpanded = false;
		if( GetItemState( pNMHDR->m_hItem,TVIS_EXPANDED) & TVIS_EXPANDED) 
		bItemExpanded = true;

		//Set the image for the item based on its state
		SetImage( pNMHDR->m_hItem );
	
		GetParent()->SendMessage( TVN_ITEM_CHECK_TOGGLE,(WPARAM)(&m_vecCheckedItems),NULL ); 

	}	
	return 0;
	
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To get the index of the bitmap from the image list
/
/PARAM
/------
/		uBitmapID[in]	-	ID of the bitmap
/
/RESULT:
/-------
/		Index of the bitmap if found,-1 otherwise
*/
int	CVersatileTreeCtrl::GetBitmapIndexFromImgList( UINT uBitmapID )
{
	//Search the bitmap in the m_mapBitmapID
	int iBmpCtr = 0;
	map<UINT, vector<int> >::iterator it = m_mapBitmapID.find(uBitmapID);
	if( it != m_mapBitmapID.end( ) )
	{
		return ( std::distance( m_mapBitmapID.begin( ), it ) );
	}
	return -1;
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To add a given image and its mask to the list
/
/PARAM
/------
/		uBmpID[in]			-	ID of the bitmap
/		uPrefixBmpID		-	Resource id of the prefix bitmap
/
/RESULT:
/-------
/		Index of the bitmap in the image list
*/
int  CVersatileTreeCtrl::AddImage( UINT uBmpID,UINT uPrefixBmpID )
{

	int newBmpW,newBmpH;
	CBitmap imageBmp;
	CClientDC dc(this);

	//Else prepare the image with its prefix.Similarly the mask of the image with its prefix
	PrepareImageWithPrefixBmp( uBmpID,imageBmp,newBmpW,newBmpH,uPrefixBmpID );
	
	//If there is no image list create it
	if( !m_pImgList )
	{
		m_pImgList = new CImageList;
		m_pImgList->Create( newBmpW,newBmpH,ILC_COLOR32 | ILC_MASK,5,5);
		SetImageList(m_pImgList,TVSIL_NORMAL);
	}

	HBITMAP hNmp = imageBmp.operator HBITMAP();
	int index = -1;
	index = m_pImgList->Add( &imageBmp,m_cMaskColor );
	
	//Get the image for the respective index
	IMAGEINFO imgInfo;
	m_pImgList->GetImageInfo(index,&imgInfo);
	return index;
}
//***************************************************************************
void CVersatileTreeCtrl::OnPaint()
{
	CTreeCtrl::OnPaint();
	int n = GetVisibleCount();
	IterateItems( DrawItem,NULL,NULL,NULL );	
}
//***************************************************************************
void CVersatileTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	
	TV_HITTESTINFO tvHitInfo;
	tvHitInfo.pt = point;
	m_hRClickItem = NULL;
	m_hRClickItem = HitTest(&tvHitInfo );

	//Get the custom data of the item
	if( m_hRClickItem )
	{
		//If the item was already in selected state, then show only the context menu
		if( GetItemState( m_hRClickItem,TVIS_SELECTED ) & TVIS_SELECTED )
		{
			//Dont do any thing. Just show the context menu
		}
		else
		{
			//If there are some already selected items, deselect them and select the right clicked item
			//and show the context menu
			int iSelItemCtr = 0;
			for( ; iSelItemCtr < m_vecSelectedItems.size( ); iSelItemCtr++ )
			{
				SetItemState(m_vecSelectedItems[iSelItemCtr],~TVIS_SELECTED,TVIS_SELECTED );
			}
			SelectItem(NULL);

			//Select the right clicked item
			SetItemState(m_hRClickItem,TVIS_SELECTED,TVIS_SELECTED );			

			//As this is the only selected item, have only this in the m_vecSelectedItems
			m_vecSelectedItems.clear( );
			m_vecSelectedItems.push_back( m_hRClickItem );
			GetParent()->SendMessage( TVN_SELECTION_CHANGED,(WPARAM)(&m_vecSelectedItems),NULL ); 
		}

		//Show the menu associated with the right clicked item
		PCUSTOMITEMDATA pCustomData = (PCUSTOMITEMDATA) GetItemData(m_hRClickItem);

		//Get the menu id associated with the item
		UINT uMenuID = pCustomData->m_uMenuID;
		if( uMenuID == -1 )
			return;

		//Load the menu
		CMenu menu;
		menu.LoadMenu( uMenuID );

		//Get the rectangle of the the item
		CRect rc;
		GetItemRect( m_hRClickItem,&rc,true);

		CPoint bottomRight;
		bottomRight.x = rc.right;
		bottomRight.y = rc.bottom;
		ClientToScreen(&bottomRight);

		CMenu* pMenu = menu.GetSubMenu(0);
		pMenu->TrackPopupMenu( TPM_LEFTBUTTON ,bottomRight.x,bottomRight.y,GetParent() );
	}	
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To Create the disabled image for an item
/
/PARAM
/------
/		bmp[out]		-	Resuting disabled image
/		
/
/RESULT:
/-------
/		void
*/
void	CVersatileTreeCtrl::GenerateDisableImage( CBitmap& bmp )
{
	SetBitMapColor( bmp,::GetSysColor(COLOR_GRAYTEXT),RGB(0,128,128) );
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To set the color in the bitmap
/
/PARAM
/------
/		bmp[out]		-	Resuting disabled image
/		color[in]		-	Color to be set for each pixel of the bitmap
/		excludeColor	-	Color to be excluded from setting
/		
/
/RESULT:
/-------
/		Index of the bitmap if found,-1 otherwise
*/
void	CVersatileTreeCtrl::SetBitMapColor( CBitmap& bmp,COLORREF color,COLORREF excludeColor)
{
	CClientDC dc(this);

	//Get bitmap size and height
	BITMAP bm;
	bmp.GetBitmap(&bm);

	WORD biBits = 32 * bm.bmPlanes;  

	//Get the info about the bitmap
	BITMAPINFO bi;
    ZeroMemory(&bi,sizeof(bi));
    bi.bmiHeader.biSize			= sizeof( BITMAPINFOHEADER );
    bi.bmiHeader.biHeight		= bm.bmHeight;
    bi.bmiHeader.biWidth		= bm.bmWidth;
    bi.bmiHeader.biPlanes		= bm.bmPlanes;
    bi.bmiHeader.biBitCount		= biBits;

	//Get the size of the bitmap in number of bytes.Pass 5th param as NULL.So 
	//that it will give  you the size
	GetDIBits( dc,bmp,0,bm.bmHeight,NULL,&bi,DIB_RGB_COLORS);

	//Next create the array of bytes to get the color values
	//NOTE: lower bottom of the bitmap is origin to take the bytes.i.e, the lower bottom
	//line is first parsed,then the line above the lower bottom etc.,
	int nbBytes  = bi.bmiHeader.biSizeImage;
	LPBYTE pBits = new BYTE[ nbBytes ];

	//Get the color values from the bitmap
	GetDIBits( dc,bmp,0,bm.bmHeight,pBits,&bi,DIB_RGB_COLORS);

	int byteCtr = 0;

	if( bi.bmiHeader.biBitCount == 32 )
	{
		//if biBitCount = 32 then each pixel is represented by 32 bits.That is 4 bytes.
		//Highbyte is not used.RGB is in reversed order i.e, 2,1,0 and not 0,1,2
		for( ; byteCtr < nbBytes/4; byteCtr++ )
		{
			BYTE red	=	pBits[ byteCtr*4+2];
			BYTE green  =	pBits[ byteCtr*4+1];
			BYTE blue	=	pBits[ byteCtr*4+0];

			COLORREF col = RGB( red,green,blue );

			if( col != excludeColor )
			{
				pBits[ byteCtr*4+2] = GetRValue( color );
				pBits[ byteCtr*4+1] = GetGValue( color );
				pBits[ byteCtr*4+0] = GetBValue( color );					
			}
		}
		//Set the newly set color array to the bitmap
		SetDIBits( dc,bmp,0,bm.bmHeight,pBits,&bi,DIB_RGB_COLORS);
		delete pBits;
		pBits = NULL;	
		
		//SaveBitmap( dc.GetSafeHdc(),bmp,"D:\\chk.bmp");

	}
}	
/***************************************************************************
/DESCRIPTION:
/-----------
/			To get the bitmap of the image from the image list
/
/PARAM
/------
/		iIndex[in]	-	Index of the image
/		bmp[out]	-	Resulting bitmap 
/		
/
/RESULT:
/-------
/		True if successfull,false otherwise
*/
bool	CVersatileTreeCtrl::GetBitampFromImageList( int iIndex,CBitmap& bmp )
{
	//Get the image list of the tree control
	CImageList* pImageList = GetImageList(TVSIL_NORMAL);
	if( !pImageList )
		return false;

	//Get the count of images in the imagelist
	int iImgCt = pImageList->GetImageCount();
	if( iIndex < 0 || iIndex >= iImgCt )
		return false;

	//Get the size of image at the specified index
	int imgW,imgH;
	ImageList_GetIconSize( pImageList->GetSafeHandle(),&imgW,&imgH);

	//Extract the icon of the item
	HICON hIcon = pImageList->ExtractIcon(iIndex);

	//Convert the icon into bitmap
	GetBitmapFromIcon( hIcon,imgW,imgH,bmp);

	return true;

}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To convert the icon into bitmap
/
/PARAM
/------
/		hIcon[out]		-	Handle to the icon to be converted
/		ImgWidth[in]	-	Width of the icon
/		ImgHeight[in]	-	Height of the icon
/		
/
/RESULT:
/-------
/		True if successful,false otherwise
*/
bool	 CVersatileTreeCtrl::GetBitmapFromIcon( HICON hIcon,int ImgWidth,int ImgHeight,CBitmap& cBitmap )
{
	if( !hIcon )
		return false;

	//Create DC
	CClientDC dc(this);

	//Create memory dc
	CDC cMemDC;
	if ( !cMemDC.CreateCompatibleDC(&dc) )
		return false;

	//Create the bitmap of required size
	if(!cBitmap.CreateCompatibleBitmap(&dc, ImgWidth, ImgHeight))
		return false;

	//Select the bitmap into the memory DC
	CBitmap* pOldBmp = cMemDC.SelectObject(&cBitmap );

	//Fill the background with the masking color
	cMemDC.FillSolidRect(0,0,ImgWidth,ImgHeight, RGB(0, 128, 128));

	//Now draw the icon using DrawIconEx
	DrawIconEx(cMemDC.m_hDC, 0, 0, hIcon, ImgWidth, ImgHeight, 0, 0, DI_NORMAL);
	
	//Now restore the old bitmap
	cMemDC.SelectObject(pOldBmp );

	return true;

}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To set the image index based on the state of the item
/
/PARAM
/------
/		hItem[in]	-	Item to which the image to be set
/
/RESULT:
/-------
/		True if successful,false otherwise
*/
void	CVersatileTreeCtrl::SetImage( HTREEITEM hItem )
{
	//Check for item
	if( !hItem )
		return;
	
	//Get the custom data
	PCUSTOMITEMDATA pCustData = (PCUSTOMITEMDATA) GetItemData(hItem);
	if( !pCustData )
		return;

	//if the item is enabled
	if( pCustData->m_bEnable )
	{
		//Is the item expanded
		bool bItemExpanded = false;
		if( GetItemState( hItem,TVIS_EXPANDED) & TVIS_EXPANDED) 
			bItemExpanded = true;
		
		SetExpandImage( hItem,bItemExpanded );
	}
	else
	{
		//TODO : DISABLED IMAGE
		int iBmpFound = -1;
		iBmpFound = GetBitmapIndexFromImgList( pCustData->m_uNormalImage );
		SetItemImage( hItem, pCustData->m_iDisableIndex,pCustData->m_iDisableIndex);
	}
	Invalidate();
}
/***************************************************************************
/DESCRIPTION:
/-----------
/			To set the image when the item is expanded
/
/PARAM
/------
/		hItem[in]		-	Item to which the image to be set
/		bItemExpanded	-	Item is expanded or collpased
/
/RESULT:
/-------
/		True if successful,false otherwise
*/
void	CVersatileTreeCtrl::SetExpandImage( HTREEITEM hItem,bool bItemExpanded/*=true*/  )
{
	//Get the custom data
	PCUSTOMITEMDATA pCustData = (PCUSTOMITEMDATA) GetItemData(hItem);
	if( !pCustData )
		return;

	//Get the bitmap id associated with the item
	int iBmpFound = -1;
	iBmpFound = GetBitmapIndexFromImgList( pCustData->m_uNormalImage );
	if( iBmpFound < 0 )
		return;

	int imgIndex = -1;
	//Check the item has the checkbox 
	if( pCustData->m_bChecked )
	{
		//If the item is checked
		if( pCustData->m_bCheckState )
		{
			//If the item is expanded
			if( bItemExpanded )
			{
				imgIndex = pCustData->m_iCheckedExpandedIndex;
			}
			//Collapsed
			else
			{
				imgIndex = pCustData->m_iCheckedNormalIndex;
			}
		}
		//Item is not checked
		else
		{
			//If the item is expanded
			if( bItemExpanded )
			{
				imgIndex = pCustData->m_iUnCheckedExpandedIndex;
			}
			//Collapsed
			else
			{
				imgIndex = pCustData->m_iUnCheckedNormalIndex;
			}
		}
	}
	//If the item doesnt have checkbox
	else
	{
		//If the item is expanded
		if( bItemExpanded )
		{
			imgIndex = pCustData->m_iExpandedIndex;
		}
		else
		{
			imgIndex = pCustData->m_iNormalIndex;
		}
	}
	SetItemImage( hItem, imgIndex,imgIndex);
}


int		CVersatileTreeCtrl::IsNormalCheckedExists( UINT uBmpID )
{
	return 0;
}

//***************************************************************************
void CVersatileTreeCtrl::SetMoveDraggedItem( bool flag )
{
	m_bMoveItem = flag;	
}

void CVersatileTreeCtrl::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
I'm working as Senior software Engineer since 7 years and interested in MFC and COM programming.

Comments and Discussions