www.pudn.com > TabBar.rar > TabBarCtrl.cpp, change:2006-04-06,size:53716b


// outbar.h : implementation of the CTabBarCtrl class 
 
#include "stdafx.h" 
#include "tabbarctrl.h" 
 
#define IDC_TABBARCTRL_REMOVE 60000 
#define IDS_TABBARCTRL_REMOVE "Remove" 
#define IDC_TABBARCTRL_RENAME 60001 
#define IDS_TABBARCTRL_RENAME "Rename" 
#define IDC_TABBARCTRL_ADD    60002 
#define IDS_TABBARCTRL_ADD    "Add Tab" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CItemTracker class 
 
CItemTracker::CItemTracker() 
{ 
	m_nHandleSize = TABBARCTRL_BLOCKTRACKER_BORDERWIDTH; 
	m_nStyle      = hatchedBorder; 
} 
 
CItemTracker::~CItemTracker() 
{ 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Operations 
 
BOOL CItemTracker::Track(CWnd *pWnd, CPoint Point, BOOL bAllowInvert,	CWnd *pWndClipTo /*= NULL*/) 
{ 
	ASSERT_VALID(pWnd); 
	// get these codes from the MFC source codes for calling the subclass TrackHandle() function 
	// perform hit testing on the handles 
	int nHandle = HitTestHandles(Point); 
	if(nHandle < 0) 
	{ 
		// didn't hit a handle, so just return FALSE 
		return FALSE; 
	} 
	// otherwise, call helper function to do the tracking 
	m_bAllowInvert = bAllowInvert; 
	return TrackHandle(nHandle, pWnd, Point, pWndClipTo); 
} 
 
BOOL CItemTracker::TrackHandle(int nHandle, CWnd *pWnd, CPoint Point, CWnd *pWndClipTo) 
{ 
	ASSERT_VALID(pWnd); 
	// write more codes is the MFC source codes, but add the mouse state handle 
	ASSERT(nHandle >= 0); 
	ASSERT(nHandle <= 8);   // handle 8 is inside the rect 
	// don't handle if capture already set 
	if(::GetCapture() != NULL) 
		return FALSE; 
	AfxLockTempMaps();  // protect maps while looping 
	ASSERT(!m_bFinalErase); 
	// save original width & height in pixels 
	int nWidth = m_rect.Width(); 
	int nHeight = m_rect.Height(); 
	// set capture to the window which received this message 
	pWnd->SetCapture(); 
	ASSERT(pWnd == CWnd::GetCapture()); 
	pWnd->UpdateWindow(); 
	if(pWndClipTo != NULL) 
		pWndClipTo->UpdateWindow(); 
	CRect rectSave = m_rect; 
	// find out what x/y coords we are supposed to modify 
	int *px, *py; 
	int xDiff, yDiff; 
	GetModifyPointers(nHandle, &px, &py, &xDiff, &yDiff); 
	xDiff = Point.x - xDiff; 
	yDiff = Point.y - yDiff; 
	// get DC for drawing 
	CDC* pDrawDC; 
	if(pWndClipTo != NULL) 
		// clip to arbitrary window by using adjusted Window DC 
		pDrawDC = pWndClipTo->GetDCEx(NULL, DCX_CACHE); 
	else 
		// otherwise, just use normal DC 
		pDrawDC = pWnd->GetDC(); 
	ASSERT_VALID(pDrawDC); 
	CRect rectOld; 
	BOOL bMoved = FALSE; 
	pWnd->SetTimer(10, TABBARCTRL_BLOCKTRACKER_DELAYTIME, NULL); 
	BOOL bSetCursor = FALSE; 
	// get messages until capture lost or cancelled/accepted 
	for(;;) 
	{ 
		MSG msg; 
		VERIFY(::GetMessage(&msg, NULL, 0, 0)); 
		if(CWnd::GetCapture() != pWnd) 
			break; 
		// add codes for setting the cursor 
		if((msg.message == WM_MOUSEMOVE || msg.message == WM_LBUTTONUP || msg.message == WM_TIMER) && bSetCursor) 
		{ 
			CPoint MousePoint; 
			GetCursorPos(&MousePoint); 
			CRect ClientRect; 
			pWnd->GetClientRect(&ClientRect); 
			pWnd->ScreenToClient(&MousePoint); 
			if(ClientRect.PtInRect(MousePoint)) 
				::SetCursor(AfxGetApp()->LoadCursor(IDC_MOVE)); 
			else 
				::SetCursor(::LoadCursor(NULL, IDC_NO)); 
		} 
		switch(msg.message) 
		{ 
		// handle movement/accept messages 
		case WM_TIMER: 
			if(msg.wParam == 10) 
			{ 
				pWnd->KillTimer(10); 
				if(!bMoved) 
				{ 
					bMoved = TRUE; 
					m_bErase = FALSE; 
					DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd); 
					bSetCursor = TRUE; 
					::SetCursor(AfxGetApp()->LoadCursor(IDC_MOVE)); 
				} 
			} 
			break; 
		case WM_LBUTTONUP: 
		case WM_MOUSEMOVE: 
			rectOld = m_rect; 
			// handle resize cases (and part of move) 
			if(px != NULL) 
				*px = (int)(short)LOWORD(msg.lParam) - xDiff; 
			if(py != NULL) 
				*py = (int)(short)HIWORD(msg.lParam) - yDiff; 
			// handle move case 
			if(nHandle == hitMiddle) 
			{ 
				m_rect.right = m_rect.left + nWidth; 
				m_rect.bottom = m_rect.top + nHeight; 
			} 
			// allow caller to adjust the rectangle if necessary 
			AdjustRect(nHandle, &m_rect); 
			// only redraw and callback if the rect actually changed! 
			m_bFinalErase = (msg.message == WM_LBUTTONUP); 
			if(!rectOld.EqualRect(&m_rect) || m_bFinalErase) 
			{ 
				if(bMoved) 
				{ 
					m_bErase = TRUE; 
					DrawTrackerRect(&rectOld, pWndClipTo, pDrawDC, pWnd); 
				} 
				OnChangedRect(rectOld); 
				if(msg.message != WM_LBUTTONUP) 
				{ 
					bMoved = TRUE; 
					bSetCursor = TRUE; 
				} 
			} 
			if(m_bFinalErase) 
				goto ExitLoop; 
			if(!rectOld.EqualRect(&m_rect)) 
			{ 
				m_bErase = FALSE; 
				DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd); 
			} 
			break; 
		// handle cancel messages 
		case WM_KEYDOWN: 
			if(msg.wParam != VK_ESCAPE) 
				break; 
		case WM_RBUTTONDOWN: 
			if(bMoved) 
			{ 
				m_bErase = m_bFinalErase = TRUE; 
				DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd); 
			} 
			m_rect = rectSave; 
			goto ExitLoop; 
		// just dispatch rest of the messages 
		default: 
			DispatchMessage(&msg); 
			break; 
		} 
	} 
ExitLoop: 
	if(pWndClipTo != NULL) 
		pWndClipTo->ReleaseDC(pDrawDC); 
	else 
		pWnd->ReleaseDC(pDrawDC); 
	ReleaseCapture(); 
	AfxUnlockTempMaps(FALSE); 
	// restore rect in case bMoved is still FALSE 
	if(!bMoved) 
		m_rect = rectSave; 
	m_bFinalErase = FALSE; 
	m_bErase = FALSE; 
	// return TRUE only if rect has changed 
	return !rectSave.EqualRect(&m_rect); 
} 
 
void CItemTracker::OnChangedRect(const CRect& /*OldRect*/) 
{ 
	// no default implementation, useful for derived classes 
	m_rect.bottom = m_rect.top + m_FirstRect.Height(); 
	m_rect.right = m_rect.left + m_FirstRect.Width(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CFolderAddDlg class 
 
CFolderAddDlg::CFolderAddDlg(CWnd *pParent /*=NULL*/) : CDialog(CFolderAddDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CFolderAddDlg) 
		// NOTE: the ClassWizard will add member initialization here 
	m_AddFolderName = _T(""); 
	//}}AFX_DATA_INIT 
} 
 
BEGIN_MESSAGE_MAP(CFolderAddDlg, CDialog) 
	//{{AFX_MSG_MAP(CFolderAddDlg) 
		// NOTE: the ClassWizard will add message map macros here 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// Overrides 
 
void CFolderAddDlg::DoDataExchange(CDataExchange *pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CFolderAddDlg) 
		// NOTE: the ClassWizard will add DDX and DDV calls here 
	DDX_Text(pDX, IDC_TABBARCTRL_ADDFOLDERNAME, m_AddFolderName); 
	//}}AFX_DATA_MAP 
} 
 
