www.pudn.com > TabBar.rar > TabBarCtrl.cpp
// 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);
}