www.pudn.com > WQDemo.rar > XHeaderCtrl.cpp


// XHeaderCtrl.cpp 
// 
// Author:  Hans Dietrich 
//          hdietrich2@hotmail.com 
// 
// This code is based on "Outlook 98-Style FlatHeader Control"  
// by Maarten Hoeben. 
// 
// See http://www.codeguru.com/listview/FlatHeader.shtml 
// 
// This software is released into the public domain. 
// You are free to use it in any way you like. 
// 
// This software is provided "as is" with no expressed 
// or implied warranty.  I accept no liability for any 
// damage or loss of business that this software may cause. 
// 
/////////////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "XHeaderCtrl.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CXHeaderCtrl 
 
IMPLEMENT_DYNCREATE(CXHeaderCtrl, CHeaderCtrl) 
 
BEGIN_MESSAGE_MAP(CXHeaderCtrl, CHeaderCtrl) 
	//{{AFX_MSG_MAP(CXHeaderCtrl) 
	ON_MESSAGE(HDM_INSERTITEMA, OnInsertItem) 
	ON_MESSAGE(HDM_INSERTITEMW, OnInsertItem) 
	ON_MESSAGE(HDM_DELETEITEM, OnDeleteItem) 
	ON_MESSAGE(HDM_SETIMAGELIST, OnSetImageList) 
	ON_MESSAGE(HDM_LAYOUT, OnLayout) 
	ON_WM_PAINT() 
	ON_WM_SYSCOLORCHANGE() 
	ON_WM_ERASEBKGND() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