BOOL CFolderAddDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
	return TRUE;  // return TRUE unless you set the focus to a control 
	              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CFolderEdit class 
 
CFolderEdit::CFolderEdit() 
{ 
	m_bEscapeKeyPressed = FALSE; 
	m_nIndex = -1; 
	m_EditString.Empty(); 
} 
 
CFolderEdit::~CFolderEdit() 
{ 
} 
 
BEGIN_MESSAGE_MAP(CFolderEdit, CEdit) 
	//{{AFX_MSG_MAP(CFolderEdit) 
	ON_WM_CREATE() 
	ON_WM_KILLFOCUS() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// Overrides 
 
void CFolderEdit::PostNcDestroy() 
{ 
	CEdit::PostNcDestroy(); 
	delete this; 
} 
 
BOOL CFolderEdit::PreTranslateMessage(MSG *pMsg)  
{ 
	if(pMsg->wParam == VK_RETURN) 
	{ 
		PostMessage(WM_CLOSE, 0, 0); 
		m_bEscapeKeyPressed = FALSE; 
		return TRUE; 
	} 
	else if(pMsg->wParam == VK_ESCAPE) 
	{ 
		PostMessage(WM_CLOSE, 0, 0); 
		m_bEscapeKeyPressed = TRUE; 
		return TRUE; 
	} 
	return CEdit::PreTranslateMessage(pMsg); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Message handlers 
 
int CFolderEdit::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
	if(CEdit::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	SendMessage(WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0)); 
	return 0; 
} 
 
