www.pudn.com > HReportTest.rar > HFlatHeaderCtrl.cpp


// HFlatHeaderCtrl.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "HFlatHeaderCtrl.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CHFlatHeaderCtrl 
 
#define XTWM_INITIAL_UPDATE  WM_USER+1024 
 
static const COLORREF  clr3DFace		= ::GetSysColor( COLOR_3DFACE ); 
static const COLORREF  clr3DShadow		= ::GetSysColor( COLOR_3DSHADOW ); 
static const COLORREF  clr3DHilight		= ::GetSysColor( COLOR_3DHILIGHT ); 
 
/* 
static const COLORREF  clr3DDkShadow	= ::GetSysColor( COLOR_3DDKSHADOW ); 
static const COLORREF  clrBtnText		= ::GetSysColor( COLOR_BTNTEXT ); 
static const COLORREF  clrGrayText		= ::GetSysColor( COLOR_GRAYTEXT ); 
static const COLORREF  clrHighlight		= ::GetSysColor( COLOR_HIGHLIGHT ); 
static const COLORREF  clrHighlightText	= ::GetSysColor( COLOR_HIGHLIGHTTEXT ); 
static const COLORREF  clrMenu			= ::GetSysColor( COLOR_MENU ); 
static const COLORREF  clrMenuText		= ::GetSysColor( COLOR_MENUTEXT ); 
static const COLORREF  clrWindow		= ::GetSysColor( COLOR_WINDOW ); 
static const COLORREF  clrWindowFrame	= ::GetSysColor( COLOR_WINDOWFRAME ); 
static const COLORREF  clrWindowText	= ::GetSysColor( COLOR_WINDOWTEXT ); 
static const COLORREF  clrActiveCaption	= ::GetSysColor( COLOR_ACTIVECAPTION ); 
*/ 
 
CHFlatHeaderCtrl::CHFlatHeaderCtrl() 
{ 
    m_bLBtnDown    = FALSE; 
    m_bAscending   = -1; 
    m_bSortArrow   = FALSE; 
    m_nSortedCol   = -1; 
	m_nOffset	   = 6; 
	m_bInitControl = TRUE; 
} 
 
CHFlatHeaderCtrl::~CHFlatHeaderCtrl() 
{ 
} 
 
IMPLEMENT_DYNAMIC(CHFlatHeaderCtrl, CHeaderCtrl) 
 
BEGIN_MESSAGE_MAP(CHFlatHeaderCtrl, CHeaderCtrl) 
	//{{AFX_MSG_MAP(CHFlatHeaderCtrl) 
	ON_WM_PAINT() 
	ON_WM_CREATE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_ERASEBKGND() 
	ON_WM_WINDOWPOSCHANGED() 
	//}}AFX_MSG_MAP 
	ON_MESSAGE(XTWM_INITIAL_UPDATE, OnInitControl) 
END_MESSAGE_MAP() 
 
void CHFlatHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
{ 
	ASSERT(lpDrawItemStruct != NULL); 
 
	// define some temporary variables. 
	CDC*	pDC			= CDC::FromHandle( lpDrawItemStruct->hDC ); 
	CRect	rcItem		= lpDrawItemStruct->rcItem; 
	CRect	rcIcon		= lpDrawItemStruct->rcItem; 
    int 	nState		= lpDrawItemStruct->itemState; 
	int		nItemID		= lpDrawItemStruct->itemID; 
 
	CWnd* pParentWnd = GetParent(); 
	BOOL bNoSortHeader = ((pParentWnd->GetStyle() & LVS_NOSORTHEADER) == LVS_NOSORTHEADER); 
 
	int nSavedDC = pDC->SaveDC(); 
 
	// Paint the background. 
	pDC->FillSolidRect(rcItem, clr3DFace); 
	pDC->SetBkMode(TRANSPARENT); 
	 
	// Set clipping region to limit drawing within column 
	CRgn rgn; 
	rgn.CreateRectRgnIndirect( &rcItem ); 
	pDC->SelectObject( &rgn ); 
	rgn.DeleteObject(); 
 
	// Get the column text and format 
	TCHAR buf[256]; 
	HD_ITEM hditem; 
	 
	hditem.mask = HDI_TEXT | HDI_FORMAT; 
	hditem.pszText = buf; 
	hditem.cchTextMax = 255; 
	 
	GetItem( nItemID, &hditem ); 
	 
	// Determine format for drawing column label 
	UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP  
		| DT_VCENTER | DT_END_ELLIPSIS ; 
	 
	if( hditem.fmt & HDF_CENTER)  
	{ 
		uFormat |= DT_CENTER; 
	} 
	else if( hditem.fmt & HDF_RIGHT)  
	{ 
		uFormat |= DT_RIGHT; 
	} 
	else  
	{ 
		uFormat |= DT_LEFT; 
	} 
	 
	// Adjust the rect if the mouse button is pressed on it 
	if (nState == ODS_SELECTED && !bNoSortHeader) 
	{ 
		rcItem.left++; 
		rcItem.top += 2; 
		rcItem.right++; 
	} 
 
	// Adjust the rect further if Sort arrow is to be displayed 
	if (nItemID == m_nSortedCol && m_bSortArrow) { 
		rcItem.right -= 3 * m_nOffset; 
	} 
	 
	rcItem.left += m_nOffset; 
	rcItem.right -= m_nOffset; 
 
	// Draw column label 
	if( rcItem.left < rcItem.right ) 
	{ 
		pDC->SelectObject(GetFont()); 
		pDC->DrawText(buf,-1,rcItem, uFormat); 
	} 
 
	// Draw the Sort arrow 
	if(( nItemID == m_nSortedCol ) && m_bSortArrow && !bNoSortHeader) 
	{ 
		// Set up pens to use for drawing the triangle 
		CPen penLite(PS_SOLID, 1, clr3DHilight); 
		CPen penShad(PS_SOLID, 1, clr3DShadow); 
		pDC->SelectObject(&penLite); 
		 
		if (m_bAscending) 
		{ 
			// Draw triangle pointing upwards 
			pDC->MoveTo( rcIcon.right - 2*m_nOffset, m_nOffset-1); 
			pDC->LineTo( rcIcon.right - 3*m_nOffset/2, rcIcon.bottom - m_nOffset ); 
			pDC->LineTo( rcIcon.right - 5*m_nOffset/2-2, rcIcon.bottom - m_nOffset ); 
			pDC->MoveTo( rcIcon.right - 5*m_nOffset/2-1, rcIcon.bottom - m_nOffset-1 ); 
			 
			pDC->SelectObject( &penShad ); 
			pDC->LineTo( rcIcon.right - 2*m_nOffset, m_nOffset-2); 
		} 
		else 
		{ 
			// Draw triangle pointing downwords 
			pDC->MoveTo( rcIcon.right - 3*m_nOffset/2, m_nOffset-1); 
			pDC->LineTo( rcIcon.right - 2*m_nOffset-1, rcIcon.bottom - m_nOffset + 1 ); 
			pDC->MoveTo( rcIcon.right - 2*m_nOffset-1, rcIcon.bottom - m_nOffset ); 
			 
			pDC->SelectObject( &penShad ); 
			pDC->LineTo( rcIcon.right - 5*m_nOffset/2-1, m_nOffset -1 ); 
			pDC->LineTo( rcIcon.right - 3*m_nOffset/2, m_nOffset -1); 
		} 
	} 
 
	pDC->RestoreDC(nSavedDC); 
} 
 
void CHFlatHeaderCtrl::DrawBorders(CDC* pDC, CRect& rect) 
{ 
	int nSavedDC = pDC->SaveDC(); 
 
	// Draw flat style border around entire header. 
	CRect rc(rect); 
	rc.InflateRect(0,0,1,0); 
	pDC->Draw3dRect(rc, clr3DHilight, clr3DShadow); 
 
	// Cover up thick 3D border. 
	rc.DeflateRect(1,1,0,1); 
	pDC->Draw3dRect(rc, clr3DFace, clr3DFace); 
 
	// Create the pens for further cover-up. 
	CPen penLite(PS_SOLID, 1, clr3DHilight); 
	CPen penShad(PS_SOLID, 1, clr3DShadow); 
	CPen penFace(PS_SOLID, 1, clr3DFace); 
	pDC->SelectObject( &penLite ); 
	 
	// Set up the header item struct. 
	HD_ITEM hdi; 
	memset (&hdi, 0, sizeof(HD_ITEM)); 
	hdi.fmt  = HDF_STRING | HDF_LEFT | HDF_OWNERDRAW; 
	hdi.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_ORDER; 
	int cx = 0; 
	 
    long j = GetItemCount(); 
    long i = 0; 
	 
    long * ItemOrders = new long[j]; 
    for( i=0; iSelectObject(&penShad); 
		pDC->MoveTo(cx, 2); 
		pDC->LineTo(cx, rc.bottom-1); 
 
		pDC->SelectObject(&penLite); 
		pDC->MoveTo(cx+1, 2); 
		pDC->LineTo(cx+1, rc.bottom-1); 
 
		pDC->SelectObject(&penFace); 
		pDC->MoveTo(cx-1, 2); 
		pDC->LineTo(cx-1, rc.bottom-1); 
 
		pDC->SelectObject(&penFace); 
		pDC->MoveTo(cx-2, 2); 
		pDC->LineTo(cx-2, rc.bottom-1); 
	} 
	 
	delete [] ItemOrders; 
 
	if (m_bLBtnDown == FALSE) 
	{ 
		pDC->SelectObject(&penShad); 
		pDC->MoveTo(rect.right-1, rect.top); 
		pDC->LineTo(rect.right-1, rect.bottom); 
	} 
	 
	// Cleanup. 
	pDC->RestoreDC(nSavedDC); 
} 
 