/////////////////////////////////////////////////////////////////////////////// 
// ctor 
CXHeaderCtrl::CXHeaderCtrl() 
{ 
	m_bDoubleBuffer = TRUE; 
	m_iSpacing = 6; 
	m_sizeArrow.cx = 8; 
	m_sizeArrow.cy = 8; 
	m_sizeImage.cx = 0; 
	m_sizeImage.cy = 0; 
	m_bStaticBorder = FALSE; 
	m_nDontDropCursor = 0; 
	m_bResizing = FALSE; 
	m_nClickFlags = 0; 
 
	m_cr3DHighLight = ::GetSysColor(COLOR_3DHIGHLIGHT); 
	m_cr3DShadow    = ::GetSysColor(COLOR_3DSHADOW); 
	m_cr3DFace      = ::GetSysColor(COLOR_3DFACE); 
	m_crBtnText     = ::GetSysColor(COLOR_BTNTEXT); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// dtor 
CXHeaderCtrl::~CXHeaderCtrl() 
{ 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// ModifyProperty 
BOOL CXHeaderCtrl::ModifyProperty(WPARAM wParam, LPARAM lParam) 
{ 
	switch(wParam) 
	{ 
		case FH_PROPERTY_SPACING: 
			m_iSpacing = (int)lParam; 
			break; 
 
		case FH_PROPERTY_ARROW: 
			m_sizeArrow.cx = LOWORD(lParam); 
			m_sizeArrow.cy = HIWORD(lParam); 
			break; 
 
		case FH_PROPERTY_STATICBORDER: 
			m_bStaticBorder = (BOOL)lParam; 
			break; 
 
		case FH_PROPERTY_DONTDROPCURSOR: 
			m_nDontDropCursor = (UINT)lParam; 
			break; 
 
		default: 
			return FALSE; 
	} 
 
	Invalidate(); 
	return TRUE; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// DrawCtrl 
void CXHeaderCtrl::DrawCtrl(CDC* pDC) 
{ 
	CRect rectClip; 
	if (pDC->GetClipBox(&rectClip) == ERROR) 
		return; 
 
	CRect rectClient, rectItem; 
	GetClientRect(&rectClient); 
 
    pDC->FillSolidRect(rectClip, m_cr3DFace); 
 
	int iItems = GetItemCount(); 
	ASSERT(iItems >= 0); 
 
	CPen penHighLight(PS_SOLID, 1, m_cr3DHighLight); 
	CPen penShadow(PS_SOLID, 1, m_cr3DShadow); 
	CPen* pPen = pDC->GetCurrentPen(); 
 
	CFont* pFont = pDC->SelectObject(GetFont()); 
 
	pDC->SetBkColor(m_cr3DFace); 
	pDC->SetTextColor(m_crBtnText); 
 
	int iWidth = 0; 
 
	for (int i = 0; i < iItems; i++) 
	{ 
		int iItem = OrderToIndex(i); 
 
		TCHAR szText[FLATHEADER_TEXT_MAX]; 
 
		HDITEM hditem; 
		hditem.mask = HDI_WIDTH|HDI_FORMAT|HDI_TEXT|HDI_IMAGE|HDI_BITMAP; 
		hditem.pszText = szText; 
		hditem.cchTextMax = sizeof(szText); 
		VERIFY(GetItem(iItem, &hditem)); 
 
		VERIFY(GetItemRect(iItem, rectItem)); 
 
		if (rectItem.right >= rectClip.left || rectItem.left <= rectClip.right) 
		{ 
			if (hditem.fmt & HDF_OWNERDRAW) 
			{ 
				DRAWITEMSTRUCT disItem; 
				disItem.CtlType = ODT_BUTTON; 
				disItem.CtlID = GetDlgCtrlID(); 
				disItem.itemID = iItem; 
				disItem.itemAction = ODA_DRAWENTIRE; 
				disItem.itemState = 0; 
				disItem.hwndItem = m_hWnd; 
				disItem.hDC = pDC->m_hDC; 
				disItem.rcItem = rectItem; 
				disItem.itemData = 0; 
 
				DrawItem(&disItem); 
			} 
			else 
			{ 
				rectItem.DeflateRect(m_iSpacing, 0); 
				DrawItem(pDC, rectItem, &hditem); 
				rectItem.InflateRect(m_iSpacing, 0); 
 
				//if (m_nClickFlags & MK_LBUTTON && m_iHotIndex == iItem && m_hdhtiHotItem.flags & HHT_ONHEADER) 
				//	pDC->InvertRect(rectItem); 
			} 
 
			if (i < iItems-1) 
			{ 
				pDC->SelectObject(&penShadow); 
				pDC->MoveTo(rectItem.right-1, rectItem.top+2); 
				pDC->LineTo(rectItem.right-1, rectItem.bottom-2); 
 
				pDC->SelectObject(&penHighLight); 
				pDC->MoveTo(rectItem.right, rectItem.top+2); 
				pDC->LineTo(rectItem.right, rectItem.bottom-2); 
			} 
		} 
 
		iWidth += hditem.cxy; 
	} 
 
	if (iWidth > 0) 
	{ 
		rectClient.right = rectClient.left + iWidth; 
		pDC->Draw3dRect(rectClient, m_cr3DHighLight, m_cr3DShadow); 
	} 
 
	pDC->SelectObject(pFont); 
	pDC->SelectObject(pPen); 
 
	penHighLight.DeleteObject(); 
	penShadow.DeleteObject(); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// DrawItem 
void CXHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT) 
{ 
	ASSERT(FALSE);  // must override for self draw header controls 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// DrawItem 
void CXHeaderCtrl::DrawItem(CDC* pDC, CRect rect, LPHDITEM lphdi) 
{ 
	ASSERT(lphdi->mask & HDI_FORMAT); 
 
	int iWidth = 0; 
 
	CBitmap* pBitmap = NULL; 
	BITMAP BitmapInfo; 
 
	if (lphdi->fmt & HDF_BITMAP) 
	{ 
		ASSERT(lphdi->mask & HDI_BITMAP); 
		ASSERT(lphdi->hbm); 
 
		pBitmap = CBitmap::FromHandle(lphdi->hbm); 
		if (pBitmap) 
			VERIFY(pBitmap->GetObject(sizeof(BITMAP), &BitmapInfo)); 
	} 
 
	rect.left += ((iWidth = DrawImage(pDC, rect, lphdi, FALSE)) != 0) ? iWidth + m_iSpacing : 0; 
	rect.right -= ((iWidth = DrawBitmap(pDC, rect, lphdi, pBitmap, &BitmapInfo, TRUE)) != 0) ?  
		iWidth + m_iSpacing : 0; 
	DrawText(pDC, rect, lphdi); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// DrawImage 
int CXHeaderCtrl::DrawImage(CDC* pDC, CRect rect, LPHDITEM lphdi, BOOL bRight) 
{ 
	CImageList* pImageList = GetImageList(); 
	int iWidth = 0; 
 
	if (lphdi->iImage != XHEADERCTRL_NO_IMAGE) 
	{ 
		if (pImageList) 
		{ 
			if (rect.Width() > 0) 
			{ 
				POINT point; 
 
				point.y = rect.CenterPoint().y - (m_sizeImage.cy >> 1); 
 
				if (bRight) 
					point.x = rect.right - m_sizeImage.cx; 
				else 
					point.x = rect.left; 
 
				SIZE size; 
				size.cx = rect.Width()GetBkColor(); 
 
				// set image list background color to same as header control 
				pImageList->SetBkColor(pDC->GetBkColor()); 
				pImageList->DrawIndirect(pDC, lphdi->iImage, point, size, CPoint(0, 0)); 
				pImageList->SetBkColor(rgb); 
 
				iWidth = m_sizeImage.cx; 
			} 
		} 
	} 
 
	return iWidth; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// DrawBitmap 
int CXHeaderCtrl::DrawBitmap(CDC* pDC,  
								CRect rect,  
								LPHDITEM lphdi,  
								CBitmap* pBitmap,  
								BITMAP* pBitmapInfo,  
								BOOL bRight) 
{ 
	UNUSED_ALWAYS(lphdi); 
 
	int iWidth = 0; 
 
	if (pBitmap) 
	{ 
		iWidth = pBitmapInfo->bmWidth; 
		if (iWidth <= rect.Width() && rect.Width() > 0) 
		{ 
			POINT point; 
 
			point.y = rect.CenterPoint().y - (pBitmapInfo->bmHeight >> 1); 
 
			if (bRight) 
				point.x = rect.right - iWidth; 
			else 
				point.x = rect.left; 
 
			CDC dc; 
			if (dc.CreateCompatibleDC(pDC) == TRUE)  
			{ 
				VERIFY(dc.SelectObject(pBitmap)); 
				iWidth = pDC->BitBlt( 
					point.x, point.y,  
					pBitmapInfo->bmWidth, pBitmapInfo->bmHeight,  
					&dc,  
					0, 0,  
					SRCCOPY 
				) ? iWidth:0; 
			} 
			else  
				iWidth = 0; 
		} 
		else 
			iWidth = 0; 
	} 
 
	return iWidth; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// DrawText 
int CXHeaderCtrl::DrawText(CDC* pDC, CRect rect, LPHDITEM lphdi) 
{ 
	CSize size; 
 
	pDC->SetTextColor(RGB(0,0,255)); 
 
	if (rect.Width() > 0 && lphdi->mask & HDI_TEXT && lphdi->fmt & HDF_STRING) 
	{ 
		size = pDC->GetTextExtent(lphdi->pszText); 
 
		// always center column headers 
		pDC->DrawText(lphdi->pszText, -1, rect,  
			DT_CENTER|DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER); 
	} 
 
	size.cx = rect.Width()>size.cx ? size.cx:rect.Width(); 
	return size.cx>0 ? size.cx:0; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnInsertItem 
LRESULT CXHeaderCtrl::OnInsertItem(WPARAM, LPARAM) 
{ 
	return Default(); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnDeleteItem 
LRESULT CXHeaderCtrl::OnDeleteItem(WPARAM, LPARAM) 
{ 
	return Default(); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnSetImageList 
LRESULT CXHeaderCtrl::OnSetImageList(WPARAM, LPARAM lParam) 
{ 
	CImageList* pImageList; 
	pImageList = CImageList::FromHandle((HIMAGELIST)lParam); 
 
	IMAGEINFO info; 
	if (pImageList->GetImageInfo(0, &info)) 
	{ 
		m_sizeImage.cx = info.rcImage.right - info.rcImage.left; 
		m_sizeImage.cy = info.rcImage.bottom - info.rcImage.top; 
	} 
 
	return Default(); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnLayout 
LRESULT CXHeaderCtrl::OnLayout(WPARAM, LPARAM lParam) 
{ 
	LPHDLAYOUT lphdlayout = (LPHDLAYOUT)lParam; 
 
	if (m_bStaticBorder) 
		lphdlayout->prc->right += GetSystemMetrics(SM_CXBORDER)*2; 
 
	return CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnSysColorChange 
void CXHeaderCtrl::OnSysColorChange()  
{ 
	TRACE(_T("in CXHeaderCtrl::OnSysColorChange\n")); 
 
	CHeaderCtrl::OnSysColorChange(); 
	 
	m_cr3DHighLight = ::GetSysColor(COLOR_3DHIGHLIGHT); 
	m_cr3DShadow    = ::GetSysColor(COLOR_3DSHADOW); 
	m_cr3DFace      = ::GetSysColor(COLOR_3DFACE); 
	m_crBtnText     = ::GetSysColor(COLOR_BTNTEXT); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnEraseBkgnd 
BOOL CXHeaderCtrl::OnEraseBkgnd(CDC* pDC)  
{ 
	UNUSED_ALWAYS(pDC); 
	return TRUE; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// OnPaint 
void CXHeaderCtrl::OnPaint()  
{ 
    CPaintDC dc(this); 
 
    if (m_bDoubleBuffer) 
    { 
        CMemDC MemDC(&dc); 
        DrawCtrl(&MemDC); 
    } 
    else 
        DrawCtrl(&dc); 
}