void CFolderEdit::OnKillFocus(CWnd* /*pNewWnd*/) 
{ 
	PostMessage(WM_CLOSE, 0, 0); 
	if(!m_bEscapeKeyPressed) 
	{ 
		GetWindowText(m_EditString); 
		if(!m_EditString.IsEmpty()) 
			GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_FOLDERENDEDIT, (LPARAM)this); 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CTabBarCtrl class 
IMPLEMENT_DYNCREATE(CTabBarCtrl, CWnd) 
 
CTabBarCtrl::CTabBarCtrl() 
{ 
	m_nFolderBorderWidth     = TABBARCTRL_FOLDERBORDERWIDTH; 
	m_FolderLightColor       = TABBARCTRL_FOLDERLIGHTBORDER; 
	m_FolderHighlightColor   = TABBARCTRL_FOLDERHIGHLIGHTCOLOR; 
	m_FolderShadowColor      = TABBARCTRL_FOLDERSHADOWBORDER; 
	m_FolderTextColor        = TABBARCTRL_FOLDERTEXTCOLOR; 
	m_FolderBackGroundColor  = TABBARCTRL_FOLDERBACKGROUNDCOLOR; 
	m_FolderFrontColor       = TABBARCTRL_FOLDERFRONTCOLOR; 
	m_ItemLightColor         = TABBARCTRL_ITEMHILIGHTCOLOR; 
	m_ItemShadowColor        = TABBARCTRL_ITEMSHADOWCOLOR; 
	m_ItemHighlightColor     = TABBARCTRL_ITEMHIGHLIGHTCOLOR; 
	m_ItemSelectedColor      = TABBARCTRL_ITEMSELECTEDCOLOR; 
	m_ItemTextColor          = TABBARCTRL_ITEMTEXTCOLOR; 
	m_ChildBackGroundColor   = TABBARCTRL_CHILDBACKGROUNDCOLOR; 
	m_nFolderHeight          = TABBARCTRL_FOLDERHEIGHT; 
	m_nItemBorderWidth       = TABBARCTRL_ITEMBORDERWIDTH; 
	m_pImageList             = NULL; 
	m_nSelFolder             = 0; 
	m_nDelayTime             = TABBARCTRL_DELAYTIME; 
	m_nHorzSpace             = TABBARCTRL_ITEMHORZSPACE; 
	m_nVertSpace             = TABBARCTRL_ITEMVERTSPACE; 
	m_lAnimationTickCount    = TABBARCTRL_ANIMATIONTICKCOUNT; 
	m_nRButtonHitItemIndex   = -1; 
	m_nRButtonHitFolderIndex = -1; 
	m_bToolTip               = TRUE; 
	// get the windows directory 
	CString WndDirString; 
	GetWindowsDirectory(WndDirString.GetBuffer(MAX_PATH), MAX_PATH); 
	WndDirString.ReleaseBuffer(); 
	WndDirString += _T("\\winhlp32.exe"); 
	// this retrieves cursor #106 from winhlp32.exe, which is a hand pointer 
	HMODULE hModule = LoadLibrary(WndDirString); 
	if(hModule) 
	{ 
		HCURSOR hHandCursor = LoadCursor(hModule, MAKEINTRESOURCE(106)); 
		if(hHandCursor) 
			m_hHandCursor = CopyCursor(hHandCursor); 
		else 
			TRACE0("unsuccessfully copy cursor from winhlp32.exe(in tabbarctrl.cpp line 350)\n"); 
	} 
	FreeLibrary(hModule); 
} 
 
CTabBarCtrl::~CTabBarCtrl() 
{ 
	for(int i = 0; i < m_FolderList.GetSize(); i++) 
	{ 
		if(m_FolderList.GetAt(i)) 
			delete (CTabBarFolder*)m_FolderList.GetAt(i); 
	} 
	m_FolderList.RemoveAll(); 
	if(m_pImageList) 
		m_pImageList->DeleteImageList(); 
	delete m_pImageList; 
} 
 
BEGIN_MESSAGE_MAP(CTabBarCtrl, CWnd) 
	//{{AFX_MSG_MAP(CTabBarCtrl) 
	ON_COMMAND(IDC_TABBARCTRL_ADD, OnAddFolder) 
	ON_COMMAND(IDC_TABBARCTRL_REMOVE, OnRemoveItem) 
	ON_COMMAND(IDC_TABBARCTRL_RENAME, OnRenameItem) 
	ON_MESSAGE(WM_TABBARCTRL_NOTIFY, OnEndFolderEdit) 
	ON_WM_CONTEXTMENU() 
	ON_WM_CREATE() 
	ON_WM_ERASEBKGND() 
	ON_WM_LBUTTONDBLCLK() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_MOUSEMOVE() 
	ON_WM_PAINT() 
	ON_WM_SIZE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// Operations 
 
void CTabBarCtrl::AnimateFolderScroll(int nFromFolder, int nToFolder) 
{ 
	ASSERT(nFromFolder >= 0 && nFromFolder < GetFolderCount()); 
	ASSERT(nToFolder >= 0 && nToFolder < GetFolderCount()); 
	DWORD lparam = nFromFolder & 0x0000ffff; 
	DWORD dwtemp = nToFolder & 0x0000ffff; 
	lparam += dwtemp << 16; 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_FOLDERSCROLLBEGIN, (LPARAM)lparam); 
	// set the default cursor 
	SetCursor(LoadCursor(NULL, IDC_ARROW)); 
	// create three memory device contexts 
	CClientDC DrawDC(this); 
	CDC ScreenDC, FrontDC, BackDC; 
	ScreenDC.CreateCompatibleDC(&DrawDC); 
	FrontDC.CreateCompatibleDC(&DrawDC); 
	BackDC.CreateCompatibleDC(&DrawDC); 
	// get the back ground rectangle and front rectangle 
	CRect FrontRect, BackRect; 
	// get the from folder items rectangle 
	GetInsideRect(FrontRect); 
	// get the to folder rectangle 
	GetFolderRect(BackRect, nToFolder); 
	// get the update rectangle 
	BackRect.UnionRect(BackRect, FrontRect); 
	FrontRect = CRect(0, 0, BackRect.Width(), BackRect.Height()); 
	// create three bitmaps 
	CBitmap ScreenBitmap, FrontBitmap, BackBitmap; 
	ScreenBitmap.CreateCompatibleBitmap(&DrawDC, FrontRect.Width(), FrontRect.Height()); 
	FrontBitmap.CreateCompatibleBitmap(&DrawDC, FrontRect.Width(), FrontRect.Height()); 
	BackBitmap.CreateCompatibleBitmap(&DrawDC, FrontRect.Width(), FrontRect.Height()); 
	// select the bitmaps into the memory device contexts 
	CBitmap* pScreenBitmap = ScreenDC.SelectObject(&ScreenBitmap); 
	CBitmap* pFrontBitmap = FrontDC.SelectObject(&FrontBitmap); 
	CBitmap* pBackBitmap = BackDC.SelectObject(&BackBitmap); 
	// copy the screen bitmap into the memory device context 
	ScreenDC.BitBlt(0, 0, BackRect.Width(), BackRect.Height(), &DrawDC, BackRect.left, BackRect.top, SRCCOPY); 
	BackDC.BitBlt(0, 0, BackRect.Width(), BackRect.Height(), &DrawDC, BackRect.left, BackRect.top, SRCCOPY); 
	// fill the front bitmap with the back ground color 
	FrontDC.FillSolidRect(FrontRect, m_ChildBackGroundColor); 
	// draw the scrolled bitmap into the memory device context 
	if(nToFolder > nFromFolder) 
	{ 
		// draw the to folder child window 
		CWnd* pWnd = GetFolderChild(nToFolder); 
		if(pWnd) 
		{ 
			CPoint OldPoint = FrontDC.SetViewportOrg(0, m_nFolderHeight * (nToFolder - nFromFolder)); 
			BOOL bPrev = pWnd->ShowWindow(SW_SHOW); 
			pWnd->SendMessage(WM_ERASEBKGND, (WPARAM)FrontDC.GetSafeHdc(), (LPARAM)0); 
			pWnd->SendMessage(WM_PAINT, (WPARAM)FrontDC.GetSafeHdc(), (LPARAM)0); 
			if(!bPrev) 
				pWnd->ShowWindow(SW_HIDE); 
			FrontDC.SetViewportOrg(OldPoint); 
		} 
		else 
		{ 
			// redraw the to folder items 
			CRect ItemsRect; 
			GetInsideRect(ItemsRect); 
			CRect LimitRect = ItemsRect; 
			ItemsRect.top = 0; 
			CBitmap ItemsBitmap; 
			ItemsBitmap.CreateCompatibleBitmap(&DrawDC, ItemsRect.Width(), ItemsRect.Height()); 
			CDC ItemsDC; 
			ItemsDC.CreateCompatibleDC(&DrawDC); 
			CBitmap* pItemsBitmap = ItemsDC.SelectObject(&ItemsBitmap); 
			ItemsDC.FillSolidRect(&ItemsRect, m_ChildBackGroundColor); 
			PaintItems(&ItemsDC, nToFolder, LimitRect); 
			FrontDC.BitBlt(ItemsRect.left, m_nFolderHeight * (nToFolder - nFromFolder), ItemsRect.Width(), LimitRect.Height(), &ItemsDC, LimitRect.left, (nFromFolder + 1) * m_nFolderHeight, SRCCOPY); 
			ItemsDC.SelectObject(pItemsBitmap); 
			ItemsDC.DeleteDC(); 
			ItemsBitmap.DeleteObject(); 
		} 
		// draw the folders 
		CRect FolderRect(FrontRect); 
		FolderRect.top = 0; 
		FolderRect.bottom = m_nFolderHeight; 
		for(int i = nFromFolder + 1; i <= nToFolder; i++) 
		{ 
			DrawFolder(&FrontDC, i, FolderRect); 
			FolderRect.OffsetRect(0, m_nFolderHeight); 
		} 
	} 
	else 
	{ 
		// draw the to folder child window 
		CWnd* pWnd = GetFolderChild(nToFolder); 
		if(pWnd) 
		{ 
			CPoint OldPoint = FrontDC.SetViewportOrg(0, m_nFolderHeight); 
			BOOL bPrev = pWnd->ShowWindow(SW_SHOW); 
			pWnd->SendMessage(WM_ERASEBKGND, (WPARAM)FrontDC.GetSafeHdc(), (LPARAM)0); 
			pWnd->SendMessage(WM_PAINT, (WPARAM)FrontDC.GetSafeHdc(), (LPARAM)0); 
			if(!bPrev) 
				pWnd->ShowWindow(SW_HIDE); 
			FrontDC.SetViewportOrg(OldPoint); 
		} 
		else 
		{ 
			// redraw the to folder items 
			CRect ItemsRect; 
			GetInsideRect(ItemsRect); 
			CRect LimitRect = ItemsRect; 
			ItemsRect.top = 0; 
			CBitmap ItemsBitmap; 
			ItemsBitmap.CreateCompatibleBitmap(&DrawDC, ItemsRect.Width(), ItemsRect.Height()); 
			CDC ItemsDC; 
			ItemsDC.CreateCompatibleDC(&DrawDC); 
			CBitmap* pItemsBitmap = ItemsDC.SelectObject(&ItemsBitmap); 
			ItemsDC.FillSolidRect(&ItemsRect, m_ChildBackGroundColor); 
			PaintItems(&ItemsDC, nToFolder, LimitRect); 
			FrontDC.BitBlt(ItemsRect.left, m_nFolderHeight, ItemsRect.Width(), LimitRect.Height(), &ItemsDC, LimitRect.left, (nFromFolder + 1) * m_nFolderHeight, SRCCOPY); 
			ItemsDC.SelectObject(pItemsBitmap); 
			ItemsDC.DeleteDC(); 
			ItemsBitmap.DeleteObject(); 
		} 
		// draw the folders 
		CRect FolderRect(FrontRect); 
		FolderRect.top = 0; 
		FolderRect.bottom = m_nFolderHeight; 
		DrawFolder(&FrontDC, nToFolder, FolderRect); 
	} 
	// move the to folder and its child window 
	if(nToFolder > nFromFolder) 
	{ 
		for(int i = FrontRect.bottom - (nToFolder - nFromFolder) * m_nFolderHeight; i > 0; i -= TABBARCTRL_FOLDERSCROLLSTEP) 
		{ 
			ScreenDC.BitBlt(FrontRect.left, i, FrontRect.Width(), FrontRect.bottom - i, &FrontDC, 0, 0, SRCCOPY); 
			DrawDC.BitBlt(BackRect.left, BackRect.top, BackRect.Width(), BackRect.bottom, &ScreenDC, 0, 0, SRCCOPY); 
			Sleep(m_lAnimationTickCount); 
		} 
		ScreenDC.BitBlt(FrontRect.left, 0, FrontRect.Width(), FrontRect.bottom, &FrontDC, 0, 0, SRCCOPY); 
		DrawDC.BitBlt(BackRect.left, BackRect.top, BackRect.Width(), BackRect.bottom, &ScreenDC, 0, 0, SRCCOPY); 
	} 
	else 
	{ 
		for(int i = FrontRect.top; i < FrontRect.bottom - (nFromFolder - nToFolder) * m_nFolderHeight; i += TABBARCTRL_FOLDERSCROLLSTEP) 
		{ 
			ScreenDC.BitBlt(FrontRect.left, FrontRect.top, FrontRect.Width(), i - FrontRect.top, &FrontDC, 0, 0, SRCCOPY); 
			ScreenDC.BitBlt(FrontRect.left, i - FrontRect.top, FrontRect.Width(), FrontRect.bottom - (i - FrontRect.top), &BackDC, 0, m_nFolderHeight, SRCCOPY); 
			DrawDC.BitBlt(BackRect.left, BackRect.top, BackRect.Width(), BackRect.Height(), &ScreenDC, 0, 0, SRCCOPY); 
			Sleep(m_lAnimationTickCount); 
		} 
		ScreenDC.BitBlt(FrontRect.left, FrontRect.top, FrontRect.Width(), FrontRect.Height() - (nFromFolder - nToFolder) * m_nFolderHeight, &FrontDC, 0, 0, SRCCOPY); 
		ScreenDC.BitBlt(FrontRect.left, FrontRect.Height() - (nFromFolder - nToFolder) * m_nFolderHeight, FrontRect.Width(), (nFromFolder - nToFolder) * m_nFolderHeight, &BackDC, 0, m_nFolderHeight, SRCCOPY); 
		DrawDC.BitBlt(BackRect.left, BackRect.top, BackRect.Width(), BackRect.Height(), &ScreenDC, 0, 0, SRCCOPY); 
	} 
	// release the gdi resource 
	ScreenDC.SelectObject(pScreenBitmap); 
	FrontDC.SelectObject(pFrontBitmap); 
	BackDC.SelectObject(pBackBitmap); 
	ScreenDC.DeleteDC(); 
	FrontDC.DeleteDC(); 
	BackDC.DeleteDC(); 
	ScreenBitmap.DeleteObject(); 
	FrontBitmap.DeleteObject(); 
	BackBitmap.DeleteObject(); 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_FOLDERSCROLLEND, (LPARAM)lparam); 
} 
 
BOOL CTabBarCtrl::CreateToolTip() 
{ 
	CString ClassName = AfxRegisterWndClass(NULL); 
	m_bCreateToolTip = m_ToolTip.CreateEx(0L, ClassName, "ToolTip", WS_BORDER | WS_POPUP, CRect(0, 0, 0, 0), this, 0L); 
	return m_bCreateToolTip; 
} 
 
