No problem, here goes
The header file:
#ifndef ___LISTCTRLHDOD_H___
#define ___LISTCTRLHDOD_H___
#pragma once
class CColumnData : public CObject
{
public:
CColumnData()
{
m_bHidden = FALSE;
m_bDisableHide = FALSE;
m_bResizeable = TRUE;
m_bSortable = TRUE;
m_iMinWidth = 30;
m_cstrToolTip = _T("");
m_iFormat = LVCFMT_LEFT;
m_iDefWidth = 0;
m_iCurWidth = 0;
}
BOOL m_bHidden;
BOOL m_bDisableHide;
BOOL m_bResizeable;
BOOL m_bSortable;
int m_iMinWidth;
CString m_cstrToolTip;
int m_iFormat;
int m_iDefWidth;
int m_iCurWidth;
};
class CHeaderCtrlHDOD : public CHeaderCtrl
{
friend class CListCtrlHDOD;
public:
DECLARE_DYNAMIC(CHeaderCtrlHDOD)
CHeaderCtrlHDOD();
virtual ~CHeaderCtrlHDOD();
protected:
int m_iHeight;
CFont m_Font;
float m_fFontHeight;
COLORREF m_crText;
COLORREF m_crLineLight;
COLORREF m_crLineDark;
COLORREF m_crBackStart;
COLORREF m_crBackEnd;
public:
void SetHeight(int iHeight);
protected:
BOOL SubclassDlgItem(UINT nID, CWnd* pParent);
DECLARE_MESSAGE_MAP()
afx_msg void OnDestroy();
afx_msg LRESULT OnLayout(WPARAM wParam, LPARAM lParam);
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnHdnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnHdnItemDblClick(NMHDR* pNMHDR, LRESULT* pResult);
};
class CListCtrlHDOD : public CListCtrl
{
friend class CHeaderCtrlHDOD;
public:
DECLARE_DYNAMIC(CListCtrlHDOD)
CListCtrlHDOD();
virtual ~CListCtrlHDOD();
protected:
CHeaderCtrlHDOD m_HeaderCtrl;
int m_iSortCol;
bool m_bSortAsc;
int m_iItemHeight;
CString m_cstrFontName;
float m_fItemFontHeight;
float m_fMenuFontHeight;
COLORREF m_crItemText;
COLORREF m_crDisItemText;
COLORREF m_crSelItemText;
COLORREF m_crItemBack;
COLORREF m_crSelItemBack;
COLORREF m_crMenuBack;
COLORREF m_crMenuBorder;
COLORREF m_crMenuBarStart;
COLORREF m_crMenuBarEnd;
int m_iMenuItemWidth;
CMenu m_HeaderMenu;
PFNLVCOMPARE m_pfnCompareFunc;
public:
int GetSortColumn(){return m_iSortCol;}
void SetSortColumn(int i){m_iSortCol=i;}
bool GetSortAscending(){return m_bSortAsc;}
void SetSortAscending(bool b){m_bSortAsc=b;}
int GetItemHeight(){return m_iItemHeight;}
void SetItemHeight(int iHeight);
COLORREF GetItemTextColor(){return m_crItemText;}
void SetItemTextColor(COLORREF cr){__SET_VIS_PROP(m_crItemText, cr)};
COLORREF GetDisabledItemTextColor(){return m_crDisItemText;}
void SetDisabledItemTextColor(COLORREF cr){__SET_VIS_PROP(m_crDisItemText, cr)};
COLORREF GetSelectedItemTextColor(){return m_crSelItemText;}
void SetSelectedItemTextColor(COLORREF cr){__SET_VIS_PROP(m_crSelItemText, cr)};
COLORREF GetItemBackColor(){return m_crItemBack;}
void SetItemBackColor(COLORREF cr){__SET_VIS_PROP(m_crItemBack, cr)};
COLORREF GetSelectedItemBackColor(){return m_crSelItemBack;}
void SetSelectedItemBackColor(COLORREF cr){__SET_VIS_PROP(m_crSelItemBack, cr)};
void SetCompareFunction(PFNLVCOMPARE pfn){m_pfnCompareFunc = pfn;}
int GetHeaderHeight(){return m_HeaderCtrl.m_iHeight;}
void SetHeaderHeight(int iHeight){m_HeaderCtrl.SetHeight(iHeight);}
float GetHeaderFontHeight(){return m_HeaderCtrl.m_fFontHeight;}
void SetHeaderFontHeight(float fHeight){m_HeaderCtrl.m_fFontHeight=fHeight;}
int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat,
int nWidth, int nSubItem, BOOL bHidden = FALSE, BOOL bDisableHide = FALSE,
BOOL bResizeable = TRUE, BOOL bSortable = TRUE, int iMinWidth = 30,
CString cstrToolTip = _T(""));
BOOL DeleteColumn(int nCol);
void SortList();
protected:
static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
virtual void PreSubclassWindow();
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
afx_msg void OnDestroy();
afx_msg void OnPaint();
afx_msg BOOL OnLvnColumnClick(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg BOOL OnLvnItemChanged(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnHdnBegintrack(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnHdnTrack(NMHDR* pNMHDR, LRESULT *pResult);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
afx_msg void OnDrawItem(int nIDCtl, DRAWITEMSTRUCT* pDI);
afx_msg void OnMeasureItem(int nIDCtl, MEASUREITEMSTRUCT* pMI);
afx_msg void MeasureItem(MEASUREITEMSTRUCT* pMI);
};
#endif // ___LISTCTRLHDOD_H___
The cpp file:
#include "stdafx.h"
#include "ListCtrlHDOD.h"
#include "DbConfig.h"
BEGIN_MESSAGE_MAP(CHeaderCtrlHDOD, CHeaderCtrl)
ON_WM_DESTROY()
ON_MESSAGE(HDM_LAYOUT, &CHeaderCtrlHDOD::OnLayout)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_SETCURSOR()
ON_NOTIFY(HDN_BEGINDRAG, 0, &CHeaderCtrlHDOD::OnHdnBeginDrag)
ON_NOTIFY(HDN_ITEMDBLCLICKA, 0, &CHeaderCtrlHDOD::OnHdnItemDblClick)
ON_NOTIFY(HDN_ITEMDBLCLICKW, 0, &CHeaderCtrlHDOD::OnHdnItemDblClick)
END_MESSAGE_MAP()
IMPLEMENT_DYNAMIC(CHeaderCtrlHDOD, CHeaderCtrl)
CHeaderCtrlHDOD::CHeaderCtrlHDOD()
{
m_iHeight = ((CApp*)AfxGetApp())->m_iListHeaderHeight;
m_fFontHeight = ((CApp*)AfxGetApp())->m_fListHeaderFontHeight;
m_crText = ((CApp*)AfxGetApp())->m_crListHeaderText;
m_crLineLight = RGB(255,255,255);
m_crLineDark = RGB(157,157,161);
m_crBackStart = ((CApp*)AfxGetApp())->m_crListHeaderStart;
m_crBackEnd = ((CApp*)AfxGetApp())->m_crListHeaderEnd;
}
CHeaderCtrlHDOD::~CHeaderCtrlHDOD()
{
}
BOOL CHeaderCtrlHDOD::SubclassDlgItem(UINT nID, CWnd* pParent)
{
if(!CHeaderCtrl::SubclassDlgItem(nID, pParent))
return FALSE;
SetHeight(m_iHeight);
return TRUE;
}
void CHeaderCtrlHDOD::OnDestroy()
{
CHeaderCtrl::OnDestroy();
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
while(GetItemCount() > 0)
{
VERIFY(GetItem(0, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
delete pColData;
DeleteItem(0);
}
}
LRESULT CHeaderCtrlHDOD::OnLayout(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam);
HD_LAYOUT& hdl = *(HD_LAYOUT*)lParam;
RECT* prc = hdl.prc;
WINDOWPOS* pwpos = hdl.pwpos;
pwpos->cy = m_iHeight;
prc->top = m_iHeight;
return lResult;
}
void CHeaderCtrlHDOD::OnPaint()
{
CPaintDC dc(this);
CRect rClient;
GetClientRect(&rClient);
CListCtrlHDOD* pParent = (CListCtrlHDOD*)GetParent();
bool bNoSort = ((pParent->GetStyle() & LVS_NOSORTHEADER) == LVS_NOSORTHEADER);
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
CBitmap bmp;
bmp.CreateDiscardableBitmap(&dc,
rClient.Width(), rClient.Height());
dcMem.SelectObject(&bmp);
dcMem.FillSolidRect(rClient, RGB(224,226,235));
Graphics gfx(dcMem.GetSafeHdc());
gfx.SetTextRenderingHint(TextRenderingHintClearTypeGridFit);
gfx.SetSmoothingMode(SmoothingModeAntiAlias);
Color clrBackStart, clrBackEnd;
clrBackStart.SetFromCOLORREF(m_crBackStart);
clrBackEnd.SetFromCOLORREF(m_crBackEnd);
Color clrLineLight, clrLineDark;
clrLineLight.SetFromCOLORREF(m_crLineLight);
clrLineDark.SetFromCOLORREF(m_crLineDark);
Pen pnLineLight(clrLineLight, 1);
Pen pnLineDark(clrLineDark, 1);
for(int x = 0; x < GetItemCount(); x++)
{
CRect rItem;
GetItemRect(x, &rItem);
LVCOLUMN lvc = {0};
lvc.mask = LVCF_FMT;
pParent->GetColumn(x, &lvc);
HDITEM hdi = {0};
TCHAR szBuffer[256] = {_T('\0')};
hdi.pszText = szBuffer;
hdi.cchTextMax = 255;
hdi.mask = HDI_TEXT;
VERIFY(GetItem(x, &hdi));
CString strItemText(hdi.pszText);
LinearGradientBrush brBack(RC2GPR(rItem),
clrBackStart, clrBackEnd,
LinearGradientModeVertical);
gfx.FillRectangle(&brBack, RC2GPR(rItem));
if(!bNoSort)
{
rItem.InflateRect(0, -2, -1, -2);
if(rItem.left > 0) {
gfx.DrawLine(&pnLineDark,
Point(rItem.left, rItem.top),
Point(rItem.left, rItem.bottom));
}
gfx.DrawLine(&pnLineLight,
Point(rItem.right, rItem.top),
Point(rItem.right, rItem.bottom));
rItem.InflateRect(0, 0, -5, 0);
if(x == pParent->m_iSortCol)
{
CRect rMarker(
rItem.right - 10, rItem.CenterPoint().y - 3,
rItem.right, rItem.CenterPoint().y + 3 );
if(pParent->m_bSortAsc)
{
gfx.DrawLine(&pnLineDark,
Point(rMarker.left, rMarker.bottom),
Point(rMarker.right, rMarker.bottom));
gfx.DrawLine(&pnLineDark,
Point(rMarker.left, rMarker.bottom - 1),
Point(rMarker.left + 5, rMarker.top));
gfx.DrawLine(&pnLineLight,
Point(rMarker.right, rMarker.bottom - 1),
Point(rMarker.right - 5, rMarker.top));
}
else
{
gfx.DrawLine(&pnLineDark,
Point(rMarker.left, rMarker.top),
Point(rMarker.right, rMarker.top));
gfx.DrawLine(&pnLineDark,
Point(rMarker.left, rMarker.top + 1),
Point(rMarker.left + 5, rMarker.bottom));
gfx.DrawLine(&pnLineLight,
Point(rMarker.right, rMarker.top + 1),
Point(rMarker.right - 5, rMarker.bottom));
}
rItem.right -= 11;
}
}
rItem.InflateRect(-2, -2, 0, -2);
if(strItemText.GetLength() > 0)
{
Color clrText;
clrText.SetFromCOLORREF(m_crText);
SolidBrush brItemText(clrText);
Font fntItem(CT2OLE(pParent->m_cstrFontName),
m_fFontHeight, FontStyleRegular);
StringFormat strfmt;
strfmt.SetAlignment(StringAlignmentNear);
if(lvc.fmt & LVCFMT_CENTER)
strfmt.SetAlignment(StringAlignmentCenter);
if(lvc.fmt & LVCFMT_RIGHT)
strfmt.SetAlignment(StringAlignmentFar);
strfmt.SetLineAlignment(StringAlignmentCenter);
strfmt.SetTrimming(StringTrimmingEllipsisCharacter);
gfx.DrawString(CT2OLE(strItemText),
strItemText.GetLength(), &fntItem,
RC2GPRF(rItem), &strfmt, &brItemText);
}
}
dc.BitBlt(0, 0, rClient.Width(), rClient.Height(), &dcMem, 0, 0, SRCCOPY);
}
BOOL CHeaderCtrlHDOD::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
BOOL CHeaderCtrlHDOD::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT msg)
{
CPoint pt;
GetCursorPos(&pt);
ScreenToClient(&pt);
HDHITTESTINFO hhti = {0};
hhti.pt.x = pt.x;
hhti.pt.y = pt.y;
SendMessage(HDM_HITTEST, 0, (LPARAM)&hhti);
if(hhti.iItem != -1)
{
HDITEM hdi = {0};
hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_LPARAM;
VERIFY(GetItem(hhti.iItem, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
if((hdi.cxy <= 0) || (!pColData->m_bResizeable))
return 1;
}
return CHeaderCtrl::OnSetCursor(pWnd, nHitTest, msg);
}
void CHeaderCtrlHDOD::OnHdnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMHEADER phdr = reinterpret_cast<lpnmheader>(pNMHDR);
*pResult = 0;
}
void CHeaderCtrlHDOD::OnHdnItemDblClick(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMHEADER phdr = reinterpret_cast<lpnmheader>(pNMHDR);
*pResult = 0;
}
void CHeaderCtrlHDOD::SetHeight(int iHeight)
{
m_iHeight = iHeight;
return;
}
BEGIN_MESSAGE_MAP(CListCtrlHDOD, CListCtrl)
ON_WM_DESTROY()
ON_WM_PAINT()
ON_WM_CONTEXTMENU()
ON_WM_DRAWITEM()
ON_WM_MEASUREITEM()
ON_WM_MEASUREITEM_REFLECT()
ON_NOTIFY_REFLECT_EX(LVN_COLUMNCLICK, OnLvnColumnClick)
ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, OnLvnItemChanged)
ON_NOTIFY(HDN_BEGINTRACKA, 0, OnHdnBegintrack)
ON_NOTIFY(HDN_BEGINTRACKW, 0, OnHdnBegintrack)
ON_NOTIFY(HDN_TRACKA, 0, OnHdnTrack)
ON_NOTIFY(HDN_TRACKW, 0, OnHdnTrack)
END_MESSAGE_MAP()
IMPLEMENT_DYNAMIC(CListCtrlHDOD, CListCtrl)
CListCtrlHDOD::CListCtrlHDOD()
{
m_iSortCol = 0;
m_bSortAsc = true;
m_cstrFontName = ((CApp*)AfxGetApp())->m_cstrFontName;
m_fItemFontHeight = 8;
m_fMenuFontHeight = 8;
m_crItemText = RGB(0,0,0);
m_crDisItemText = RGB(128,128,128);
m_crSelItemText = RGB(255,255,255);
m_crItemBack = RGB(255,255,255);
m_crSelItemBack = RGB(10,36,106);
m_crMenuBack = RGB(255,255,255);
m_crMenuBorder = RGB(128,128,128);
m_crMenuBarStart = ((CApp*)AfxGetApp())->m_crGradStart;
m_crMenuBarEnd = ((CApp*)AfxGetApp())->m_crGradEnd;
m_iMenuItemWidth = 0;
m_pfnCompareFunc = CListCtrlHDOD::CompareFunc;
}
CListCtrlHDOD::~CListCtrlHDOD()
{
}
void CListCtrlHDOD::PreSubclassWindow()
{
CListCtrl::PreSubclassWindow();
DWORD dwStyle = GetStyle();
if(dwStyle & LVS_AUTOARRANGE)
{
TRACE(_T("The CListCtrlHDOD class cannot have the LVS_AUTOARRANGE style\n"));
ASSERT(0);
}
if(dwStyle & LVS_OWNERDATA)
{
TRACE(_T("The CListCtrlHDOD class cannot have the LVS_OWNERDATA style\n"));
ASSERT(0);
}
if(!(dwStyle & LVS_REPORT))
{
TRACE(_T("The CListCtrlHDOD class must have the LVS_REPORT style\n"));
ASSERT(0);
}
}
BOOL CListCtrlHDOD::OnCommand(WPARAM wParam, LPARAM lParam)
{
if(HIWORD(wParam) == 0)
{
int iCol = LOWORD(wParam);
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
VERIFY(m_HeaderCtrl.GetItem(iCol, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
if(GetColumnWidth(iCol) == 0)
SetColumnWidth(iCol, pColData->m_iCurWidth);
else
SetColumnWidth(iCol, 0);
}
return CListCtrl::OnCommand(wParam, lParam);
}
void CListCtrlHDOD::OnDestroy()
{
CListCtrl::OnDestroy();
}
void CListCtrlHDOD::OnPaint()
{
if(!(GetStyle() & LVS_OWNERDRAWFIXED))
{
CListCtrl::Default();
return;
}
CPaintDC dc(this);
CRect rClient;
GetClientRect(&rClient);
CRect rView = rClient;
int iHOffset = GetScrollPos(SB_HORZ);
int iVOffset = GetScrollPos(SB_VERT);
rView.OffsetRect(iHOffset, iVOffset);
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
CBitmap bmpMem;
bmpMem.CreateDiscardableBitmap(&dc,
rClient.Width(), rClient.Height());
dcMem.SelectObject(&bmpMem);
dcMem.FillSolidRect(rClient, m_crItemBack);
Graphics gfx(dcMem.GetSafeHdc());
Color clrBack, clrText;
Font fnt(CT2OLE(m_cstrFontName), m_fItemFontHeight, FontStyleRegular);
gfx.SetInterpolationMode(InterpolationModeHighQualityBicubic);
gfx.SetTextRenderingHint(TextRenderingHintAntiAlias);
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
ASSERT(pHeaderCtrl);
for(int iItem = 0; iItem < GetItemCount(); iItem ++)
{
CRect rItem;
GetItemRect(iItem, &rItem, LVIR_BOUNDS);
if((rItem.bottom < rView.top) || (rItem.top > rView.bottom))
continue;
LV_ITEM lvi = {0};
lvi.mask = LVIF_STATE;
lvi.iItem = iItem;
lvi.stateMask = 0xFFFF;
GetItem(&lvi);
bool bSelected = ((lvi.state & LVIS_SELECTED) == LVIS_SELECTED);
clrBack.SetFromCOLORREF(bSelected ? m_crSelItemBack : m_crItemBack);
clrText.SetFromCOLORREF(bSelected ? m_crSelItemText : m_crItemText);
SolidBrush brBack(clrBack);
SolidBrush brText(clrText);
for(int iCol = 0; iCol < pHeaderCtrl->GetItemCount(); iCol ++)
{
LVCOLUMN lvc = {0};
lvc.mask = LVCF_FMT;
GetColumn(iCol, &lvc);
CRect rSubItem;
GetSubItemRect(iItem, iCol, LVIR_LABEL, rSubItem);
gfx.FillRectangle(&brBack, RC2GPRF(rSubItem));
if(lvc.fmt & LVCFMT_IMAGE)
{
LV_ITEM lvisi = {0};
lvisi.mask = LVIF_IMAGE;
lvisi.iItem = iItem;
lvisi.iSubItem = iCol;
GetItem(&lvisi);
if(lvisi.iImage >= 0)
{
CImageList* pIL = GetImageList(LVSIL_SMALL);
if(pIL)
{
int cx = 0;
int cy = 0;
if(ImageList_GetIconSize(pIL->GetSafeHandle(), &cx, &cy))
{
CPoint pt(
rSubItem.left + ((rSubItem.Width() - cx) / 2),
rSubItem.top + ((rSubItem.Height() - cy) / 2));
CSize sz(cx, cy);
pIL->DrawEx(&dcMem, lvisi.iImage, pt, sz, CLR_NONE, CLR_NONE, ILD_TRANSPARENT);
if(iCol > 0)
rSubItem.left += (cx + 2);
}
}
}
}
CString cstrText = GetItemText(iItem, iCol);
if(cstrText.IsEmpty())
continue;
StringFormat strfmt;
strfmt.SetAlignment(StringAlignmentNear);
strfmt.SetLineAlignment(StringAlignmentCenter);
if(lvc.fmt & LVCFMT_CENTER)
strfmt.SetAlignment(StringAlignmentCenter);
if(lvc.fmt & LVCFMT_RIGHT)
strfmt.SetAlignment(StringAlignmentFar);
strfmt.SetFormatFlags(StringFormatFlagsNoWrap);
strfmt.SetTrimming(StringTrimmingEllipsisCharacter);
gfx.DrawString(CT2OLE(cstrText),
cstrText.GetLength(), &fnt,
RC2GPRF(rSubItem), &strfmt, &brText);
}
}
dc.BitBlt(0, 0, rClient.Width(), rClient.Height(), &dcMem, 0, 0, SRCCOPY);
}
BOOL CListCtrlHDOD::OnLvnColumnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<lpnmlistview>(pNMHDR);
*pResult = 0;
if(m_pfnCompareFunc == NULL)
return FALSE;
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
ASSERT(pHeaderCtrl);
CRect rSortItem;
pHeaderCtrl->GetItemRect(m_iSortCol, &rSortItem);
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
VERIFY(pHeaderCtrl->GetItem(pNMLV->iSubItem, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
if(!pColData->m_bSortable)
return FALSE;
if(m_iSortCol == pNMLV->iSubItem)
{
m_bSortAsc = !m_bSortAsc;
InvalidateRect(rSortItem);
}
else
{
m_iSortCol = pNMLV->iSubItem;
CRect rNewItem;
pHeaderCtrl->GetItemRect(m_iSortCol, &rNewItem);
InvalidateRect(rSortItem);
InvalidateRect(rNewItem);
}
SortList();
return FALSE;
}
BOOL CListCtrlHDOD::OnLvnItemChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
NM_LISTVIEW* pNMLV = (NM_LISTVIEW*)pNMHDR;
*pResult = 0;
if(GetStyle() & LVS_OWNERDRAWFIXED)
{
CRect rItem;
GetItemRect(pNMLV->iItem, &rItem, LVIR_BOUNDS);
InvalidateRect(rItem);
}
return FALSE;
}
void CListCtrlHDOD::OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast<lpnmheader>(pNMHDR);
*pResult = 0;
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
VERIFY(m_HeaderCtrl.GetItem(phdr->iItem, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
if((!pColData->m_bResizeable) || (GetColumnWidth(phdr->iItem) == 0))
*pResult = 1;
}
void CListCtrlHDOD::OnHdnTrack(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast<lpnmheader>(pNMHDR);
*pResult = 0;
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
VERIFY(m_HeaderCtrl.GetItem(phdr->iItem, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
if(phdr->pitem->cxy < pColData->m_iMinWidth)
phdr->pitem->cxy = pColData->m_iMinWidth;
pColData->m_iCurWidth = phdr->pitem->cxy;
}
void CListCtrlHDOD::OnContextMenu(CWnd* pWnd, CPoint point)
{
CPoint pt = point;
ScreenToClient(&pt);
CRect rHeader;
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
ASSERT(pHeaderCtrl);
pHeaderCtrl->GetClientRect(&rHeader);
if(!rHeader.PtInRect(pt))
return;
if(!m_HeaderMenu.CreatePopupMenu())
return;
m_iMenuItemWidth = 0;
Font fnt(CT2OLE(m_cstrFontName), m_fMenuFontHeight, FontStyleRegular);
Graphics gfx(::GetDC(NULL));
for(int x = 0; x < pHeaderCtrl->GetItemCount(); x++)
{
HDITEM hdi = {0};
TCHAR szText[256] = {_T('\0')};
hdi.pszText = szText;
hdi.cchTextMax = 255;
hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_LPARAM;
VERIFY(pHeaderCtrl->GetItem(x, &hdi));
StringReplace(hdi.pszText, -1, _T('\n'), _T(' '));
UINT nFlags = MF_BYPOSITION|MF_STRING|MF_OWNERDRAW;
CColumnData* pColData = (CColumnData*)hdi.lParam;
if(!pColData->m_bDisableHide)
nFlags |= ((hdi.cxy > 0) ? MF_CHECKED : MF_UNCHECKED);
else
nFlags |= MF_GRAYED;
m_HeaderMenu.InsertMenu(x, nFlags, x, szText);
RectF rect;
CString str(hdi.pszText);
gfx.MeasureString(CT2OLE(str), str.GetLength(), &fnt, RectF(0, 0, 500, 500), &rect);
if(rect.Width > m_iMenuItemWidth)
m_iMenuItemWidth = (int)rect.Width;
}
m_HeaderMenu.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this, 0);
m_HeaderMenu.DestroyMenu();
}
void CListCtrlHDOD::OnDrawItem(int nIDCtl, DRAWITEMSTRUCT* pDI)
{
if(pDI->CtlType != ODT_MENU)
{
CListCtrl::OnDrawItem(nIDCtl, pDI);
return;
}
CDC* pDC = CDC::FromHandle(pDI->hDC);
ASSERT(pDC);
Graphics gfx(pDC->GetSafeHdc());
gfx.SetSmoothingMode(SmoothingModeAntiAlias);
CRect rItem(pDI->rcItem);
UINT nState = pDI->itemState;
BOOL bDisabled = ((nState & ODS_DISABLED)||(nState & ODS_GRAYED));
BOOL bChecked = (nState & ODS_CHECKED);
BOOL bHighlight = ((pDI->itemState & ODS_SELECTED) && (pDI->itemAction & (ODA_SELECT|ODA_DRAWENTIRE)));
if(!(pDI->itemAction & ODA_DRAWENTIRE))
{
int z = 0;
}
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
ASSERT(pHeaderCtrl);
HDITEM hdi = {0};
TCHAR szText[256] = {_T('\0')};
hdi.pszText = szText;
hdi.cchTextMax = 255;
hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_LPARAM;
VERIFY(pHeaderCtrl->GetItem(pDI->itemID, &hdi));
CString strText = szText;
CRect rMenuBar = rItem;
rMenuBar.right = rItem.left + 24;
Color clrMenuBarStart;
clrMenuBarStart.SetFromCOLORREF(m_crMenuBarStart);
Color clrMenuBarEnd;
clrMenuBarEnd.SetFromCOLORREF(m_crMenuBarEnd);
LinearGradientBrush brMenuBar(RC2GPR(rMenuBar),
clrMenuBarStart, clrMenuBarEnd,
LinearGradientModeHorizontal);
gfx.FillRectangle(&brMenuBar, RC2GPR(rMenuBar));
if(bChecked)
{
CRect rCheckBox = rMenuBar;
rCheckBox.InflateRect(-2,-3,-4,-3);
SolidBrush br(Color(20,0,0,128));
gfx.FillRectangle(&br, RC2GPR(rCheckBox));
Pen pnCheckFrame(Color(255,0,0,128), 1);
Pen pnCheckMark(Color(255,0,0,0), 1.5);
gfx.DrawRectangle(&pnCheckFrame, RC2GPR(rCheckBox));
CPoint ptCenter = rCheckBox.CenterPoint();
gfx.DrawLine(&pnCheckMark, ptCenter.x, ptCenter.y + 3, ptCenter.x - 2, ptCenter.y );
gfx.DrawLine(&pnCheckMark, ptCenter.x, ptCenter.y + 3, ptCenter.x + 5, ptCenter.y - 2);
}
CRect rText = rItem;
rText.left += 24;
Color clrBack;
clrBack.SetFromCOLORREF(m_crMenuBack);
SolidBrush brBack(clrBack);
gfx.FillRectangle(&brBack, RC2GPR(rText));
if(strText.GetLength() > 0)
{
rText.left += 2;
Font fnt(CT2OLE(m_cstrFontName), m_fMenuFontHeight, FontStyleRegular);
StringFormat strfmtLC;
strfmtLC.SetAlignment(StringAlignmentNear);
strfmtLC.SetLineAlignment(StringAlignmentCenter);
strfmtLC.SetTrimming(StringTrimmingEllipsisCharacter);
Color clrText;
clrText.SetFromCOLORREF(bDisabled ? m_crDisItemText : m_crItemText);
SolidBrush brItemText(clrText);
gfx.DrawString(CT2OLE(strText), strText.GetLength(),
&fnt, RC2GPRF(rText), &strfmtLC, &brItemText);
}
if(bHighlight)
{
CRect rHighlight = rItem;
rHighlight.InflateRect(-1,-1,-1,-1);
Pen pnHLBorder(Color(255,0,0,0), 1);
SolidBrush brHighlight(Color(80,0,0,128));
gfx.FillRectangle(&brHighlight, RC2GPR(rHighlight));
gfx.DrawRectangle(&pnHLBorder, RC2GPR(rHighlight));
}
}
void CListCtrlHDOD::OnMeasureItem(int nIDCtl, MEASUREITEMSTRUCT* pMI)
{
if(pMI->CtlType == ODT_MENU)
{
pMI->itemHeight = 24;
pMI->itemWidth = (m_iMenuItemWidth + 24);
}
CListCtrl::OnMeasureItem(nIDCtl, pMI);
}
void CListCtrlHDOD::MeasureItem(MEASUREITEMSTRUCT* pMI)
{
pMI->itemHeight = m_iItemHeight;
}
void CListCtrlHDOD::SetItemHeight(int iHeight)
{
if(m_iItemHeight == iHeight)
return;
m_iItemHeight = iHeight;
CRect rThis;
GetWindowRect(&rThis);
WINDOWPOS wp = {0};
wp.hwnd = GetSafeHwnd();
wp.cx = rThis.Width();
wp.cy = rThis.Height();
wp.flags = SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
}
int CListCtrlHDOD::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat,
int nWidth, int nSubItem, BOOL bHidden, BOOL bDisableHide,
BOOL bResizeable, BOOL bSortable, int iMinWidth,
CString cstrToolTip)
{
int iItem = CListCtrl::InsertColumn(nCol,
lpszColumnHeading, nFormat, (bHidden ? 0 : nWidth), nSubItem);
if(iItem < 0)
return iItem;
if(!m_HeaderCtrl.GetSafeHwnd())
VERIFY(m_HeaderCtrl.SubclassDlgItem(0, this));
CColumnData* pColData = new CColumnData;
ASSERT(pColData);
pColData->m_bHidden = bHidden;
pColData->m_bDisableHide = bDisableHide;
pColData->m_bResizeable = bResizeable;
pColData->m_bSortable = bSortable;
pColData->m_iMinWidth = iMinWidth;
pColData->m_cstrToolTip = cstrToolTip;
pColData->m_iFormat = nFormat;
pColData->m_iDefWidth = nWidth;
pColData->m_iCurWidth = nWidth;
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
VERIFY(m_HeaderCtrl.GetItem(nCol, &hdi));
hdi.lParam = (LPARAM)pColData;
VERIFY(m_HeaderCtrl.SetItem(nCol, &hdi));
return iItem;
}
BOOL CListCtrlHDOD::DeleteColumn(int nCol)
{
HDITEM hdi = {0};
hdi.mask = HDI_LPARAM;
VERIFY(m_HeaderCtrl.GetItem(nCol, &hdi));
CColumnData* pColData = (CColumnData*)hdi.lParam;
ASSERT(pColData);
delete pColData;
return CListCtrl::DeleteColumn(nCol);
}
void CListCtrlHDOD::SortList()
{
if(!m_pfnCompareFunc)
return;
SortItems(m_pfnCompareFunc, (DWORD_PTR)this);
}
int CALLBACK CListCtrlHDOD::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CListCtrlHDOD* pThis = (CListCtrlHDOD*)lParamSort;
ASSERT(pThis);
LVFINDINFO lvfi1 = {0};
lvfi1.flags = LVFI_PARAM;
lvfi1.lParam = lParam1;
LVFINDINFO lvfi2 = {0};
lvfi2.flags = LVFI_PARAM;
lvfi2.lParam = lParam2;
int iIndex1 = pThis->FindItem(&lvfi1);
ASSERT(iIndex1 != -1);
int iIndex2 = pThis->FindItem(&lvfi2);
ASSERT(iIndex2 != -1);
CString strItem1 = pThis->GetItemText(iIndex1, pThis->m_iSortCol);
CString strItem2 = pThis->GetItemText(iIndex2, pThis->m_iSortCol);
int iResult = _tcscmp(strItem1, strItem2);
return (pThis->m_bSortAsc ? iResult : (-iResult));
}
</lpnmheader></lpnmheader></lpnmlistview></lpnmheader></lpnmheader>