// XTPHeaderCtrl.cpp : implementation of the CXTPHeaderCtrl class. // // This file is a part of the XTREME CONTROLS MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Common/XTPResourceManager.h" #include "Common/XTPColorManager.h" #include "Common/XTPImageManager.h" #include "../Util/XTPControlTheme.h" #include "Common/XTPDrawHelpers.h" #include "../Defines.h" #include "../Resource.h" #include "../Util/XTPGlobal.h" #include "XTPHeaderCtrlTheme.h" #include "XTPHeaderCtrl.h" #include "../Util/XTPFunctions.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CXTPHeaderCtrl CXTPHeaderCtrl::CXTPHeaderCtrl() : m_iMinSize(0) , m_nPos(0) , m_iOverIndex(-1) , m_nSortedCol(-1) , m_bRTL(DetermineRTL()) , m_bAutoSize(false) , m_bEnableMenus(TRUE) , m_bAscending(TRUE) , m_bLBtnDown(FALSE) , m_bPainted(FALSE) , m_popupMenuID(0) , m_pt(CPoint(0, 0)) , m_pTheme(NULL) { m_pImageManager = NULL; VERIFY(SetTheme(xtpControlThemeDefault)); } CXTPHeaderCtrl::~CXTPHeaderCtrl() { CMDTARGET_RELEASE(m_pTheme); CMDTARGET_RELEASE(m_pImageManager); } void CXTPHeaderCtrl::SetImageManager(CXTPImageManager* pImageManager) { CMDTARGET_RELEASE(m_pImageManager); m_pImageManager = pImageManager; } BEGIN_MESSAGE_MAP(CXTPHeaderCtrl, CHeaderCtrl) //{{AFX_MSG_MAP(CXTPHeaderCtrl) ON_WM_WINDOWPOSCHANGING() ON_WM_SETCURSOR() ON_WM_PAINT() ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient) ON_WM_ERASEBKGND() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_TIMER() ON_WM_DESTROY() ON_WM_RBUTTONDOWN() ON_NOTIFY_REFLECT_EX(HDN_ITEMCHANGING, OnItemchanging) ON_COMMAND(XTP_IDC_SORTASC, OnSortAsc) ON_COMMAND(XTP_IDC_SORTDSC, OnSortDsc) ON_COMMAND(XTP_IDC_ALIGNLEFT, OnAlignLeft) ON_COMMAND(XTP_IDC_ALIGNCENTER, OnAlignCenter) ON_COMMAND(XTP_IDC_ALIGNRIGHT, OnAlignRight) ON_MESSAGE(HDM_LAYOUT, OnLayout) //}}AFX_MSG_MAP ON_MESSAGE(WM_XTP_SETCONTROLTHEME, OnSetTheme) END_MESSAGE_MAP() IMPLEMENT_DYNAMIC(CXTPHeaderCtrl, CHeaderCtrl) ///////////////////////////////////////////////////////////////////////////// // CXTPHeaderCtrl message handlers void CXTPHeaderCtrl::OnThemeChanged() { RecalcLayout(); } BOOL CXTPHeaderCtrl::IsThemeValid() const { return (m_pTheme != NULL); } void CXTPHeaderCtrl::ApplyFieldWidths(int iNewWidth) { CListCtrl* pListCtrl = (CListCtrl*)GetParent(); ASSERT_VALID(pListCtrl); int iItemCount = GetItemCount(); int iFrozenCount = (int)m_arFrozenCols.GetCount(); int iThawedCount = iItemCount - iFrozenCount; if (iThawedCount <= 0) return; int iWidth = iNewWidth/iThawedCount; int iItem; for (iItem = 0; iItem < iItemCount; iItem++) { if (IsColFrozen(iItem)) continue; if (iWidth > m_iMinSize) pListCtrl->SetColumnWidth(iItem, iWidth); iNewWidth -= iWidth; } } void CXTPHeaderCtrl::ResizeColumnsToFit() { FitFieldWidths(0); } void CXTPHeaderCtrl::FitFieldWidths(int iNewWidth) { if (iNewWidth <= 0) { CXTPWindowRect rc(this); iNewWidth = rc.Width(); } // adjust for vertical scroll bar. DWORD dwStyle = ::GetWindowLong(::GetParent(m_hWnd), GWL_STYLE); if ((dwStyle & WS_VSCROLL) == WS_VSCROLL) iNewWidth -= ::GetSystemMetrics(SM_CXVSCROLL); // adjust for frozen columns. iNewWidth -= GetFrozenColWidth(); ApplyFieldWidths(iNewWidth); } void CXTPHeaderCtrl::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) { if (m_bAutoSize) { int iCount = GetItemCount(); if (iCount > 0) { if (GetCapture() != GetParent()) // indicates scrolling { // is the window size changing? CXTPWindowRect rc(this); if (rc.Width() != lpwndpos->cx) { FitFieldWidths(lpwndpos->cx); } } } } else { CHeaderCtrl::OnWindowPosChanging(lpwndpos); } } void CXTPHeaderCtrl::EnableAutoSize(bool bEnable/*=true*/) { m_bAutoSize = bEnable; } void CXTPHeaderCtrl::FreezeColumn(int iCol) { m_arFrozenCols.AddTail(iCol); } void CXTPHeaderCtrl::ThawColumn(int iCol) { for (POSITION pos = m_arFrozenCols.GetHeadPosition(); pos; m_arFrozenCols.GetNext(pos)) { int iNext = m_arFrozenCols.GetAt(pos); if (iNext == iCol) { m_arFrozenCols.RemoveAt(pos); break; } } } void CXTPHeaderCtrl::ThawAllColumns() { m_arFrozenCols.RemoveAll(); } BOOL CXTPHeaderCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if (m_arFrozenCols.GetCount()) { CPoint pt; ::GetCursorPos(&pt); CPoint ptClient = pt; ScreenToClient(&ptClient); HDHITTESTINFO hti; ::ZeroMemory(&hti, sizeof(hti)); hti.pt.x = ptClient.x; hti.pt.y = ptClient.y; int nIndex = (int)::SendMessage(GetSafeHwnd(), HDM_HITTEST, 0L, (LPARAM)&hti); if (nIndex > -1) { // if we are over one of the frozen columns, we can stop if (IsColFrozen(nIndex)) { ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); return TRUE; } else { // determine if the current index is adjacent to a frozen column index. // if columns are resized by dragging to the right, test for the frozen column on the left. // if columns are resized by dragging to the left, test for the frozen column on the right. int iAdjIndex = nIndex + (m_bRTL ? 1 : -1); if ((iAdjIndex > -1) && IsColFrozen(iAdjIndex)) { CRect r; Header_GetItemRect(m_hWnd, nIndex, &r); int nMidPoint = (r.left + (r.Width()/2)); // if columns resize to the right and the point is the right half of the header item... if (!m_bRTL && (ptClient.x <= nMidPoint)) { ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); return TRUE; } // if columns resize to the left and the point is the left half of the header item... else if (m_bRTL && (ptClient.x >= nMidPoint)) { ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); return TRUE; } } } } } return CHeaderCtrl::OnSetCursor(pWnd, nHitTest, message); } BOOL CXTPHeaderCtrl::OnItemchanging(NMHDR* pNMHDR, LRESULT* pResult) { HD_NOTIFY* pHDN = (HD_NOTIFY*)pNMHDR; *pResult = FALSE; if (pHDN && (pHDN->pitem->mask & HDI_WIDTH) != 0) { // if sizing is disabled for this column, keep the user from resizing if (m_arFrozenCols.GetCount() && IsColFrozen(pHDN->iItem)) *pResult = TRUE; // if the column is smaller than the minimum size, keep the user from resizing if (pHDN->pitem->mask & HDI_WIDTH && pHDN->pitem->cxy < m_iMinSize) *pResult = TRUE; } return BOOL(*pResult); } bool CXTPHeaderCtrl::IsColFrozen(int iCol) { for (POSITION pos = m_arFrozenCols.GetHeadPosition(); pos; m_arFrozenCols.GetNext(pos)) { int iNext = m_arFrozenCols.GetAt(pos); if (iNext == iCol) { return true; } } return false; } bool CXTPHeaderCtrl::DetermineRTL() { CWindowDC dc(NULL); // determine if columns are resized by dragging them right (most languages) or // left (RTL languages like Arabic & Hebrew). UINT nAlign = dc.GetTextAlign(); ASSERT(nAlign != GDI_ERROR); // will only be true for RTL languages, text is laid out right to left and // columns resize to the left if ((nAlign != GDI_ERROR) && (nAlign & TA_RTLREADING)) { return true; } return false; } int CXTPHeaderCtrl::GetFrozenColWidth() { int iFrozenWidth = 0; for (POSITION pos = m_arFrozenCols.GetHeadPosition(); pos; m_arFrozenCols.GetNext(pos)) { int iCol = m_arFrozenCols.GetAt(pos); CRect r; Header_GetItemRect(m_hWnd, iCol, &r); iFrozenWidth += r.Width(); } return iFrozenWidth; } void CXTPHeaderCtrl::SetMinSize(int iMinSize) { m_iMinSize = iMinSize; } void CXTPHeaderCtrl::OnPaint() { CPaintDC dc(this); if (IsThemeValid()) { CXTPBufferDC memDC(dc); m_pTheme->DrawHeader(&memDC, this); } else { CHeaderCtrl::DefWindowProc(WM_PAINT, (WPARAM)dc.m_hDC, 0); } } LRESULT CXTPHeaderCtrl::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/) { CDC* pDC = CDC::FromHandle((HDC)wParam); if (pDC && IsThemeValid()) { m_pTheme->DrawHeader(pDC, this); return TRUE; } return Default(); } BOOL CXTPHeaderCtrl::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; } void CXTPHeaderCtrl::OnLButtonDown(UINT nFlags, CPoint point) { m_bLBtnDown = TRUE; CHeaderCtrl::OnLButtonDown(nFlags, point); } void CXTPHeaderCtrl::OnLButtonUp(UINT nFlags, CPoint point) { m_bLBtnDown = FALSE; CHeaderCtrl::OnLButtonUp(nFlags, point); } void CXTPHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point) { if (IsThemeValid() && m_pTheme->UseWinXPThemes(this)) { SetTimer(1, 10, NULL); } CHeaderCtrl::OnMouseMove(nFlags, point); } int CXTPHeaderCtrl::HitTest(CPoint pt, UINT* pFlags/*=NULL*/) const { HDHITTESTINFO hti; hti.pt.x = pt.x; hti.pt.y = pt.y; int iItem = (int)::SendMessage(m_hWnd, HDM_HITTEST, 0, (LPARAM)(&hti)); if (pFlags != NULL) *pFlags = hti.flags; return iItem; } BOOL CXTPHeaderCtrl::ItemPressed(int iItem) { if (m_bLBtnDown) { CPoint point; ::GetCursorPos(&point); ScreenToClient(&point); UINT uFlags; if (HitTest(point, &uFlags) == iItem) return ((uFlags & HHT_ONHEADER) == HHT_ONHEADER); } return FALSE; } void CXTPHeaderCtrl::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { CPoint pt; ::GetCursorPos(&pt); ScreenToClient(&pt); int iOverIndex = HitTest(pt); if (iOverIndex == -1) { KillTimer(1); if (m_bPainted == TRUE) { RedrawWindow(); } m_bPainted = false; return; } if (iOverIndex != m_iOverIndex) { m_iOverIndex = iOverIndex; m_bPainted = false; } if (!m_bPainted) { RedrawWindow(); m_bPainted = true; } } CHeaderCtrl::OnTimer(nIDEvent); } LRESULT CXTPHeaderCtrl::OnLayout(WPARAM wParam, LPARAM lParam) { if (IsThemeValid()) { return (LRESULT)m_pTheme->Layout( (LPHDLAYOUT)lParam, this); } return CHeaderCtrl::DefWindowProc(HDM_LAYOUT, wParam, lParam); } int CXTPHeaderCtrl::SetSortImage(int iSortCol, BOOL bSortAsc) { ASSERT(iSortCol < GetItemCount()); int nPrevCol = m_nSortedCol; m_nSortedCol = iSortCol; m_bAscending = bSortAsc; RedrawWindow(); return nPrevCol; } int CXTPHeaderCtrl::GetSortedCol(BOOL* pbSortAsc/*=NULL*/) { if (pbSortAsc) *pbSortAsc = m_bAscending; return m_nSortedCol; } BOOL CXTPHeaderCtrl::RecalcLayout() { if (!::IsWindow(m_hWnd)) return FALSE; HD_LAYOUT hdl; CXTPClientRect rcClient(this); hdl.prc = &rcClient; WINDOWPOS wp; ZeroMemory(&wp, sizeof(WINDOWPOS)); hdl.pwpos = ℘ if (!Header_Layout(m_hWnd, &hdl)) return FALSE; // Set the size, position, and visibility of the header window. ::SetWindowPos(m_hWnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_FRAMECHANGED); CWnd* pWndParent = GetParent(); if (!::IsWindow(pWndParent->GetSafeHwnd())) return FALSE; // Force list control to recalculate it's layout. CXTPWindowRect rcWindow(pWndParent); const int cx = rcWindow.Width(); const int cy = rcWindow.Height(); pWndParent->SetWindowPos(NULL, 0, 0, cx, cy+1, SWP_NOMOVE | SWP_FRAMECHANGED); pWndParent->SetWindowPos(NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_FRAMECHANGED); return TRUE; } void CXTPHeaderCtrl::OnDestroy() { if (IsThemeValid()) m_pTheme->CleanUp(this); CHeaderCtrl::OnDestroy(); } void CXTPHeaderCtrl::SetBitmap(int iCol, UINT uBitmapID, DWORD dwRemove/*=NULL*/) { if (dwRemove) { HD_ITEM hdi; hdi.mask = HDI_FORMAT; GetItem(iCol, &hdi); hdi.fmt &= ~dwRemove; SetItem(iCol, &hdi); } SetBitmap(iCol, uBitmapID, FALSE, RGB(192, 192, 192)); } void CXTPHeaderCtrl::SetBitmap(int iCol, UINT uBitmapID, BOOL bRemove, COLORREF crMask) { if (IsThemeValid()) { m_pTheme->SetBitmap(iCol, uBitmapID, bRemove, crMask, this); } } void CXTPHeaderCtrl::InitializeHeader(BOOL bBoldFont) { SetFont(bBoldFont ? &XTPAuxData().fontBold : &XTPAuxData().font); RedrawWindow(); } BOOL CXTPHeaderCtrl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { if (message == WM_SETTINGCHANGE || message == WM_SYSCOLORCHANGE) { RefreshMetrics(); } return CHeaderCtrl::OnWndMsg(message, wParam, lParam, pResult); } void CXTPHeaderCtrl::OnRButtonDown(UINT nFlags, CPoint point) { CPoint pt = m_pt = point; ClientToScreen(&pt); // If no sort headers are defined for the parent control or popup menus // has been disabled, call the base class and return. CWnd* pParentWnd = GetParent(); if (pParentWnd->GetStyle() & LVS_NOSORTHEADER || m_bEnableMenus == FALSE) { CHeaderCtrl::OnRButtonDown(nFlags, point); return; } // No menu was defined use default if (!m_popupMenuID) { // Get the index to the header item under the cursor. int iIndex = HitTest(m_pt); if (iIndex != -1) { CMenu menu; CXTPResourceManager::AssertValid(XTPResourceManager()->LoadMenu(&menu, XTP_IDM_POPUP)); CMenu* pPopup = menu.GetSubMenu(2); ASSERT(pPopup != NULL); if (!pPopup) return; if (m_nSortedCol == iIndex && m_bAscending == TRUE) pPopup->CheckMenuItem(XTP_IDC_SORTASC, MF_CHECKED | MF_BYCOMMAND); else if (m_nSortedCol == iIndex && m_bAscending == FALSE) pPopup->CheckMenuItem(XTP_IDC_SORTDSC, MF_CHECKED | MF_BYCOMMAND); if (pParentWnd && ( pParentWnd->IsKindOf(RUNTIME_CLASS(CListCtrl)) || pParentWnd->IsKindOf(RUNTIME_CLASS(CListView)))) { LVCOLUMN lvc; lvc.mask = LVCF_FMT; ListView_GetColumn(pParentWnd->m_hWnd, iIndex, &lvc); switch (lvc.fmt & LVCFMT_JUSTIFYMASK) { case LVCFMT_LEFT: pPopup->CheckMenuItem(XTP_IDC_ALIGNLEFT, MF_CHECKED | MF_BYCOMMAND); break; case LVCFMT_CENTER: pPopup->CheckMenuItem(XTP_IDC_ALIGNCENTER, MF_CHECKED | MF_BYCOMMAND); break; case LVCFMT_RIGHT: pPopup->CheckMenuItem(XTP_IDC_ALIGNRIGHT, MF_CHECKED | MF_BYCOMMAND); break; } } XTPContextMenu(pPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this, XTP_IDR_TBAR_HDR); } } else { CMenu menu; VERIFY(menu.LoadMenu(m_popupMenuID)); CMenu* pPopup = menu.GetSubMenu(m_nPos); ASSERT(pPopup != NULL); if (!pPopup) return; pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, GetOwner()); } } void CXTPHeaderCtrl::SetMenuID(UINT popupMenuID, int nPos) { m_popupMenuID = popupMenuID; m_nPos = nPos; } void CXTPHeaderCtrl::SendNotify(int iIndex) { CWnd* pParentWnd = GetParent(); if (!pParentWnd || !::IsWindow(pParentWnd->m_hWnd)) return; if (pParentWnd->IsKindOf(RUNTIME_CLASS(CListCtrl)) || pParentWnd->IsKindOf(RUNTIME_CLASS(CListView))) { 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. pParentWnd->SendMessage(WM_NOTIFY, (WPARAM)(int)nmh.hdr.idFrom, (LPARAM)(NMHEADER*)&nmh); // then forward to the descendants. pParentWnd->SendMessageToDescendants(WM_NOTIFY, (WPARAM)(int)nmh.hdr.idFrom, (LPARAM)(NMHEADER*)&nmh); } } void CXTPHeaderCtrl::OnSortAsc() { int iIndex = HitTest(m_pt); if (iIndex != -1) { if (m_nSortedCol != iIndex || m_bAscending == FALSE) { m_bAscending = TRUE; m_nSortedCol = iIndex; SendNotify(iIndex); } } } void CXTPHeaderCtrl::OnSortDsc() { int iIndex = HitTest(m_pt); if (iIndex != -1) { if (m_nSortedCol != iIndex || m_bAscending == TRUE) { m_bAscending = FALSE; m_nSortedCol = iIndex; SendNotify(iIndex); } } } BOOL CXTPHeaderCtrl::SetAlingment(int nFlag) { int iIndex = HitTest(m_pt); if (iIndex != -1) { CWnd* pParentWnd = GetParent(); if (pParentWnd && ( pParentWnd->IsKindOf(RUNTIME_CLASS(CListCtrl)) || pParentWnd->IsKindOf(RUNTIME_CLASS(CListView)))) { LVCOLUMN lvc; lvc.mask = LVCF_FMT; ListView_GetColumn(pParentWnd->m_hWnd, iIndex, &lvc); lvc.fmt &= ~LVCFMT_JUSTIFYMASK; lvc.fmt |= nFlag; ListView_SetColumn(pParentWnd->m_hWnd, iIndex, &lvc); ListView_SetWorkAreas(pParentWnd->m_hWnd, 0, NULL); } } return FALSE; } void CXTPHeaderCtrl::OnAlignLeft() { SetAlingment(LVCFMT_LEFT); } void CXTPHeaderCtrl::OnAlignCenter() { SetAlingment(LVCFMT_CENTER); } void CXTPHeaderCtrl::OnAlignRight() { SetAlingment(LVCFMT_RIGHT); } BOOL CXTPHeaderCtrl::HasSortArrow() { if (IsThemeValid()) return m_pTheme->HasSortArrow(); return FALSE; } void CXTPHeaderCtrl::ShowSortArrow(BOOL bSortArrow) { if (IsThemeValid()) { DWORD dwStyle = m_pTheme->GetDrawStyle() & ~HDR_XTP_SORTARROW; if (bSortArrow) dwStyle |= HDR_XTP_SORTARROW; m_pTheme->SetDrawStyle(dwStyle, this); } } void CXTPHeaderCtrl::SetFontBold(BOOL bBoldFont) { ASSERT(::IsWindow(m_hWnd)); SetFont(bBoldFont ? &XTPAuxData().fontBold : &XTPAuxData().font); } void CXTPHeaderCtrl::RefreshMetrics() { if (m_pTheme) m_pTheme->RefreshMetrics(this); if (::IsWindow(m_hWnd)) RedrawWindow(); } BOOL CXTPHeaderCtrl::SetTheme(CXTPHeaderCtrlTheme* pTheme) { CMDTARGET_RELEASE(m_pTheme); m_pTheme = pTheme; RefreshMetrics(); return (m_pTheme != NULL); } BOOL CXTPHeaderCtrl::SetTheme(XTPControlTheme eTheme) { CMDTARGET_RELEASE(m_pTheme); switch (eTheme) { case xtpControlThemeFlat: case xtpControlThemeUltraFlat: case xtpControlThemeOffice2000: case xtpControlThemeOfficeXP: m_pTheme = new CXTPHeaderCtrlThemeOfficeXP; break; case xtpControlThemeOffice2003: m_pTheme = new CXTPHeaderCtrlThemeOffice2003; break; case xtpControlThemeVisualStudio2005: case xtpControlThemeVisualStudio2008: case xtpControlThemeVisualStudio2010: case xtpControlThemeNativeWinXP: m_pTheme = new CXTPHeaderCtrlThemeExplorer; m_pTheme->SetDrawStyle(HDR_XTP_WINDEF|HDR_XTP_HOTTRACKING|HDR_XTP_SORTARROW, this); break; case xtpControlThemeResource: m_pTheme = new CXTPHeaderCtrlThemeResource; break; case xtpControlThemeDefault: default: m_pTheme = new CXTPHeaderCtrlTheme; break; } RefreshMetrics(); return (m_pTheme != NULL); } LRESULT CXTPHeaderCtrl::OnSetTheme(WPARAM wParam, LPARAM /*lParam*/) { XTPControlTheme eTheme = (XTPControlTheme)wParam; SetTheme(eTheme); return 0; }