BOOL CTabBarCtrl::DragItem(CPoint Point, int nItemIndex) 
{ 
	// set the items tracker 
	ReleaseCapture(); 
	DWORD lpparam = nItemIndex & 0x0000ffff; 
	DWORD dwtemp = m_nSelFolder & 0x0000ffff; 
	lpparam += dwtemp << 16; 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_DRAGITEMBEGIN, (LPARAM)lpparam); 
	CRect ItemRect; 
	GetItemRect(ItemRect, nItemIndex, m_nSelFolder); 
	CItemTracker Tracker; 
	Tracker.m_rect = ItemRect; 
	Tracker.m_FirstRect = ItemRect; 
	BOOL bReturn = Tracker.Track(this, Point, FALSE, NULL); 
	if(!bReturn) 
	{ 
		InvalidateRect(Tracker.m_rect, FALSE); 
		return FALSE; 
	} 
	// get the capture 
	CPoint MousePoint; 
	GetCursorPos(&MousePoint); 
	ScreenToClient(&MousePoint); 
	CRect ClientRect; 
	GetClientRect(&ClientRect); 
	if(ClientRect.PtInRect(MousePoint) && GetCapture() == NULL) 
	{ 
		SetCapture(); 
		ASSERT(this == GetCapture()); 
	} 
	// check if the item is in other folder 
	int nIndex1, ht1 = HitTestEx(MousePoint, nIndex1); 
	if(ht1 == htFolder && nIndex1 != m_nSelFolder) 
	{ 
		// change the item 
		AfxLockTempMaps(); 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(m_nSelFolder); 
		void* pBarItem = (pBarFolder->m_ItemList.GetAt(nItemIndex)); 
		pBarFolder->m_ItemList.RemoveAt(nItemIndex); 
		pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nIndex1); 
		if(((CTabBarItem*)pBarItem)->m_bSelected) 
			ResetAllSelectedItems(nIndex1); 
		pBarFolder->m_ItemList.Add(pBarItem); 
		AfxUnlockTempMaps(FALSE); 
		lpparam = nItemIndex & 0x0000ffff; 
		dwtemp = nIndex1 & 0x0000ffff; 
		lpparam += dwtemp << 16; 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ITEMMOVE, (LPARAM)lpparam); 
		SetSelectedFolder(nIndex1); 
		bReturn = TRUE; 
	} 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_DRAGITEMEND, (LPARAM)0L); 
	return bReturn; 
} 
 
CWnd* CTabBarCtrl::GetFolderChild(int nFolderIndex) const 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	return pBarFolder->m_pChildWnd; 
} 
 
DWORD CTabBarCtrl::GetFolderData(int nFolderIndex) const 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	return pBarFolder->m_dwExData; 
} 
 
void CTabBarCtrl::GetFolderRect(CRect& FolderRect, int nFolderIndex) 
{ 
	AssertFolderIndex(nFolderIndex); 
	CRect ClientRect; 
	GetClientRect(ClientRect); 
	if(nFolderIndex > m_nSelFolder) 
		FolderRect.SetRect(ClientRect.left, ClientRect.bottom - ((m_FolderList.GetSize() - nFolderIndex)) * m_nFolderHeight, ClientRect.right, ClientRect.bottom - (m_FolderList.GetSize() - nFolderIndex - 1) * m_nFolderHeight); 
	else  
		FolderRect.SetRect(ClientRect.left, ClientRect.top + nFolderIndex * m_nFolderHeight - 1, ClientRect.right, ClientRect.top + (1 + nFolderIndex) * m_nFolderHeight - 1); 
} 
 
CString CTabBarCtrl::GetFolderText(int nFolderIndex) const 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	return pBarFolder->m_FolderString; 
} 
 
int CTabBarCtrl::GetHightedFolder() const 
{ 
	for(int i = 0; i < m_FolderList.GetSize(); i++) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(i); 
		ASSERT(pBarFolder); 
		if(pBarFolder->m_bHighted) 
			return i; 
	} 
	return -1; 
} 
 
int CTabBarCtrl::GetHightedItem(int nFolderIndex) const 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	for(int i = 0; i < pBarFolder->m_ItemList.GetSize(); i++) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		ASSERT(pBarItem); 
		if(pBarItem->m_bHighted) 
			return i; 
	} 
	return -1; 
} 
 
void CTabBarCtrl::GetInsideRect(CRect& ChildRect) 
{ 
	GetClientRect(ChildRect); 
	if(m_FolderList.GetSize() > 0) 
	{ 
		ChildRect.top += m_nFolderHeight * (m_nSelFolder + 1) - 1; 
		ChildRect.bottom -= (m_FolderList.GetSize() - m_nSelFolder - 1) * m_nFolderHeight; 
	} 
} 
 
int CTabBarCtrl::GetItemCount(int nFolderIndex) const 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	return pBarFolder->m_ItemList.GetSize(); 
} 
 
DWORD CTabBarCtrl::GetItemData(int nItemIndex, int nFolderIndex) const 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	return pBarItem->m_dwExData; 
} 
 
int CTabBarCtrl::GetItemImage(int nItemIndex, int nFolderIndex) const 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	return pBarItem->m_nImageIndex; 
} 
 
BOOL CTabBarCtrl::GetItemRect(CRect& ItemRect, int nItemIndex, int nFolderIndex) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	// get the child window 
	CRect InsideRect; 
	GetInsideRect(InsideRect); 
	// recorde the top left point 
	CPoint TopLeftPoint = InsideRect.TopLeft() + CPoint(m_nHorzSpace, m_nVertSpace); 
	InsideRect.OffsetRect(-InsideRect.left, -InsideRect.top); 
	// get the item size 
	CSize ItemSize = GetItemSize(nItemIndex, nFolderIndex); 
	// check the child window width and height 
	int nHorzItemCount, nVertItemCount; 
	nHorzItemCount = (int)((InsideRect.Width() - m_nHorzSpace) / (m_nHorzSpace + ItemSize.cx)); 
	nVertItemCount = (int)((InsideRect.Height() - m_nVertSpace) / (m_nVertSpace + ItemSize.cy)); 
	// check if the item is visible 
	if(nItemIndex >= nHorzItemCount * nVertItemCount) 
	{ 
		ItemRect.SetRectEmpty(); 
		return FALSE; 
	} 
	// get the item position 
	int nVertPosition = (int)(nItemIndex / nHorzItemCount); 
	int nHorzPosition = nItemIndex - nVertPosition * nHorzItemCount; 
	// get item rectangle 
	ItemRect.top = nVertPosition * (ItemSize.cy + m_nVertSpace); 
	ItemRect.left = nHorzPosition * (ItemSize.cx + m_nHorzSpace); 
	ItemRect.bottom = ItemRect.top + ItemSize.cy; 
	ItemRect.right = ItemRect.left + ItemSize.cx; 
	ItemRect.OffsetRect(TopLeftPoint); 
	ItemRect.InflateRect(TABBARCTRL_ITEMBORDERWIDTH, TABBARCTRL_ITEMBORDERWIDTH); 
	return TRUE; 
} 
 
CSize CTabBarCtrl::GetItemSize(int nItemIndex, int nFolderIndex) const 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	CSize ImageSize(0, 0); 
	if(pBarItem->m_nImageIndex >= 0) 
	{ 
		ASSERT_VALID(m_pImageList); 
		IMAGEINFO ImageInfo; 
		m_pImageList->GetImageInfo(pBarItem->m_nImageIndex, &ImageInfo); 
		ImageSize = CRect(ImageInfo.rcImage).Size(); 
	} 
	ImageSize += CSize(2, 2); 
	return ImageSize; 
} 
 
CString CTabBarCtrl::GetItemText(int nItemIndex, int nFolderIndex) const 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	return pBarItem->m_ItemString; 
} 
 
