// MyHeaderCtrl.cpp : implementation file // #include "stdafx.h" #include "CB32.h" #include "MyHeaderCtrl.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMyHeaderCtrl CMyHeaderCtrl::CMyHeaderCtrl() : marker_rect(0,0,0,0), marker_rect2(0,0,0,0) { m_pWidth = NULL; m_bDragging = FALSE; m_bCheckForDrag = FALSE; m_fpDragCol = NULL; m_pOwnerWnd = NULL; m_nSortCol = -1; } CMyHeaderCtrl::CMyHeaderCtrl(CWnd *pWnd, void (CWnd::*fpDragCol)(int, int)) : marker_rect(0,0,0,0), marker_rect2(0,0,0,0) { m_pWidth = NULL; m_bDragging = FALSE; m_bCheckForDrag = FALSE; m_fpDragCol = fpDragCol; m_pOwnerWnd = pWnd; m_nSortCol = -1; } CMyHeaderCtrl::~CMyHeaderCtrl() { } BEGIN_MESSAGE_MAP(CMyHeaderCtrl, CHeaderCtrl) //{{AFX_MSG_MAP(CMyHeaderCtrl) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_LBUTTONDOWN() ON_WM_DRAWITEM_REFLECT() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyHeaderCtrl message handlers void CMyHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point) { if( (MK_LBUTTON & nFlags) == 0) { // The left mouse button is not pressed - so reset flags m_bCheckForDrag = FALSE; m_bDragging = FALSE; } else if( m_bDragging ) { // Get column number that falls under the mouse int i=0, cx = 0; if( point.x > 0 ) for( i = 0; i < GetItemCount(); i++ ) { if( point.x > cx && point.x < cx + m_pWidth[i] ) break; cx += m_pWidth[i]; } if( i != m_nDropPos ) { m_nDropPos = i; CRect rect; GetWindowRect( &rect ); // Invalidate area occupied by previous marker InvalidateRect( &marker_rect ); InvalidateRect( &marker_rect2 ); // Draw a new marker CClientDC dc(this); POINT pts[3]; POINT pts2[3]; pts[0].x = cx -3; pts[0].y = rect.Height()/2; pts[1].x = cx -8; pts[1].y = rect.Height()-4; pts[2].x = cx -8; pts[2].y = 4; pts2[0].x = cx +1; pts2[0].y = rect.Height()/2; pts2[1].x = cx +6; pts2[1].y = rect.Height()-4; pts2[2].x = cx +6; pts2[2].y = 4; // COLORREF clrBG = GetSysColor(COLOR_ACTIVECAPTION); COLORREF clrBG = RGB(255,0,0); CBrush brush(clrBG); CBrush* pOldBrush = dc.SelectObject(&brush); dc.Polygon( pts, 3 ); dc.Polygon( pts2, 3 ); dc.SelectObject(pOldBrush); // save marker information marker_rect.left = cx - 9; marker_rect.top = rect.Height() -3; marker_rect.right = cx + 9; marker_rect.bottom = 3; marker_rect2.left = cx + 7; marker_rect2.top = rect.Height() -3; marker_rect2.right = cx - 7; marker_rect2.bottom = 3; } return; } else if( m_bCheckForDrag ) { // The mouse button was pressed over a column header // and now the mouse has moved - so start drag m_bCheckForDrag = FALSE; m_bDragging = TRUE; m_nDropPos = m_nDragCol; SetCapture(); // Store information for later use int iCount = GetItemCount(); HD_ITEM hd_item; m_pWidth = new int[iCount]; for( int i = 0; i < iCount; i++ ) { hd_item.mask = HDI_WIDTH; GetItem( i, &hd_item ); m_pWidth[i] = hd_item.cxy; } return; } CHeaderCtrl::OnMouseMove(nFlags, point); } void CMyHeaderCtrl::OnLButtonUp(UINT nFlags, CPoint point) { ASSERT( m_pOwnerWnd != NULL && m_fpDragCol != NULL ); if( m_bDragging ) { m_bDragging = FALSE; delete[] m_pWidth; ReleaseCapture(); Invalidate(); // Call the callback function. if( m_nDragCol != m_nDropPos && m_nDragCol != m_nDropPos -1 ) (m_pOwnerWnd->*m_fpDragCol)( m_nDragCol, m_nDropPos ); } CHeaderCtrl::OnLButtonUp(nFlags, point); } void CMyHeaderCtrl::OnLButtonDown(UINT nFlags, CPoint point) { // Determine if mouse was pressed over a column header HD_HITTESTINFO hd_hittestinfo; hd_hittestinfo.pt = point; SendMessage(HDM_HITTEST, 0, (LPARAM)(&hd_hittestinfo)); if( hd_hittestinfo.flags == HHT_ONHEADER ) { m_nDragCol = hd_hittestinfo.iItem; m_bCheckForDrag = TRUE; } CHeaderCtrl::OnLButtonDown(nFlags, point); } void CMyHeaderCtrl::SetCallback( CWnd* pWnd, void (CWnd::*fpDragCol)(int, int) ) { m_fpDragCol = fpDragCol; m_pOwnerWnd = pWnd; } int CMyHeaderCtrl::SetSortImage(int nCol, BOOL bAsc) { int nPrevCol = m_nSortCol; m_nSortCol = nCol; m_bSortAsc = bAsc; // Change the item to ownder drawn HD_ITEM hditem; hditem.mask = HDI_FORMAT; GetItem( nCol, &hditem ); hditem.fmt |= HDF_OWNERDRAW; SetItem( nCol, &hditem ); // Invalidate header control so that it gets redrawn Invalidate(); return nPrevCol; } void CMyHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC dc; dc.Attach( lpDrawItemStruct->hDC ); // Get the column rect CRect rcLabel( lpDrawItemStruct->rcItem ); // Save DC int nSavedDC = dc.SaveDC(); // Set clipping region to limit drawing within column CRgn rgn; rgn.CreateRectRgnIndirect( &rcLabel ); dc.SelectObject( &rgn ); rgn.DeleteObject(); // Draw the background dc.FillRect(rcLabel, &CBrush(::GetSysColor(COLOR_3DFACE))); // Labels are offset by a certain amount // This offset is related to the width of a space character int offset = dc.GetTextExtent(_T(" "), 1 ).cx*2; // 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( lpDrawItemStruct->itemID, &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( lpDrawItemStruct->itemState == ODS_SELECTED ) { rcLabel.left++; rcLabel.top += 2; rcLabel.right++; } // Adjust the rect further if Sort arrow is to be displayed if( lpDrawItemStruct->itemID == (UINT)m_nSortCol ) { rcLabel.right -= 3 * offset; } rcLabel.left += offset; rcLabel.right -= offset; // Draw column label if( rcLabel.left < rcLabel.right ) dc.DrawText(buf,-1,rcLabel, uFormat); // Draw the Sort arrow if( lpDrawItemStruct->itemID == (UINT)m_nSortCol ) { CRect rcIcon( lpDrawItemStruct->rcItem ); // Set up pens to use for drawing the triangle CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); CPen *pOldPen = dc.SelectObject( &penLight ); if( m_bSortAsc ) { // Draw triangle pointing upwards dc.MoveTo( rcIcon.right - 2*offset, offset-1); dc.LineTo( rcIcon.right - 3*offset/2, rcIcon.bottom - offset ); dc.LineTo( rcIcon.right - 5*offset/2-2, rcIcon.bottom - offset ); dc.MoveTo( rcIcon.right - 5*offset/2-1, rcIcon.bottom - offset-1 ); dc.SelectObject( &penShadow ); dc.LineTo( rcIcon.right - 2*offset, offset-2); } else { // Draw triangle pointing downwords dc.MoveTo( rcIcon.right - 3*offset/2, offset-1); dc.LineTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset + 1 ); dc.MoveTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset ); dc.SelectObject( &penShadow ); dc.LineTo( rcIcon.right - 5*offset/2-1, offset -1 ); dc.LineTo( rcIcon.right - 3*offset/2, offset -1); } // Restore the pen dc.SelectObject( pOldPen ); } // Restore dc dc.RestoreDC( nSavedDC ); // Detach the dc before returning dc.Detach(); }