298 lines
7.6 KiB
C++
298 lines
7.6 KiB
C++
// 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();
|
|
}
|