CMenu* CTabBarCtrl::GetMenu() 
{ 
	CMenu* PopupMenu; 
	PopupMenu = new CMenu(); 
	CPoint ClientPoint; 
	GetCursorPos(&ClientPoint); 
	ScreenToClient(&ClientPoint); 
	int nIndex, ht = HitTestEx(ClientPoint, nIndex); 
	CMenu Menu; 
	PopupMenu->CreatePopupMenu(); 
	PopupMenu->AppendMenu(MF_STRING, IDC_TABBARCTRL_ADD, IDS_TABBARCTRL_ADD); 
	CString String; 
	if(ht == htItem) 
	{ 
		m_nRButtonHitItemIndex = nIndex; 
		m_nRButtonHitFolderIndex = -1; 
		PopupMenu->AppendMenu(MF_STRING, IDC_TABBARCTRL_REMOVE, IDS_TABBARCTRL_REMOVE); 
		if(GetItemCount(m_nSelFolder) <= 1) 
			PopupMenu->EnableMenuItem(IDC_TABBARCTRL_REMOVE, MF_DISABLED | MF_GRAYED); 
	} 
	else if(ht == htFolder) 
	{ 
		m_nRButtonHitFolderIndex = nIndex; 
		m_nRButtonHitItemIndex = -1; 
		PopupMenu->AppendMenu(MF_STRING, IDC_TABBARCTRL_REMOVE, IDS_TABBARCTRL_REMOVE); 
		if(m_FolderList.GetSize() <= 1) 
			PopupMenu->EnableMenuItem(IDC_TABBARCTRL_REMOVE, MF_DISABLED | MF_GRAYED); 
		PopupMenu->AppendMenu(MF_STRING, IDC_TABBARCTRL_RENAME, IDS_TABBARCTRL_RENAME); 
	} 
	return PopupMenu; 
} 
 
int CTabBarCtrl::GetSelectedItem(int nFolderIndex) const 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	for(int i = 0; i < pBarFolder->m_ItemList.GetSize(); i++) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		ASSERT(pBarItem); 
		if(pBarItem->m_bSelected) 
			return i; 
	} 
	return -1; 
} 
	 
BOOL CTabBarCtrl::HideToolTip() 
{ 
	if(m_ToolTip.IsWindowVisible()) 
	{ 
		m_ToolTip.SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); 
		return TRUE; 
	} 
	return FALSE; 
} 
 
void CTabBarCtrl::HighlightFolder(int nFolderIndex) 
{ 
	// check if it has focus 
	CWnd* pWnd = GetFocus(); 
	if(pWnd != NULL && pWnd != this && IsChild(pWnd)) 
	{ 
		TRACE0("the folder do not has focus(in tabbarctrl.cpp line 821)\n"); 
		return; 
	} 
	// check if the last highlighted folder is different from the folder 
	for(int i = 0; i < m_FolderList.GetSize(); i++) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(i); 
		if(pBarFolder->m_bHighted) 
			break; 
	} 
	if(nFolderIndex == -1) 
	{ 
		if(i < m_FolderList.GetSize()) 
		{ 
			CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(i); 
			pBarFolder->m_bHighted = FALSE; 
			CRect UpdateRect; 
			GetFolderRect(UpdateRect, i); 
			InvalidateRect(&UpdateRect, FALSE); 
		} 
	} 
	else if(i == m_FolderList.GetSize()) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
		pBarFolder->m_bHighted = TRUE; 
		CRect UpdateRect; 
		GetFolderRect(UpdateRect, nFolderIndex); 
		InvalidateRect(&UpdateRect, FALSE); 
	} 
	else if(i != nFolderIndex) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(i); 
		pBarFolder->m_bHighted = FALSE; 
		pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
		pBarFolder->m_bHighted = TRUE; 
		CRect OldFolderRect, NewFolderRect; 
		GetFolderRect(OldFolderRect, i); 
		GetFolderRect(NewFolderRect, nFolderIndex); 
		InvalidateRect(&OldFolderRect, FALSE); 
		InvalidateRect(&NewFolderRect, FALSE); 
	} 
} 
 
void CTabBarCtrl::HighlightItem(int nItemIndex) 
{ 
	// check if it has focus 
	CWnd* pWnd = GetFocus(); 
	if(pWnd != NULL && pWnd != this && IsChild(pWnd)) 
	{ 
		TRACE0("the item do not has focus(in tabbarctrl.cpp line 870)\n"); 
		return; 
	} 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(m_nSelFolder); 
	// check if the last highlighted item is different from the item 
	for(int i = 0; i < pBarFolder->m_ItemList.GetSize(); i++) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		ASSERT(pBarItem); 
		if(pBarItem->m_bHighted) 
			break; 
	} 
	// get the child window rectangle 
	CRect InsideRect; 
	GetInsideRect(InsideRect); 
	// create the device context 
	CClientDC DrawDC(this); 
	int nDC = DrawDC.SaveDC(); 
	CRgn ItemsRegion; 
	ItemsRegion.CreateRectRgnIndirect(&InsideRect); 
	DrawDC.SelectClipRgn(&ItemsRegion); 
	ItemsRegion.DeleteObject(); 
	// update the window 
	if(nItemIndex == -1) 
	{ 
		if(i < pBarFolder->m_ItemList.GetSize()) 
		{ 
			CTabBarItem* pBarItem = (CTabBarItem*)(pBarFolder->m_ItemList.GetAt(i)); 
			pBarItem->m_bHighted = FALSE; 
			CRect UpdateRect; 
			GetItemRect(UpdateRect, i, m_nSelFolder); 
			InvalidateRect(&UpdateRect, FALSE); 
			HideToolTip(); 
		} 
	} 
	else if(i == pBarFolder->m_ItemList.GetSize()) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)(pBarFolder->m_ItemList.GetAt(nItemIndex)); 
		pBarItem->m_bHighted = TRUE; 
		CRect UpdateRect; 
		if(GetItemRect(UpdateRect, nItemIndex, m_nSelFolder)) 
			InvalidateRect(&UpdateRect, FALSE); 
		ShowToolTip(nItemIndex); 
	} 
	else if(i != nItemIndex) 
	{ 
		CRect OldItemRect, NewItemRect; 
		CTabBarItem* pBarItem = (CTabBarItem*)(pBarFolder->m_ItemList.GetAt(i)); 
		pBarItem->m_bHighted = FALSE; 
		pBarItem = (CTabBarItem*)(pBarFolder->m_ItemList.GetAt(nItemIndex)); 
		pBarItem->m_bHighted = TRUE; 
		if(GetItemRect(OldItemRect, i, m_nSelFolder) &&	GetItemRect(NewItemRect, nItemIndex, m_nSelFolder)) 
		{ 
			InvalidateRect(&OldItemRect, FALSE); 
			InvalidateRect(&NewItemRect, FALSE); 
		} 
		ShowToolTip(nItemIndex); 
	} 
	DrawDC.RestoreDC(nDC); 
} 
 
void CTabBarCtrl::OnStartFolderEdit(int nFolderIndex) 
{ 
	ReleaseCapture(); 
	AssertFolderIndex(nFolderIndex); 
	CFolderEdit* pEdit = new CFolderEdit(); 
	pEdit->m_nIndex = nFolderIndex; 
	CRect FolderRect; 
	GetFolderRect(FolderRect, nFolderIndex); 
	FolderRect.DeflateRect(2, 2); 
	pEdit->Create(WS_CHILD | WS_VISIBLE | ES_CENTER | ES_AUTOHSCROLL, FolderRect, this, IDC_TABBARCTRL_RENAME); 
	pEdit->ModifyStyleEx(0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	pEdit->SetWindowText(pBarFolder->m_FolderString); 
	pEdit->SetFocus(); 
	pEdit->SetCapture(); 
} 
 
void CTabBarCtrl::ResetAllHightedItems(int nFolderIndex) 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	for(int i = 0; i < pBarFolder->m_ItemList.GetSize(); i++) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		ASSERT(pBarItem); 
		pBarItem->m_bHighted = FALSE; 
	} 
	Invalidate(FALSE); 
} 
 
void CTabBarCtrl::ResetAllSelectedItems(int nFolderIndex) 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	for(int i = 0; i < pBarFolder->m_ItemList.GetSize(); i++) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		ASSERT(pBarItem); 
		pBarItem->m_bSelected = FALSE; 
	} 
	Invalidate(FALSE); 
} 
 
void CTabBarCtrl::SelectItem(int nItemIndex) 
{ 
	// set the selected items 
	if(GetSelectedItem(m_nSelFolder) == nItemIndex) 
	{ 
		ResetAllSelectedItems(m_nSelFolder); 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_RESETALLITEMS, (LPARAM)0L); 
	} 
	else 
		SetSelectedItem(nItemIndex, m_nSelFolder); 
} 
 
void CTabBarCtrl::SetFolderText(int nFolderIndex, CString TextString) 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	pBarFolder->m_FolderString = TextString; 
} 
 
CImageList* CTabBarCtrl::SetImageList(CImageList *pImageList) 
{ 
	ASSERT_VALID(pImageList); 
	if(m_pImageList) 
	{ 
		CImageList* pOldImageList = m_pImageList; 
		m_pImageList->DeleteImageList(); 
		delete m_pImageList; 
		return pOldImageList; 
	} 
	else 
	{ 
		m_pImageList = new CImageList(); 
		m_pImageList->Create(pImageList); 
	} 
	return NULL; 
} 
 
