/** * @file XTPHeaderCtrlTheme.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" #include "Common/XTPTypeId.h" #include "Common/XTPCasting.h" #include "Common/XTPFramework.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPWinThemeWrapper.h" #include "Common/XTPColorManager.h" #include "Common/XTPResourceImage.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPImageManager.h" #include "Controls/Util/XTPControlTheme.h" #include "Controls/Header/XTPHeaderCtrlTheme.h" #include "Controls/Header/XTPHeaderCtrl.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # undef THIS_FILE static char THIS_FILE[] = __FILE__; # define new DEBUG_NEW #endif //============================================================================= // CXTPHeaderCtrlTheme //============================================================================= CXTPHeaderCtrlTheme::CXTPHeaderCtrlTheme() : m_iArrowPadding(XTP_DPI_X(10)) , m_dwDrawStyle(0) , m_bUseWinThemes(false) , m_sizePadding(XTP_DPI_X(6), 0) , m_sizeArrow(XTP_DPI_X(8), XTP_DPI_Y(7)) { m_dwDrawStyle = HDR_XTP_WINDEF | HDR_XTP_HOTTRACKING | HDR_XTP_SORTARROW; m_themeHeader = new CXTPWinThemeWrapper(); } CXTPHeaderCtrlTheme::~CXTPHeaderCtrlTheme() { SAFE_DELETE(m_themeHeader); } void CXTPHeaderCtrlTheme::RefreshMetrics(CXTPHeaderCtrl* /*pHeader*/) { m_crText = GetXtremeColor(COLOR_BTNTEXT); m_cr3DFace = GetXtremeColor(COLOR_3DFACE); m_cr3DShadow = GetXtremeColor(COLOR_3DSHADOW); m_cr3DDkShadow = GetXtremeColor(COLOR_3DDKSHADOW); m_cr3DHighLight = GetXtremeColor(COLOR_3DHIGHLIGHT); m_themeHeader->OpenThemeData(0, L"HEADER"); } void CXTPHeaderCtrlTheme::OnDrawBackground(LPDRAWITEMSTRUCT lpDIS) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); CRect rcItem = lpDIS->rcItem; // fill background pDC->FillSolidRect(&rcItem, m_cr3DFace); rcItem.right += 2; // draw 3D borders. pDC->Draw3dRect(&rcItem, m_cr3DHighLight, m_cr3DDkShadow); rcItem.DeflateRect(1, 1); pDC->Draw3dRect(&rcItem, m_cr3DFace, m_cr3DShadow); } void CXTPHeaderCtrlTheme::OnDrawItemBackground(LPDRAWITEMSTRUCT lpDIS) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); if (lpDIS->itemState == ODS_SELECTED) { pDC->Draw3dRect(&lpDIS->rcItem, m_cr3DShadow, m_cr3DShadow); CXTPPenDC penDC(pDC->m_hDC, m_cr3DHighLight); pDC->MoveTo(lpDIS->rcItem.right, 1); pDC->LineTo(lpDIS->rcItem.right, lpDIS->rcItem.bottom - 1); penDC.Color(m_cr3DFace); pDC->MoveTo(lpDIS->rcItem.left + 1, lpDIS->rcItem.bottom - 2); pDC->LineTo(lpDIS->rcItem.right - 1, lpDIS->rcItem.bottom - 2); } else { CXTPPenDC penDC(pDC->m_hDC, m_cr3DShadow); pDC->MoveTo(lpDIS->rcItem.right - 2, 1); pDC->LineTo(lpDIS->rcItem.right - 2, lpDIS->rcItem.bottom - 1); penDC.Color(m_cr3DDkShadow); pDC->MoveTo(lpDIS->rcItem.right - 1, 0); pDC->LineTo(lpDIS->rcItem.right - 1, lpDIS->rcItem.bottom - 1); penDC.Color(m_cr3DHighLight); pDC->MoveTo(lpDIS->rcItem.right, 1); pDC->LineTo(lpDIS->rcItem.right, lpDIS->rcItem.bottom - 1); } } BOOL CXTPHeaderCtrlTheme::OnDrawBackgroundWinThemed(LPDRAWITEMSTRUCT lpDIS) { if ((GetDrawStyle() & HDR_XTP_HOTTRACKING) == 0) return FALSE; if (m_themeHeader->DrawThemeBackground(lpDIS->hDC, 0, HIS_NORMAL, &lpDIS->rcItem, NULL) != S_OK) { TRACE0("Error drawing background using WinTheme API.\n"); return FALSE; } return TRUE; } BOOL CXTPHeaderCtrlTheme::OnDrawItemBackgroundWinThemed(LPDRAWITEMSTRUCT lpDIS) { int iState = HIS_NORMAL; if (lpDIS->itemState & ODS_HOTLIGHT) iState = HIS_HOT; if (lpDIS->itemState & ODS_SELECTED) iState = HIS_PRESSED; if (m_themeHeader->DrawThemeBackground(lpDIS->hDC, HP_HEADERITEM, iState, &lpDIS->rcItem, NULL) != S_OK) { TRACE0("Error drawing background using WinTheme API.\n"); return FALSE; } return TRUE; } void CXTPHeaderCtrlTheme::DrawSortArrow(CDC* pDC, LPPOINT ptsArrow, BOOL bAscending) { CXTPPenDC dcPen(pDC->m_hDC, bAscending ? m_cr3DHighLight : m_cr3DShadow); pDC->MoveTo(ptsArrow[2]); pDC->LineTo(ptsArrow[bAscending ? 1 : 0]); pDC->LineTo(ptsArrow[bAscending ? 0 : 1]); dcPen.Color(bAscending ? m_cr3DShadow : m_cr3DHighLight); pDC->MoveTo(ptsArrow[bAscending ? 0 : 2]); pDC->LineTo(ptsArrow[bAscending ? 2 : 1]); } void CXTPHeaderCtrlTheme::OnDrawItemSortArrow(LPDRAWITEMSTRUCT lpDIS, BOOL bAscending) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); CRect rcItem = lpDIS->rcItem; CPoint point; point.x = rcItem.right + m_iArrowPadding; point.y = (rcItem.top - 1) + (rcItem.Height() - m_sizeArrow.cy) / 2; if (point.x < rcItem.left) return; if (lpDIS->itemState == ODS_SELECTED) point.Offset(XTP_DPI_X(1), XTP_DPI_Y(1)); CRect rcArrow; rcArrow.left = point.x; rcArrow.top = point.y; rcArrow.right = point.x + m_sizeArrow.cx; rcArrow.bottom = point.y + m_sizeArrow.cy; int x = point.x + (m_sizeArrow.cx / 2); // int y = point.y + (m_sizeArrow.cy/2); POINT ptsArrow[3]; ptsArrow[0].x = x - m_sizeArrow.cx / 2; ptsArrow[0].y = bAscending ? rcArrow.bottom : rcArrow.top; ptsArrow[1].x = x + m_sizeArrow.cx / 2; ptsArrow[1].y = bAscending ? rcArrow.bottom : rcArrow.top; ptsArrow[2].x = x; ptsArrow[2].y = bAscending ? rcArrow.top : rcArrow.bottom; DrawSortArrow(pDC, ptsArrow, bAscending); } void CXTPHeaderCtrlTheme::OnDrawItemText(LPDRAWITEMSTRUCT lpDIS, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); CDC* pDC = CDC::FromHandle(lpDIS->hDC); LPHDITEM lpHDI = (LPHDITEM)lpDIS->itemData; // prepare the device context to draw text. CXTPFontDC fontDC(pDC, pHeaderCtrl->GetFont()); // construct text size. CRect rcItem(lpDIS->rcItem); rcItem.DeflateRect(m_sizePadding.cx, 0); BOOL bSortAsc = FALSE; UINT nSortItem = XTPToUInt(pHeaderCtrl->GetSortedCol(&bSortAsc)); if (nSortItem == lpDIS->itemID) rcItem.right -= m_sizeArrow.cx + m_iArrowPadding * 2; CRect rcText(rcItem); CSize sizeText = pDC->GetTextExtent(CString(lpHDI->pszText) + CString(_T(" "))); rcText.top = (m_sizePadding.cy > 0) ? m_sizePadding.cy : (rcItem.Height() - sizeText.cy) / 2; rcText.bottom = rcText.top + sizeText.cy; if ((lpHDI->fmt & HDF_BITMAP && lpHDI->hbm != NULL) || (lpHDI->fmt & HDF_IMAGE)) { if (lpHDI->fmt & HDF_BITMAP_ON_RIGHT) { CRect rcImage(rcText); rcImage.left += sizeText.cx + m_sizePadding.cx; OnDrawItemBitmap(lpDIS, rcImage, pHeaderCtrl); } else { OnDrawItemBitmap(lpDIS, rcText, pHeaderCtrl); } } // determine justification for text. switch (lpHDI->fmt & HDF_JUSTIFYMASK) { case HDF_LEFT: rcText.right = rcText.left + sizeText.cx; break; case HDF_CENTER: rcText.left += (rcItem.Width() - sizeText.cx) / 2; rcText.right = rcText.left + sizeText.cx; break; case HDF_RIGHT: rcText.left = rcText.right - sizeText.cx; break; } // size text to fit available display area. rcText.left = __max(rcText.left, rcItem.left); rcText.right = __min(rcText.right, rcItem.right); // check if we are sorting. if (HasSortArrow() && nSortItem == lpDIS->itemID) { lpDIS->rcItem = rcText; OnDrawItemSortArrow(lpDIS, bSortAsc); } if (rcText.Width() > 0) { if (lpDIS->itemState == ODS_SELECTED) rcText.OffsetRect(XTP_DPI_X(1), XTP_DPI_Y(1)); // draw text. pDC->DrawText(lpHDI->pszText, &rcText, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); } } void CXTPHeaderCtrlTheme::DrawHeader(CDC* pDC, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); CXTPClientRect rcClient(pHeaderCtrl); DRAWITEMSTRUCT dis; dis.CtlType = ODT_BUTTON; dis.CtlID = 0; dis.itemID = 0; dis.itemAction = ODA_DRAWENTIRE; dis.itemState = 0; dis.hwndItem = pHeaderCtrl->m_hWnd; dis.hDC = pDC->m_hDC; dis.rcItem = rcClient; dis.itemData = 0; // draw background. if (!m_bUseWinThemes || !OnDrawBackgroundWinThemed(&dis)) OnDrawBackground(&dis); // set text attributes. CXTPFontDC fontDC(pDC, pHeaderCtrl->GetFont()); pDC->SetBkColor(m_cr3DFace); pDC->SetTextColor(m_crText); pDC->SetBkMode(TRANSPARENT); // Set up the header item order array. HD_ITEM hdi; ::ZeroMemory(&hdi, sizeof(HD_ITEM)); hdi.fmt = HDF_STRING | HDF_LEFT | HDF_BITMAP; hdi.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_ORDER | HDI_BITMAP | HDI_LPARAM; int cxy = 0; int iItem = 0; int iItemCount = pHeaderCtrl->GetItemCount(); int* plItems = new int[XTPToUIntChecked(iItemCount)]; for (iItem = 0; iItem < iItemCount; iItem++) { pHeaderCtrl->GetItem(iItem, &hdi); plItems[hdi.iOrder] = iItem; } hdi.fmt = HDF_STRING | HDF_LEFT | HDF_BITMAP; hdi.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_BITMAP | HDI_LPARAM; // get cursor position. CPoint point; ::GetCursorPos(&point); pHeaderCtrl->ScreenToClient(&point); // Draw each header item for (iItem = 0; iItem < iItemCount; ++iItem) { // Get the header item text and format TCHAR szBuffer[256]; hdi.pszText = szBuffer; hdi.cchTextMax = 255; pHeaderCtrl->GetItem(plItems[iItem], &hdi); // initialize draw item structure. dis.itemID = XTPToUInt(plItems[iItem]); dis.itemState = 0; dis.rcItem = rcClient; dis.rcItem.left = cxy; dis.rcItem.right = dis.rcItem.left + hdi.cxy; dis.itemData = (DWORD_PTR)&hdi; // if hot tracking is enabled, set the state. if (GetDrawStyle() & HDR_XTP_HOTTRACKING) { if (pHeaderCtrl->HitTest(point) == plItems[iItem]) dis.itemState = ODS_HOTLIGHT; } // check if the item is selected if (pHeaderCtrl->ItemPressed(plItems[iItem])) dis.itemState = ODS_SELECTED; // draw the item background. if (!m_bUseWinThemes || !OnDrawItemBackgroundWinThemed(&dis)) OnDrawItemBackground(&dis); // draw the item text. OnDrawItemText(&dis, pHeaderCtrl); cxy += hdi.cxy; } delete[] plItems; } BOOL CXTPHeaderCtrlTheme::UseWinXPThemes(CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); // if windows xp themes are not allowed, return FALSE. if ((GetDrawStyle() & HDR_XTP_WINDEF) == 0) return FALSE; // if we got this far then we try to load the theme data for // this control if it is not currently open. if (!m_themeHeader->ThemeDataOpen()) m_themeHeader->OpenThemeData(pHeaderCtrl->m_hWnd, L"HEADER"); // if our application is not "Theme Ready" meaning that we cannot // display Windows XP themes, then return FALSE. #ifndef _XTP_ACTIVEX if (!m_themeHeader->IsAppThemeReady()) return FALSE; #endif // this will return TRUE if we can display visual styles. return m_themeHeader->ThemeDataOpen(); } void CXTPHeaderCtrlTheme::SetDrawStyle(DWORD dwDrawStyle, CXTPHeaderCtrl* pHeaderCtrl) { m_dwDrawStyle = dwDrawStyle; m_bUseWinThemes = UseWinXPThemes(pHeaderCtrl) && ((m_dwDrawStyle & HDR_XTP_WINDEF) != 0); } DWORD CXTPHeaderCtrlTheme::GetDrawStyle() const { return m_dwDrawStyle; } BOOL CXTPHeaderCtrlTheme::Layout(LPHDLAYOUT lpHDL, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); return (BOOL)pHeaderCtrl->DefWindowProc(HDM_LAYOUT, (WPARAM)0, (LPARAM)lpHDL); } BOOL CXTPHeaderCtrlTheme::SetBitmap(int iCol, UINT uBitmapID, BOOL bRemove, COLORREF crMask, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); // reset header image list HD_ITEM hdi; ::ZeroMemory(&hdi, sizeof(HD_ITEM)); hdi.mask = HDI_BITMAP | HDI_FORMAT; pHeaderCtrl->GetItem(iCol, &hdi); // free previous GDI resources. if (hdi.fmt & HDF_BITMAP && hdi.hbm != NULL) ::ImageList_Destroy((HIMAGELIST)hdi.hbm); hdi.hbm = NULL; hdi.fmt &= ~HDF_BITMAP; pHeaderCtrl->SetItem(iCol, &hdi); pHeaderCtrl->RedrawWindow(); // add new image list if (!bRemove) { HBITMAP hBitmap = (HBITMAP)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(uBitmapID), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); if (hBitmap == NULL) return FALSE; BITMAP bmpInfo; ZeroMemory(&bmpInfo, sizeof(BITMAP)); if (::GetObject(hBitmap, sizeof(BITMAP), &bmpInfo) == 0) return FALSE; HIMAGELIST hImageList = ::ImageList_Create(bmpInfo.bmWidth, bmpInfo.bmHeight, ILC_MASK | ILC_COLOR24, 0, 1); if (hImageList == NULL) return FALSE; if (::ImageList_AddMasked(hImageList, hBitmap, crMask) == -1) { ::ImageList_Destroy(hImageList); ::DeleteObject(hBitmap); return FALSE; } // we are actually storing a handle to the image list and // not the bitmap so we can draw using the mask. hdi.hbm = (HBITMAP)hImageList; hdi.fmt = HDF_BITMAP; pHeaderCtrl->SetItem(iCol, &hdi); pHeaderCtrl->RedrawWindow(); ::DeleteObject(hBitmap); return TRUE; } return FALSE; } void CXTPHeaderCtrlTheme::OnDrawItemBitmap(LPDRAWITEMSTRUCT lpDIS, CRect& rcText, CXTPHeaderCtrl* pHeaderCtrl) { ASSERT_VALID(pHeaderCtrl); HDITEM hdi; hdi.mask = HDI_BITMAP | HDI_FORMAT | HDI_IMAGE; pHeaderCtrl->GetItem(XTPToInt(lpDIS->itemID), &hdi); HIMAGELIST hImageList = 0; int nIndex = -1; if (hdi.fmt & HDF_BITMAP && hdi.hbm != NULL) { hImageList = (HIMAGELIST)hdi.hbm; nIndex = 0; } else if (hdi.fmt & HDF_IMAGE) { hImageList = (HIMAGELIST)pHeaderCtrl->SendMessage(HDM_GETIMAGELIST); nIndex = hdi.iImage; } if (nIndex != -1 && (hdi.fmt & HDF_IMAGE) && pHeaderCtrl->GetImageManager()) { CXTPImageManagerIcon* pIcon = pHeaderCtrl->GetImageManager()->GetImage(XTPToUInt(nIndex), 0); if (pIcon) { CSize szIcon = pIcon->GetExtent(); if (pIcon->IsVectorIcon() || pHeaderCtrl->IsDpiBitmapScalingEnabled()) szIcon = XTP_DPI(szIcon); CRect rcItem(lpDIS->rcItem); CPoint point(rcText.left, (rcItem.Height() - szIcon.cy) / 2); rcText.left += szIcon.cx + m_sizePadding.cx; XTPImageState imageState = (lpDIS->itemState & ODS_SELECTED) ? xtpImageChecked : (lpDIS->itemState & ODS_HOTLIGHT) ? xtpImageHot : xtpImageNormal; if (lpDIS->itemState == ODS_SELECTED) point.Offset(XTP_DPI_X(1), XTP_DPI_Y(1)); if (point.x + szIcon.cx > lpDIS->rcItem.right) return; pIcon->Draw(CDC::FromHandle(lpDIS->hDC), point, imageState, szIcon); return; } } if (hImageList) { int cx, cy; if (::ImageList_GetIconSize(hImageList, &cx, &cy) && (nIndex < ImageList_GetImageCount(hImageList))) { if (pHeaderCtrl->IsDpiBitmapScalingEnabled()) { cx = XTP_DPI_X(cx); cy = XTP_DPI_X(cy); } CRect rcItem(lpDIS->rcItem); CPoint point(rcText.left, (rcItem.Height() - cy) / 2); rcText.left += cx + m_sizePadding.cx; if (lpDIS->itemState == ODS_SELECTED) point.Offset(XTP_DPI_X(1), XTP_DPI_Y(1)); if (point.x + cx > lpDIS->rcItem.right) return; CXTPDrawHelpers::StretchImageListImage(CDC::FromHandle(lpDIS->hDC), CRect(point, CSize(cx, cy)), CImageList::FromHandle(hImageList), nIndex); } } } void CXTPHeaderCtrlTheme::CleanUp(CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); // free GDI resources for (int i = 0; i < pHeaderCtrl->GetItemCount(); ++i) { HDITEM hdi; hdi.mask = HDI_FORMAT | HDI_BITMAP; pHeaderCtrl->GetItem(i, &hdi); if (hdi.fmt & HDF_BITMAP && hdi.hbm != NULL) { ::ImageList_Destroy((HIMAGELIST)hdi.hbm); } } } //============================================================================= // CXTPHeaderCtrlThemeOfficeXP //============================================================================= CXTPHeaderCtrlThemeOfficeXP::CXTPHeaderCtrlThemeOfficeXP() { m_nTheme = xtpControlThemeOfficeXP; m_dwDrawStyle = HDR_XTP_SORTARROW; } CXTPHeaderCtrlThemeOfficeXP::~CXTPHeaderCtrlThemeOfficeXP() { } void CXTPHeaderCtrlThemeOfficeXP::OnDrawBackground(LPDRAWITEMSTRUCT lpDIS) { CRect rcItem(lpDIS->rcItem); CDC* pDC = CDC::FromHandle(lpDIS->hDC); // fill background pDC->FillSolidRect(&rcItem, m_cr3DFace); rcItem.right += 2; // draw 3D borders. pDC->Draw3dRect(&rcItem, m_cr3DHighLight, m_cr3DShadow); } void CXTPHeaderCtrlThemeOfficeXP::OnDrawItemBackground(LPDRAWITEMSTRUCT lpDIS) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); if (lpDIS->itemState == ODS_SELECTED) { CXTPPenDC penDC(lpDIS->hDC, m_cr3DShadow); pDC->MoveTo(lpDIS->rcItem.right - 2, 2); pDC->LineTo(lpDIS->rcItem.right - 2, lpDIS->rcItem.bottom - 2); penDC.Color(m_cr3DHighLight); pDC->MoveTo(lpDIS->rcItem.right - 1, 2); pDC->LineTo(lpDIS->rcItem.right - 1, lpDIS->rcItem.bottom - 2); } else { CXTPPenDC penDC(lpDIS->hDC, m_cr3DShadow); pDC->MoveTo(lpDIS->rcItem.right - 2, 2); pDC->LineTo(lpDIS->rcItem.right - 2, lpDIS->rcItem.bottom - 2); penDC.Color(m_cr3DHighLight); pDC->MoveTo(lpDIS->rcItem.right - 1, 2); pDC->LineTo(lpDIS->rcItem.right - 1, lpDIS->rcItem.bottom - 2); } } //============================================================================= // CXTPHeaderCtrlThemeOffice2003 //============================================================================= CXTPHeaderCtrlThemeOffice2003::CXTPHeaderCtrlThemeOffice2003() { m_nTheme = xtpControlThemeOffice2003; m_dwDrawStyle = HDR_XTP_SORTARROW; m_sizePadding = CSize(XTP_DPI_X(6), 0); } CXTPHeaderCtrlThemeOffice2003::~CXTPHeaderCtrlThemeOffice2003() { } void CXTPHeaderCtrlThemeOffice2003::OnDrawBackground(LPDRAWITEMSTRUCT lpDIS) { CRect rcItem(lpDIS->rcItem); CDC* pDC = CDC::FromHandle(lpDIS->hDC); // fill background pDC->FillSolidRect(&rcItem, m_cr3DFace); rcItem.right += 2; // draw 3D borders. pDC->Draw3dRect(&rcItem, m_cr3DHighLight, MixColor(m_cr3DFace, m_cr3DShadow, 0.6)); CXTPPenDC penDC(lpDIS->hDC, MixColor(m_cr3DFace, m_cr3DShadow, 0.4)); pDC->MoveTo(rcItem.left, rcItem.bottom - 2); pDC->LineTo(rcItem.right, rcItem.bottom - 2); penDC.Color(MixColor(m_cr3DFace, m_cr3DShadow, 0.25)); pDC->MoveTo(rcItem.left, rcItem.bottom - 3); pDC->LineTo(rcItem.right, rcItem.bottom - 3); } void CXTPHeaderCtrlThemeOffice2003::OnDrawItemBackground(LPDRAWITEMSTRUCT lpDIS) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); if (lpDIS->itemState == ODS_SELECTED) { CXTPPenDC penDC(lpDIS->hDC, m_cr3DShadow); pDC->MoveTo(lpDIS->rcItem.right - 2, 2); pDC->LineTo(lpDIS->rcItem.right - 2, lpDIS->rcItem.bottom - 4); penDC.Color(m_cr3DHighLight); pDC->MoveTo(lpDIS->rcItem.right - 1, 2); pDC->LineTo(lpDIS->rcItem.right - 1, lpDIS->rcItem.bottom - 4); } else { CXTPPenDC penDC(lpDIS->hDC, m_cr3DShadow); pDC->MoveTo(lpDIS->rcItem.right - 2, 2); pDC->LineTo(lpDIS->rcItem.right - 2, lpDIS->rcItem.bottom - 4); penDC.Color(m_cr3DHighLight); pDC->MoveTo(lpDIS->rcItem.right - 1, 2); pDC->LineTo(lpDIS->rcItem.right - 1, lpDIS->rcItem.bottom - 4); } } BOOL CXTPHeaderCtrlThemeOffice2003::Layout(LPHDLAYOUT lpHDL, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); LPRECT pRC = lpHDL->prc; LPWINDOWPOS pWP = lpHDL->pwpos; CWindowDC dc(NULL); CXTPFontDC fontDC(&dc, pHeaderCtrl->GetFont()); TEXTMETRIC tm; dc.GetTextMetrics(&tm); int iHeight = tm.tmHeight + XTP_DPI_Y(10); pWP->hwndInsertAfter = 0; pWP->x = pRC->left; pWP->cx = pRC->right - pRC->left; pWP->cy = iHeight; pWP->y = pRC->top; pRC->top += iHeight; pWP->flags = SWP_NOACTIVATE | SWP_NOZORDER; return TRUE; } //============================================================================= // CXTPHeaderCtrlThemeExplorer //============================================================================= CXTPHeaderCtrlThemeExplorer::CXTPHeaderCtrlThemeExplorer() { m_nTheme = xtpControlThemeNativeWinXP; m_dwDrawStyle = HDR_XTP_WINDEF | HDR_XTP_HOTTRACKING | HDR_XTP_SORTARROW; m_sizePadding = CSize(XTP_DPI_X(6), 0); m_sizeArrow = XTP_DPI(CSize(8, 4)); } CXTPHeaderCtrlThemeExplorer::~CXTPHeaderCtrlThemeExplorer() { } BOOL CXTPHeaderCtrlThemeExplorer::OnDrawItemBackgroundWinThemed(LPDRAWITEMSTRUCT lpDIS) { return CXTPHeaderCtrlTheme::OnDrawItemBackgroundWinThemed(lpDIS); } BOOL CXTPHeaderCtrlThemeExplorer::Layout(LPHDLAYOUT lpHDL, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); LPRECT pRC = lpHDL->prc; LPWINDOWPOS pWP = lpHDL->pwpos; CWindowDC dc(NULL); CXTPFontDC fontDC(&dc, pHeaderCtrl->GetFont()); TEXTMETRIC tm; dc.GetTextMetrics(&tm); int iHeight = tm.tmHeight + XTP_DPI_Y(6); pWP->hwndInsertAfter = 0; pWP->x = pRC->left; pWP->cx = pRC->right - pRC->left; pWP->cy = iHeight; pWP->y = pRC->top; pRC->top += iHeight; pWP->flags = SWP_NOACTIVATE | SWP_NOZORDER; return TRUE; } void CXTPHeaderCtrlThemeExplorer::DrawSortArrow(CDC* pDC, LPPOINT ptsArrow, BOOL /*bAscending*/) { CXTPPenDC dcPen(pDC->m_hDC, RGB(172, 168, 153)); CXTPBrushDC dcBrush(pDC->m_hDC, RGB(172, 168, 153)); pDC->SetPolyFillMode(WINDING); pDC->Polygon(ptsArrow, 3); } void CXTPHeaderCtrlThemeExplorer::OnDrawBackground(LPDRAWITEMSTRUCT lpDIS) { CRect rcItem(lpDIS->rcItem); CDC* pDC = CDC::FromHandle(lpDIS->hDC); // fill background pDC->FillSolidRect(&rcItem, m_cr3DFace); rcItem.right += 2; // draw 3D borders. pDC->Draw3dRect(&rcItem, m_cr3DHighLight, m_cr3DShadow); } //============================================================================= // CXTPHeaderCtrlThemeResource //============================================================================= CXTPHeaderCtrlThemeResource::CXTPHeaderCtrlThemeResource() { m_nTheme = xtpControlThemeResource; m_sizeArrow = XTP_DPI(CSize(8, 4)); } void CXTPHeaderCtrlThemeResource::RefreshMetrics(CXTPHeaderCtrl* pHeader) { CXTPHeaderCtrlThemeOfficeXP::RefreshMetrics(pHeader); CXTPResourceImages* pImages = XTPResourceImages(); if (pImages) { m_crText = pImages->GetImageColor(_T("GridControl"), _T("HeaderText"), m_crText); m_cr3DShadow = pImages->GetImageColor(_T("GridControl"), _T("ColumnSeparator"), m_crText); m_cr3DDkShadow = pImages->GetImageColor(_T("GridControl"), _T("ColumnShadow"), m_crText); m_crgBack.SetStandardValue(pImages->GetImageColor(_T("GridControl"), _T("NormalColumnLight"), m_cr3DFace), pImages->GetImageColor(_T("GridControl"), _T("NormalColumnDark"), m_cr3DFace)); m_crgBackPressed.SetStandardValue( pImages->GetImageColor(_T("GridControl"), _T("PressedColumnLight"), m_cr3DFace), pImages->GetImageColor(_T("GridControl"), _T("PressedColumnDark"), m_cr3DFace)); } else { m_crgBack.SetStandardValue(m_cr3DFace, m_cr3DFace); } } void CXTPHeaderCtrlThemeResource::OnDrawBackground(LPDRAWITEMSTRUCT lpDIS) { CXTPResourceImages* pImages = XTPResourceImages(); if (pImages) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); CRect rcItem = lpDIS->rcItem; // fill background XTPDrawHelpers()->GradientFill(pDC, rcItem, m_crgBack, FALSE); rcItem.right += 2; // draw border. CXTPPenDC penDC(pDC->m_hDC, m_cr3DDkShadow); pDC->MoveTo(lpDIS->rcItem.left, lpDIS->rcItem.bottom - 1); pDC->LineTo(lpDIS->rcItem.right, lpDIS->rcItem.bottom - 1); } else { CXTPHeaderCtrlThemeOfficeXP::OnDrawBackground(lpDIS); } } void CXTPHeaderCtrlThemeResource::OnDrawItemBackground(LPDRAWITEMSTRUCT lpDIS) { CXTPResourceImages* pImages = XTPResourceImages(); if (pImages) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); CRect rcItem = lpDIS->rcItem; rcItem.left++; if (lpDIS->itemState == ODS_SELECTED) { XTPDrawHelpers()->GradientFill(pDC, &rcItem, m_crgBackPressed, FALSE); // draw border. { CXTPPenDC dcPen(pDC->m_hDC, m_cr3DDkShadow); pDC->MoveTo(rcItem.left, rcItem.bottom - 1); pDC->LineTo(rcItem.right, rcItem.bottom - 1); } // draw separator. { CXTPPenDC dcPen(pDC->m_hDC, m_cr3DShadow); pDC->MoveTo(rcItem.right, 2); pDC->LineTo(rcItem.right, rcItem.bottom - 3); } } else { // draw separator. CXTPPenDC dcPen(pDC->m_hDC, m_cr3DShadow); pDC->MoveTo(rcItem.right, 2); pDC->LineTo(rcItem.right, rcItem.bottom - 3); } } else { CXTPHeaderCtrlThemeOfficeXP::OnDrawItemBackground(lpDIS); } } void CXTPHeaderCtrlThemeResource::DrawSortArrow(CDC* pDC, LPPOINT ptsArrow, BOOL bAscending) { CXTPResourceImages* pImages = XTPResourceImages(); if (pImages) { CXTPPenDC dcPen(pDC->m_hDC, m_cr3DShadow); CXTPBrushDC dcBrush(pDC->m_hDC, m_cr3DShadow); pDC->SetPolyFillMode(WINDING); pDC->Polygon(ptsArrow, 3); } else { CXTPHeaderCtrlThemeOfficeXP::DrawSortArrow(pDC, ptsArrow, bAscending); } } void CXTPHeaderCtrlThemeResource::OnDrawItemText(LPDRAWITEMSTRUCT lpDIS, CXTPHeaderCtrl* pHeaderCtrl) { _ASSERTE(pHeaderCtrl); CDC* pDC = CDC::FromHandle(lpDIS->hDC); LPHDITEM lpHDI = (LPHDITEM)lpDIS->itemData; // prepare the device context to draw text. CXTPFontDC fontDC(pDC, pHeaderCtrl->GetFont()); // construct text size. CRect rcItem(lpDIS->rcItem); rcItem.DeflateRect(m_sizePadding.cx, 0); BOOL bSortAsc; UINT nSortItem = XTPToUInt(pHeaderCtrl->GetSortedCol(&bSortAsc)); if (nSortItem == lpDIS->itemID) rcItem.right -= m_sizeArrow.cx + m_iArrowPadding * 2; CRect rcText(rcItem); CSize sizeText = pDC->GetTextExtent(lpHDI->pszText); rcText.top = (m_sizePadding.cy > 0) ? m_sizePadding.cy : (rcItem.Height() - sizeText.cy) / 2; rcText.bottom = rcText.top + sizeText.cy; if ((lpHDI->fmt & HDF_BITMAP && lpHDI->hbm != NULL) || (lpHDI->fmt & HDF_IMAGE)) { if (lpHDI->fmt & HDF_BITMAP_ON_RIGHT) { CRect rcImage(rcText); rcImage.left += sizeText.cx + m_sizePadding.cx; OnDrawItemBitmap(lpDIS, rcImage, pHeaderCtrl); } else { OnDrawItemBitmap(lpDIS, rcText, pHeaderCtrl); } } // determine justification for text. switch (lpHDI->fmt & HDF_JUSTIFYMASK) { case HDF_LEFT: rcText.right = rcText.left + sizeText.cx; break; case HDF_CENTER: rcText.left += (rcItem.Width() - sizeText.cx) / 2; rcText.right = rcText.left + sizeText.cx; break; case HDF_RIGHT: rcText.left = rcText.right - sizeText.cx; break; } // size text to fit available display area. rcText.left = __max(rcText.left, rcItem.left); rcText.right = __min(rcText.right, rcItem.right); // check if we are sorting. if (HasSortArrow() && nSortItem == lpDIS->itemID) { lpDIS->rcItem = rcText; OnDrawItemSortArrow(lpDIS, bSortAsc); } if (rcText.Width() > 0) { // draw text. pDC->DrawText(lpHDI->pszText, &rcText, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); } } void CXTPHeaderCtrlThemeResource::OnDrawItemSortArrow(LPDRAWITEMSTRUCT lpDIS, BOOL bAscending) { CDC* pDC = CDC::FromHandle(lpDIS->hDC); CRect rcItem = lpDIS->rcItem; CPoint point; point.x = rcItem.right + m_iArrowPadding; point.y = (rcItem.top - 1) + (rcItem.Height() - m_sizeArrow.cy) / 2; if (point.x < rcItem.left) return; CRect rcArrow; rcArrow.left = point.x; rcArrow.top = point.y; rcArrow.right = point.x + m_sizeArrow.cx; rcArrow.bottom = point.y + m_sizeArrow.cy; int x = point.x + (m_sizeArrow.cx / 2); POINT ptsArrow[3]; ptsArrow[0].x = x - m_sizeArrow.cx / 2; ptsArrow[0].y = bAscending ? rcArrow.bottom : rcArrow.top; ptsArrow[1].x = x + m_sizeArrow.cx / 2; ptsArrow[1].y = bAscending ? rcArrow.bottom : rcArrow.top; ptsArrow[2].x = x; ptsArrow[2].y = bAscending ? rcArrow.top : rcArrow.bottom; DrawSortArrow(pDC, ptsArrow, bAscending); }