LRESULT CHFlatHeaderCtrl::OnInitControl(WPARAM wParam, LPARAM lParam) 
{ 
	UNREFERENCED_PARAMETER(wParam); 
	UNREFERENCED_PARAMETER(lParam); 
 
	if (m_bInitControl) 
	{ 
		m_bInitControl = FALSE; 
 
		CWnd* pParentWnd = GetParent(); 
		ASSERT_VALID(pParentWnd); 
		pParentWnd->ModifyStyle(0, WS_CLIPCHILDREN); 
	} 
 
	return 0; 
} 
 
void CHFlatHeaderCtrl::PreSubclassWindow()  
{ 
	CHeaderCtrl::PreSubclassWindow(); 
	PostMessage(XTWM_INITIAL_UPDATE); 
} 
 
int CHFlatHeaderCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CHeaderCtrl::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	 
	SendMessage(XTWM_INITIAL_UPDATE); 
 
	return 0; 
} 
 
void CHFlatHeaderCtrl::OnPaint()  
{ 
	// background is already filled in gray 
	CPaintDC dc(this); 
 
	// Get the client rect. 
	CRect rectClient; 
	GetClientRect(&rectClient); 
 
	// Paint to a memory device context to help 
	// eliminate screen flicker. 
	CHMemDC memDC(&dc, rectClient); 
 
	// and let the window do its default painting... 
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 ); 
 
	// draw the flat borders. 
	DrawBorders(&memDC, rectClient); 
} 
 
BOOL CHFlatHeaderCtrl::OnEraseBkgnd(CDC* pDC)  
{ 
	UNUSED_ALWAYS(pDC); 
	return FALSE; 
} 
 
void CHFlatHeaderCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	m_bLBtnDown = TRUE; 
	CHeaderCtrl::OnLButtonDown(nFlags, point); 
} 
 
void CHFlatHeaderCtrl::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
	m_bLBtnDown = FALSE; 
	CHeaderCtrl::OnLButtonUp(nFlags, point); 
} 
 
void CHFlatHeaderCtrl::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)  
{ 
	CHeaderCtrl::OnWindowPosChanged(lpwndpos); 
	Invalidate(); 
} 
 
int CHFlatHeaderCtrl::HitTest( CPoint pt ) const 
{ 
	for (int iItem = 0; iItem < GetItemCount(); ++iItem) 
	{ 
		CRect r; 
		Header_GetItemRect(m_hWnd, iItem, &r); 
		 
		if (r.PtInRect(pt)) 
			return iItem; 
	} 
 
	return -1; 
} 
 
void CHFlatHeaderCtrl::SendNotify(int iIndex) 
{ 
	CWnd* pParentWnd = GetParent(); 
	if (pParentWnd && ( 
		pParentWnd->IsKindOf(RUNTIME_CLASS(CListCtrl)) || 
		pParentWnd->IsKindOf(RUNTIME_CLASS(CListView)))) 
	{ 
		CWnd* pOwnerWnd = pParentWnd->GetOwner(); 
		if (pOwnerWnd) 
		{ 
			TCHAR  lpBuffer[256]; 
			 
			HDITEM hdi; 
			hdi.mask       = HDI_TEXT|HDI_BITMAP|HDI_FORMAT|HDI_IMAGE|HDI_LPARAM|HDI_ORDER|HDI_WIDTH; 
			hdi.pszText    = lpBuffer; 
			hdi.cchTextMax = 256; 
			 
			GetItem(iIndex, &hdi); 
			 
			NMHEADER nmh; 
			nmh.hdr.hwndFrom = m_hWnd; 
			nmh.hdr.idFrom   = GetDlgCtrlID(); 
			nmh.hdr.code     = HDN_ITEMCLICK; 
			nmh.iItem        = iIndex; 
			nmh.iButton      = 1; 
			nmh.pitem        = &hdi; 
			 
			// send message to the parent's owner window. 
			pOwnerWnd->SendMessage(WM_NOTIFY,  
				(WPARAM)(int)nmh.hdr.idFrom, (LPARAM)(NMHEADER*)&nmh); 
 
			// then forward to the descendants. 
			pOwnerWnd->SendMessageToDescendants(WM_NOTIFY,  
				(WPARAM)(int)nmh.hdr.idFrom, (LPARAM)(NMHEADER*)&nmh); 
		} 
	} 
} 
 
int CHFlatHeaderCtrl::SetSortImage(int nCol, BOOL bAsc) 
{ 
	int nPrevCol = m_nSortedCol; 
	 
	m_nSortedCol = nCol; 
	m_bAscending = bAsc; 
	 
	// Change the item to ownder drawn 
	HD_ITEM hditem; 
	 
	hditem.mask = HDI_BITMAP | HDI_FORMAT; 
	GetItem( nCol, &hditem ); 
	if (hditem.hbm == NULL) 
	{ 
		hditem.fmt |= HDF_OWNERDRAW; 
		SetItem( nCol, &hditem ); 
		Invalidate(); 
	} 
	 
	return nPrevCol; 
}