void CTabBarCtrl::SetItemData(int nItemIndex, int nFolderIndex, DWORD dwData) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	pBarItem->m_dwExData = dwData; 
} 
 
void CTabBarCtrl::SetItemImage(int nItemIndex, int nFolderIndex, int nImageIndex) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	pBarItem->m_nImageIndex = nImageIndex; 
} 
 
void CTabBarCtrl::SetItemText(int nItemIndex, int nFolderIndex, CString TextString) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	pBarItem->m_ItemString = TextString; 
} 
 
void CTabBarCtrl::SetSelectedFolder(int nFolderIndex) 
{ 
	AssertFolderIndex(nFolderIndex); 
	// check if the current selected folder is different from the folder 
	if(nFolderIndex == m_nSelFolder) 
		return; 
	// hide the current selected folder child window 
	CWnd* pWnd = GetFolderChild(m_nSelFolder); 
	if(pWnd) 
		pWnd->ShowWindow(SW_HIDE); 
	// set the current selected folder 
	ResetAllHightedItems(m_nSelFolder); 
	ResetAllHightedItems(nFolderIndex); 
	// scroll the new folder 
	AnimateFolderScroll(m_nSelFolder, nFolderIndex); 
	m_nSelFolder = nFolderIndex; 
	// set the new selected folder 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(m_nSelFolder); 
	pWnd = pBarFolder->m_pChildWnd; 
	if(pWnd) 
	{ 
		CRect ChildRect; 
		GetInsideRect(ChildRect); 
		pWnd->MoveWindow(ChildRect); 
		pWnd->ShowWindow(SW_SHOW); 
		pWnd->Invalidate(FALSE); 
	}	 
	// check the current folder state 
	CRect FolderRect; 
	GetFolderRect(FolderRect, m_nSelFolder); 
	CPoint ScreenPoint; 
	GetCursorPos(&ScreenPoint); 
	ScreenToClient(&ScreenPoint); 
	if(!FolderRect.PtInRect(ScreenPoint)) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(m_nSelFolder); 
		pBarFolder->m_bHighted = FALSE; 
		InvalidateRect(FolderRect, FALSE); 
	} 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_FOLDERCHANGE, (LPARAM)m_nSelFolder); 
} 
 
void CTabBarCtrl::SetSelectedItem(int nItemIndex, int nFolderIndex) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	for(int i = 0; i < pBarFolder->m_ItemList.GetSize(); i++) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		ASSERT(pBarItem); 
		if(pBarItem->m_bSelected) 
			break; 
	} 
	if(i == pBarFolder->m_ItemList.GetSize()) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
		pBarItem->m_bSelected = TRUE; 
		CRect UpdateRect; 
		if(GetItemRect(UpdateRect, nItemIndex, nFolderIndex)) 
			InvalidateRect(&UpdateRect, FALSE); 
	} 
	else if(i != nItemIndex) 
	{ 
		CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(i); 
		pBarItem->m_bSelected = FALSE; 
		pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
		pBarItem->m_bSelected = TRUE; 
		CRect OldItemRect, NewItemRect; 
		GetItemRect(OldItemRect, i, nFolderIndex); 
		GetItemRect(NewItemRect, nItemIndex, nFolderIndex); 
		InvalidateRect(&OldItemRect, FALSE); 
		InvalidateRect(&NewItemRect, FALSE); 
	} 
	DWORD lpparam = nItemIndex & 0x0000ffff; 
	DWORD dwtemp = nFolderIndex & 0x0000ffff; 
	lpparam += dwtemp << 16; 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ITEMCHANGE, (LPARAM)lpparam); 
} 
 
BOOL CTabBarCtrl::ShowToolTip(int nItemIndex) 
{ 
	if(m_bCreateToolTip && m_bToolTip) 
	{ 
		// get the tool tip top left point 
		CRect ItemRect; 
		GetItemRect(ItemRect, nItemIndex, m_nSelFolder); 
		ClientToScreen(&ItemRect); 
		CPoint Point; 
		Point.x = (ItemRect.right + ItemRect.left) / 2; 
		Point.y = ItemRect.bottom + 10; 
		// get the tool tip device context 
		CDC* pToolTipDC = m_ToolTip.GetDC(); 
		// create the tool tip font 
		CFont Font; 
		Font.CreateFont(-6, 0, 0, 0, 400, FALSE, FALSE, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, "MS Sans Serif"); 
		CFont* pFont = pToolTipDC->SelectObject(&Font); 
		// get the tool tip text 
		CString ToolTipText = GetItemText(nItemIndex, m_nSelFolder); 
		// get the tool tip top size 
		CSize TextSize = pToolTipDC->GetOutputTextExtent(ToolTipText); 
		CSize Size = CSize(3, 2) + TextSize; 
		// show the tool tip window 
		UINT nFlags = SWP_NOACTIVATE | SWP_NOZORDER; 
		if(m_ToolTip.IsWindowVisible()) 
			m_ToolTip.SetWindowPos(NULL, Point.x, Point.y, Size.cx, Size.cy, nFlags); 
		else 
			m_ToolTip.SetWindowPos(NULL, Point.x, Point.y, Size.cx, Size.cy, nFlags | SWP_SHOWWINDOW); 
		// draw the text 
		int nOldMode = pToolTipDC->SetBkMode(OPAQUE); 
		CRect ToolTipRect(0, 0, Size.cx, Size.cy); 
		pToolTipDC->FillSolidRect(ToolTipRect, GetSysColor(COLOR_INFOBK)); 
		pToolTipDC->DrawText(ToolTipText, ToolTipRect, DT_LEFT); 
		pToolTipDC->SetBkMode(nOldMode); 
		// release the device context 
		pToolTipDC->SelectObject(pFont); 
		Font.DeleteObject(); 
		m_ToolTip.ReleaseDC(pToolTipDC); 
		return TRUE; 
	} 
	return FALSE; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Overrides 
 
int CTabBarCtrl::AddFolder(CString FolderName, DWORD dwExData /*= 0*/) 
{ 
	CTabBarFolder* pBarFolder = new CTabBarFolder(FolderName, dwExData); 
	ASSERT(pBarFolder); 
	int nIndex = m_FolderList.Add((void*)pBarFolder); 
	if(m_FolderList.GetSize() == 1) 
		SetSelectedFolder(0); 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ADDFOLDER, (LPARAM)nIndex); 
	return m_FolderList.GetSize() - 1; 
} 
 
int CTabBarCtrl::AddFolderBar(CString FolderName, CWnd *pChildWnd, DWORD dwExData /*= 0*/) 
{ 
	ASSERT_VALID(pChildWnd); 
	CTabBarFolder* pBarFolder = new CTabBarFolder(FolderName, dwExData); 
	ASSERT(pBarFolder); 
	pBarFolder->m_pChildWnd = pChildWnd; 
	int nIndex = m_FolderList.Add((void*)pBarFolder); 
	if(m_FolderList.GetSize() == 1) 
		SetSelectedFolder(0); 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ADDFOLDER, (LPARAM)nIndex); 
	return m_FolderList.GetSize() - 1; 
} 
 
BOOL CTabBarCtrl::Create(DWORD dwStyle, CRect Rect, CWnd *pParentWnd, UINT nID) 
{ 
	return CWnd::CreateEx(NULL, NULL, NULL, dwStyle, Rect, pParentWnd, nID); 
} 
 
BOOL CTabBarCtrl::CreateEx(DWORD dwExStyle, DWORD dwStyle, CRect Rect, CWnd *pParentWnd, UINT nID) 
{ 
	return CWnd::CreateEx(dwExStyle, NULL, NULL, dwStyle, Rect, pParentWnd, nID); 
} 
 
void CTabBarCtrl::DrawFolder(CDC *pDrawDC, int nFolderIndex, CRect FolderRect) 
{ 
	AssertFolderIndex(nFolderIndex); 
	ASSERT_VALID(pDrawDC); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	// draw the folder 
	CPen Pen(PS_SOLID, 1, m_FolderBackGroundColor); 
	CPen* pOldPen = pDrawDC->SelectObject(&Pen); 
	pDrawDC->MoveTo(FolderRect.left, FolderRect.top); 
	pDrawDC->LineTo(FolderRect.right, FolderRect.top); 
	pDrawDC->SelectObject(pOldPen); 
	FolderRect.top++; 
	Pen.DeleteObject(); 
	// draw the folder state 
	COLORREF FolderBackGroundColor = m_FolderFrontColor; 
	if(pBarFolder->m_bHighted) 
		FolderBackGroundColor = m_FolderHighlightColor; 
	pDrawDC->FillSolidRect(FolderRect, FolderBackGroundColor); 
	if(pBarFolder->m_bHighted) 
		pDrawDC->Draw3dRect(FolderRect, RGB(0, 0, 0), RGB(255, 255, 255)); 
	else 
		pDrawDC->Draw3dRect(FolderRect, RGB(255, 255, 255), RGB(0, 0, 0)); 
	FolderRect.InflateRect(-1, -1); 
	for(int i = 0; i < m_nFolderBorderWidth; i++) 
	{ 
		if(pBarFolder->m_bHighted) 
			pDrawDC->Draw3dRect(FolderRect, m_FolderShadowColor, m_FolderLightColor); 
		else 
			pDrawDC->Draw3dRect(FolderRect, m_FolderLightColor, m_FolderShadowColor); 
		FolderRect.InflateRect(-1, -1); 
	} 
	// draw the folder text 
	int nOldMode = pDrawDC->SetBkMode(TRANSPARENT); 
	CFont* pOldFont = pDrawDC->SelectObject(CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT))); 
	COLORREF OldTextColor = pDrawDC->SetTextColor(m_FolderTextColor); 
	pDrawDC->DrawText(pBarFolder->m_FolderString, FolderRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_PATH_ELLIPSIS); 
	pDrawDC->SetBkMode(nOldMode); 
	pDrawDC->SelectObject(pOldFont); 
	pDrawDC->SetTextColor(OldTextColor); 
} 
 
void CTabBarCtrl::DrawItem(CDC *pDrawDC, int nFolderIndex, CRect ItemRect, int nItemIndex) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	ASSERT_VALID(m_pImageList); 
	ASSERT_VALID(pDrawDC); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	CFont* pOldFont = (CFont*)pDrawDC->SelectObject(CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT))); 
	COLORREF OldTextColor = pDrawDC->SetTextColor(m_ItemTextColor); 
	int nOldMode = pDrawDC->SetBkMode(TRANSPARENT); 
	// draw the item state 
	COLORREF ItemBackgroundColor = m_ChildBackGroundColor; 
	if(pBarItem->m_bSelected) 
		ItemBackgroundColor = m_ItemSelectedColor; 
	else if(pBarItem->m_bHighted) 
		ItemBackgroundColor = m_ItemHighlightColor; 
	pDrawDC->FillSolidRect(&ItemRect, ItemBackgroundColor); 
	for(int i = 0; i < m_nItemBorderWidth; i++) 
	{ 
		if(pBarItem->m_bSelected) 
			pDrawDC->Draw3dRect(ItemRect, m_ItemShadowColor, m_ItemLightColor); 
		else if(pBarItem->m_bHighted) 
			pDrawDC->Draw3dRect(ItemRect, m_ItemLightColor, m_ItemShadowColor); 
		ItemRect.DeflateRect(1, 1); 
	} 
	// draw the item image 
	if(m_pImageList && m_pImageList->GetImageCount()) 
	{ 
		CPoint ImagePoint; 
		IMAGEINFO ImageInfo; 
		m_pImageList->GetImageInfo(pBarItem->m_nImageIndex, &ImageInfo); 
		CSize ImageSize = CRect(ImageInfo.rcImage).Size(); 
		ImagePoint.x = ItemRect.left + (ItemRect.Width() - ImageSize.cx) / 2; 
		ImagePoint.y = ItemRect.top + (ItemRect.Height() - ImageSize.cy) / 2; 
		if(pBarItem->m_bSelected) 
			ImagePoint += CPoint(1, 1); 
		else if(pBarItem->m_bHighted) 
			ImagePoint -= CPoint(1, 1); 
		m_pImageList->Draw(pDrawDC, pBarItem->m_nImageIndex, ImagePoint, ILD_NORMAL); 
	} 
	pDrawDC->SetTextColor(OldTextColor); 
	pDrawDC->SelectObject(pOldFont); 
	pDrawDC->SetBkMode(nOldMode); 
} 
 
int CTabBarCtrl::HitTestEx(CPoint Point, int& nIndex) 
{ 
	CRect HitRect; 
	// test if the folder is hit 
	for(int i = 0; i < m_FolderList.GetSize(); i++) 
	{ 
		GetFolderRect(HitRect, i); 
		if (HitRect.PtInRect(Point))  
		{ 
			nIndex = i; 
			return htFolder; 
		} 
	} 
	// test if the item is hit 
	GetInsideRect(HitRect); 
	if(HitRect.PtInRect(Point)) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(m_nSelFolder); 
		ASSERT(pBarFolder); 
		for(i = 0; i < pBarFolder->GetItemCount(); i++) 
		{ 
			CRect ItemRect; 
			if(GetItemRect(ItemRect, i, m_nSelFolder) && ItemRect.PtInRect(Point) && HitRect.PtInRect(ItemRect.TopLeft()) && HitRect.PtInRect(ItemRect.BottomRight())) 
			{ 
				nIndex = i; 
				return htItem; 
			} 
		} 
	} 
	return htNothing; 
} 
 
int CTabBarCtrl::InsertItem(int nFolderIndex, int nItemIndex, CString ItemName, int nImageIndex /*= -1*/, DWORD dwExData /*= 0*/) 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	int nIndex = pBarFolder->InsertItem(nItemIndex, ItemName, nImageIndex, dwExData); 
	DWORD lpparam = nIndex & 0x0000ffff; 
	DWORD dwtemp = nFolderIndex & 0x0000ffff; 
	lpparam += dwtemp << 16; 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_INSERTITEM, (LPARAM)lpparam); 
	return nIndex; 
} 
 
void CTabBarCtrl::PaintItems(CDC *pDrawDC, int nFolderIndex, CRect LimitRect) 
{ 
	AssertFolderIndex(nFolderIndex); 
	ASSERT_VALID(pDrawDC); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CRect InsideRect; 
	GetInsideRect(InsideRect); 
	int nDC = pDrawDC->SaveDC(); 
	CRgn ItemsRegion; 
	ItemsRegion.CreateRectRgnIndirect(&InsideRect); 
	pDrawDC->SelectClipRgn(&ItemsRegion); 
	ItemsRegion.DeleteObject(); 
	for(int i = 0; i < pBarFolder->GetItemCount(); i++) 
	{ 
		CRect ItemRect; 
		if(!GetItemRect(ItemRect, i, nFolderIndex)) 
			return; 
		if(ItemRect.top > LimitRect.bottom) 
			break; 
		else 
			DrawItem(pDrawDC, nFolderIndex, ItemRect, i); 
	} 
	pDrawDC->RestoreDC(nDC); 
} 
 
void CTabBarCtrl::RemoveFolder(int nFolderIndex) 
{ 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	if(pBarFolder->m_pChildWnd) 
		pBarFolder->m_pChildWnd->SendMessage(WM_CLOSE); 
	delete pBarFolder; 
	m_FolderList.RemoveAt(nFolderIndex); 
	if(m_nSelFolder >= nFolderIndex) 
		m_nSelFolder = nFolderIndex - 1; 
	if(m_nSelFolder < 0 && m_FolderList.GetSize() > 0) 
		m_nSelFolder = 0; 
	Invalidate(FALSE); 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_REMOVEFOLDER, (LPARAM)nFolderIndex); 
} 
 
void CTabBarCtrl::RemoveItem(int nItemIndex, int nFolderIndex) 
{ 
	AssertItemIndex(nItemIndex, nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	delete pBarItem; 
	pBarFolder->m_ItemList.RemoveAt(nItemIndex); 
	CRect Rect; 
	GetInsideRect(Rect); 
	InvalidateRect(Rect, FALSE); 
	DWORD lpparam = nItemIndex & 0x0000ffff; 
	DWORD dwtemp = nFolderIndex & 0x0000ffff; 
	lpparam += dwtemp << 16; 
	GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_REMOVEITEM, (LPARAM)lpparam); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Diagnostics 
 
void CTabBarCtrl::AssertFolderIndex(int nFolderIndex) const 
{ 
#ifdef _DEBUG 
	ASSERT(m_FolderList.GetSize() > 0); 
	ASSERT(nFolderIndex >= 0 && nFolderIndex < m_FolderList.GetSize()); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	ASSERT(pBarFolder); 
#endif 
} 
 
void CTabBarCtrl::AssertItemIndex(int nItemIndex, int nFolderIndex) const 
{ 
#ifdef _DEBUG 
	AssertFolderIndex(nFolderIndex); 
	CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(nFolderIndex); 
	ASSERT(pBarFolder); 
	ASSERT(pBarFolder->m_ItemList.GetSize() > 0); 
	ASSERT(nItemIndex >= 0 && nItemIndex < pBarFolder->m_ItemList.GetSize()); 
	CTabBarItem* pBarItem = (CTabBarItem*)pBarFolder->m_ItemList.GetAt(nItemIndex); 
	ASSERT(pBarItem); 
#endif 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Message handlers 
 
void CTabBarCtrl::OnAddFolder() 
{ 
	CFolderAddDlg dlg; 
	if(dlg.DoModal() == IDOK) 
		AddFolder(dlg.m_AddFolderName); 
	Invalidate(FALSE); 
} 
 
void CTabBarCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint Point) 
{ 
	HideToolTip(); 
	CMenu* PopupMenu = GetMenu(); 
	PopupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, Point.x, Point.y, this); 
	PopupMenu->DestroyMenu(); 
} 
 
int CTabBarCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	CWnd::OnCreate(lpCreateStruct); 
	CreateToolTip(); 
	return TRUE; 
} 
 
long CTabBarCtrl::OnEndFolderEdit(WPARAM wParam, LPARAM lParam) 
{ 
	if(wParam == NM_TB_FOLDERENDEDIT) 
	{ 
		CFolderEdit* pEdit = (CFolderEdit*)lParam; 
		ReleaseCapture(); 
		int nIndex = pEdit->m_nIndex; 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_FOLDERENDEDIT, (LPARAM)nIndex); 
		SetFolderText(nIndex, pEdit->m_EditString); 
		CRect FolderRect; 
		GetFolderRect(FolderRect, nIndex); 
		InvalidateRect(FolderRect, FALSE); 
		SetCapture(); 
	} 
	return 0; 
} 
 
BOOL CTabBarCtrl::OnEraseBkgnd(CDC* /*pDrawDC*/) 
{ 
	return TRUE; 
} 
 
void CTabBarCtrl::OnLButtonDown(UINT nFlags, CPoint Point)  
{ 
	// get the focus 
	if(GetFocus() != this) 
		SetFocus(); 
	// capture the cursor 
	if(::GetCapture() == NULL) 
	{ 
		SetCapture(); 
		ASSERT(this == GetCapture()); 
	} 
	int nIndex, ht = HitTestEx(Point, nIndex); 
	// handle if the folders is hit 
	if(ht == htFolder) 
		SetSelectedFolder(nIndex); 
	// handle if the items is hit 
	if(ht == htItem) 
	{ 
		CTabBarFolder* pBarFolder = (CTabBarFolder*)m_FolderList.GetAt(m_nSelFolder); 
		CTabBarItem* pBarItem = (CTabBarItem*)(pBarFolder->m_ItemList.GetAt(nIndex)); 
		if(pBarItem->m_bSelected) 
		{ 
			if(!DragItem(Point, nIndex)) 
				SelectItem(nIndex); 
		} 
		else 
		{ 
			SelectItem(nIndex); 
			DragItem(Point, nIndex); 
		} 
	} 
	CWnd::OnLButtonDown(nFlags, Point); 
} 
 
void CTabBarCtrl::OnMouseMove(UINT nFlags, CPoint Point)  
{ 
	// get the focus 
	if(GetFocus() != this) 
		SetFocus(); 
	// capture the cursor 
	if(GetCapture() == NULL) 
	{ 
		SetCapture(); 
		ASSERT(this == GetCapture()); 
	} 
	// release the cursor if the cursor is not in the window client rectangle 
	CRect ClientRect; 
	GetClientRect(&ClientRect); 
	if(!ClientRect.PtInRect(Point)) 
	{ 
		ReleaseCapture(); 
		HighlightFolder(-1); 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ONFOLDER, -1); 
		HighlightItem(-1); 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ONITEM, -1); 
		return; 
	} 
	// check if the mouse hit on folders or items 
	int nIndex, ht = HitTestEx(Point, nIndex); 
	if(ht != htFolder && GetHightedFolder() != -1) 
	{ 
		SetCursor(LoadCursor(NULL, IDC_ARROW)); 
		HighlightFolder(-1); 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ONFOLDER, -1); 
	} 
	if(ht != htItem && GetHightedItem(m_nSelFolder) != -1) 
	{ 
		SetCursor(LoadCursor(NULL, IDC_ARROW)); 
		HighlightItem(-1); 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ONITEM, -1); 
	} 
	if(ht == htFolder && GetHightedFolder() != nIndex) 
	{ 
		SetCursor(m_hHandCursor); 
		HighlightFolder(nIndex); 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ONFOLDER, nIndex); 
	} 
	if(ht == htItem) 
	{ 
		if(GetHightedItem(m_nSelFolder) != nIndex) 
		{ 
			SetCursor(m_hHandCursor); 
			HighlightItem(nIndex); 
			DWORD lpparam = nIndex & 0x0000ffff; 
			DWORD dwtemp = m_nSelFolder & 0x0000ffff; 
			lpparam += dwtemp << 16; 
			GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_ONITEM, (LPARAM)lpparam); 
		} 
	} 
	CWnd::OnMouseMove(nFlags, Point); 
} 
 
void CTabBarCtrl::OnPaint()  
{ 
	CPaintDC DrawDC(this); 
	// create the memory device context 
	CRect ClientRect; 
	GetClientRect(&ClientRect); 
	CDC MemDC; 
	MemDC.CreateCompatibleDC(&DrawDC); 
	CBitmap Bitmap; 
	Bitmap.CreateCompatibleBitmap(&DrawDC, ClientRect.Width(), ClientRect.Height()); 
	CBitmap* pOldBitmap = MemDC.SelectObject(&Bitmap); 
	// draw all folders on the memory device context 
	CRect FolderRect; 
	for(int i = 0; i < m_FolderList.GetSize(); i++) 
	{ 
		GetFolderRect(FolderRect, i); 
		DrawFolder(&MemDC, i, FolderRect); 
	} 
	CRect ChildRect; 
	GetInsideRect(ChildRect); 
	if(!GetFolderChild(m_nSelFolder)) 
	{ 
		MemDC.FillSolidRect(ChildRect, m_ChildBackGroundColor); 
		PaintItems(&MemDC, m_nSelFolder, ChildRect); 
	} 
	DrawDC.BitBlt(ClientRect.left, ClientRect.top, ClientRect.Width(), ClientRect.Height(), &MemDC, 0, 0, SRCCOPY); 
	MemDC.SelectObject(pOldBitmap); 
} 
 
void CTabBarCtrl::OnRemoveItem()  
{ 
	if(m_nRButtonHitItemIndex == -1 && m_nRButtonHitFolderIndex != -1) 
	{ 
		RemoveFolder(m_nRButtonHitFolderIndex); 
		m_nRButtonHitFolderIndex = -1; 
	} 
	else if(m_nRButtonHitFolderIndex == -1 && m_nRButtonHitItemIndex != -1) 
	{ 
		RemoveItem(m_nRButtonHitItemIndex, m_nSelFolder); 
		m_nRButtonHitItemIndex = -1; 
	} 
	Invalidate(FALSE);	 
} 
 
void CTabBarCtrl::OnRenameItem()  
{ 
	if(m_nRButtonHitItemIndex == -1 && m_nRButtonHitFolderIndex != -1) 
		OnStartFolderEdit(m_nRButtonHitFolderIndex); 
} 
 
void CTabBarCtrl::OnSize(UINT nType, int cx, int cy)  
{ 
	CWnd::OnSize(nType, cx, cy); 
	CRect ChildRect; 
	GetInsideRect(ChildRect); 
	for(int i = 0; i < GetFolderCount(); i++) 
	{ 
		CWnd* pWnd = GetFolderChild(i); 
		if(pWnd) 
			pWnd->SetWindowPos(0, ChildRect.left, ChildRect.top, ChildRect.Width(), ChildRect.Height(), SWP_NOZORDER); 
	} 
} 
 
void CTabBarCtrl::OnLButtonDblClk(UINT nFlags, CPoint Point) 
{ 
	int nIndex, ht = HitTestEx(Point, nIndex); 
	if(ht == htItem) 
	{ 
		DWORD lpparam = nIndex & 0x0000ffff; 
		DWORD dwtemp = m_nSelFolder & 0x0000ffff; 
		lpparam += dwtemp << 16; 
		GetOwner()->SendMessage(WM_TABBARCTRL_NOTIFY, NM_TB_DBLCLKITEM, (LPARAM)lpparam); 
	} 
	CWnd::OnLButtonDblClk(nFlags, Point); 
}