/** * @file XTPSkinObjectHeader.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/Tmschema.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPDrawHelpers.h" #include "Common/ScrollBar/XTPScrollBase.h" #include "Common/XTPSynchro.h" #include "SkinFramework/XTPSkinObject.h" #include "SkinFramework/XTPSkinObjectFrame.h" #include "SkinFramework/XTPSkinObjectHeader.h" #include "SkinFramework/XTPSkinManager.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # undef THIS_FILE static char THIS_FILE[] = __FILE__; # define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(CXTPSkinObjectHeader, CXTPSkinObjectFrame) CXTPSkinObjectHeader::CXTPSkinObjectHeader() { m_strClassName = _T("HEADER"); m_bLBtnDown = FALSE; m_nHotItem = -1; } CXTPSkinObjectHeader::~CXTPSkinObjectHeader() { } #include "Common/Base/Diagnostic/XTPBeginAfxMap.h" BEGIN_MESSAGE_MAP(CXTPSkinObjectHeader, CXTPSkinObjectFrame) //{{AFX_MSG_MAP(CXTPSkinObjectHeader) ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient) //}}AFX_MSG_MAP END_MESSAGE_MAP() #include "Common/Base/Diagnostic/XTPEndAfxMap.h" ///////////////////////////////////////////////////////////////////////////// // CXTPSkinObjectHeader message handlers void CXTPSkinObjectHeader::OnLButtonDown(UINT nFlags, CPoint point) { UINT uFlags = 0; if (HitTest(point, &uFlags) != -1 && ((uFlags & HHT_ONHEADER) == HHT_ONHEADER)) { m_bLBtnDown = TRUE; } CXTPSkinObjectFrame::OnLButtonDown(nFlags, point); } void CXTPSkinObjectHeader::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bLBtnDown) { m_bLBtnDown = FALSE; Invalidate(FALSE); } CXTPSkinObjectFrame::OnLButtonUp(nFlags, point); } int CXTPSkinObjectHeader::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; } void CXTPSkinObjectHeader::OnMouseMove(UINT nFlags, CPoint point) { int nHotItem = HitTest(point); if (nHotItem != m_nHotItem) { m_nHotItem = nHotItem; Invalidate(FALSE); if (m_nHotItem != -1) { TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd, HOVER_DEFAULT }; _TrackMouseEvent(&tme); } } CXTPSkinObjectFrame::OnMouseMove(nFlags, point); } void CXTPSkinObjectHeader::OnMouseLeave() { OnMouseMove(0, CPoint(-1, -1)); } #ifndef HDS_FILTERBAR # define HDS_FILTERBAR 0x0100 #endif LRESULT CXTPSkinObjectHeader::OnPrintClient(WPARAM wParam, LPARAM lParam) { if ((lParam & PRF_CLIENT) == 0 || !IsDrawingEnabled()) return Default(); CDC* pDC = CDC::FromHandle((HDC)wParam); if (pDC) OnDraw(pDC); return 1; } void CXTPSkinObjectHeader::OnPaint() { if (IsDrawingEnabled()) { CXTPSkinObjectPaintDC dc(this); OnDraw(&dc); } else { CXTPSkinObjectFrame::OnPaint(); } } void CXTPSkinObjectHeader::OnDraw(CDC* pDC) { CXTPClientRect rcClient(this); CRect rcBackground(rcClient); CXTPBufferDC dc(*pDC, rcClient); BOOL bFilterBar = (GetStyle() & HDS_FILTERBAR) && XTPSystemVersion()->GetComCtlVersion() >= MAKELONG(80, 5); CRect rcFilter(0, 0, 0, 0); dc.FillSolidRect(rcClient, GetColor(COLOR_3DFACE)); if (bFilterBar) { INT cyFilter = (rcClient.Height() - 1) / 2; rcFilter = rcClient; rcClient.bottom = rcClient.top + cyFilter; rcFilter.top = rcClient.bottom; DefWindowProc(WM_PAINT, (WPARAM)dc.GetSafeHdc(), 0); } CXTPSkinManagerClass* pClass = GetSkinClass(); CXTPFontDC fontDC(&dc, GetFont()); dc.SetTextColor(GetColor(COLOR_BTNTEXT)); dc.SetBkMode(TRANSPARENT); CHeaderCtrl* pHeaderCtrl = (CHeaderCtrl*)this; int iItemCount = pHeaderCtrl->GetItemCount(); // Draw each header item for (int iItem = 0; iItem < iItemCount; ++iItem) { int nIndex = Header_OrderToIndex(m_hWnd, iItem); // initialize draw item structure. CRect rcItem(0, 0, 0, 0); Header_GetItemRect(m_hWnd, nIndex, &rcItem); if ((rcItem.right < rcClient.left) || (rcItem.left > rcClient.right)) continue; if (bFilterBar) { rcItem.bottom = rcFilter.top; } int nState = HIS_NORMAL; if (nIndex == m_nHotItem) { nState = m_bLBtnDown ? HIS_PRESSED : HIS_HOT; } rcBackground.left = max(rcBackground.left, rcItem.right); pClass->DrawThemeBackground(&dc, HP_HEADERITEM, nState, &rcItem); DrawItemEntry(&dc, nIndex, rcItem, nState); } if (rcBackground.left < rcBackground.right) pClass->DrawThemeBackground(&dc, 0, 0, &rcBackground); } #ifndef HDM_GETBITMAPMARGIN # define HDM_GETBITMAPMARGIN (HDM_FIRST + 21) #endif #ifndef HDF_SORTUP # define HDF_SORTUP 0x0400 # define HDF_SORTDOWN 0x0200 #endif void CXTPSkinObjectHeader::DrawItemEntry(CDC* pDC, int nIndex, CRect rcItem, int nState) { CXTPSkinManagerClass* pClass = GetSkinClass(); CHeaderCtrl* pHeaderCtrl = (CHeaderCtrl*)this; CImageList* pImageList = CImageList::FromHandle( (HIMAGELIST)::SendMessage(pHeaderCtrl->m_hWnd, HDM_GETIMAGELIST, 0, 0L)); // Set up the header item order array. HD_ITEM hdi; ::ZeroMemory(&hdi, sizeof(HD_ITEM)); hdi.fmt = HDF_STRING | HDF_IMAGE; hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_IMAGE | HDI_LPARAM; // Get the header item text and format CString strCaption; LPTSTR pszText = strCaption.GetBuffer(256); pszText[0] = 0; hdi.pszText = pszText; hdi.cchTextMax = 255; BOOL bResult = pHeaderCtrl->GetItem(nIndex, &hdi); strCaption.ReleaseBuffer(); #ifdef _UNICODE if (!bResult) { char tText[256]; tText[0] = 0; HD_ITEMA hdia; ::ZeroMemory(&hdia, sizeof(HD_ITEMA)); hdia.fmt = HDF_STRING | HDF_IMAGE; hdia.mask = HDI_TEXT | HDI_FORMAT | HDI_IMAGE | HDI_LPARAM; // Get the header item text and format hdia.pszText = tText; hdia.cchTextMax = 255; ::SendMessage(pHeaderCtrl->m_hWnd, HDM_GETITEMA, XTPToWPARAM(nIndex), (LPARAM)&hdia); strCaption = tText; hdi.fmt = hdia.fmt; hdi.iImage = hdia.iImage; hdi.lParam = hdia.lParam; } #else bResult; #endif if (hdi.fmt & HDF_OWNERDRAW) { DRAWITEMSTRUCT dis; dis.CtlType = ODT_HEADER; dis.CtlID = XTPToUInt(GetDlgCtrlID()); dis.itemID = XTPToUInt(nIndex); dis.itemAction = ODA_DRAWENTIRE; dis.itemState = UINT((nState == HIS_PRESSED) ? ODS_SELECTED : 0); dis.hwndItem = m_hWnd; dis.hDC = pDC->GetSafeHdc(); dis.rcItem = rcItem; dis.itemData = static_cast(hdi.lParam); // Now send it off to my parent... if (GetParent()->SendMessage(WM_DRAWITEM, dis.CtlID, (LPARAM)(DRAWITEMSTRUCT*)&dis)) { return; } } CRect rcText(rcItem); if (pImageList && (hdi.fmt & HDF_IMAGE) && hdi.iImage >= 0 && hdi.iImage < pImageList->GetImageCount()) { int iBitmapMargin = (int)SendMessage(HDM_GETBITMAPMARGIN); if (iBitmapMargin == 0) iBitmapMargin = GetMetrics()->m_cxEdge * 3; int cxBitmap = 16, cyBitmap = 16; ImageList_GetIconSize(pImageList->GetSafeHandle(), &cxBitmap, &cyBitmap); cxBitmap = XTP_DPI_X(cxBitmap); cyBitmap = XTP_DPI_Y(cxBitmap); CPoint pt(rcItem.left + iBitmapMargin, (rcItem.bottom + rcItem.top - cyBitmap) / 2); if (hdi.fmt & HDF_BITMAP_ON_RIGHT) { CSize sz = pDC->GetTextExtent(strCaption); pt.x += sz.cx + iBitmapMargin + XTP_DPI_X(9); if (pt.x + cxBitmap > rcItem.right - XTP_DPI_X(3)) pt.x = max(rcItem.left + XTP_DPI_X(6), rcItem.right - XTP_DPI_X(3) - cxBitmap); if (nState == HIS_PRESSED) pt.x++; CRect rcImage(pt, CSize(cxBitmap, cyBitmap)); CXTPDrawHelpers::StretchImageListImage(pDC, rcImage, pImageList, hdi.iImage); rcText.right = pt.x + XTP_DPI_X(6); } else { if (nState == HIS_PRESSED) pt.x++; CRect rcImage(pt, CSize(cxBitmap, cyBitmap)); CXTPDrawHelpers::StretchImageListImage(pDC, rcImage, pImageList, hdi.iImage); rcText.left += cxBitmap + iBitmapMargin; } } if (((hdi.fmt & HDF_IMAGE) == 0) && ((hdi.fmt & HDF_SORTUP) || (hdi.fmt & HDF_SORTDOWN))) { int iBitmapMargin = GetMetrics()->m_cxEdge * 3; CSize sz = pDC->GetTextExtent(strCaption); CPoint pt(rcItem.left + iBitmapMargin, (rcItem.bottom + rcItem.top - XTP_DPI_Y(2)) / 2); pt.x += sz.cx + iBitmapMargin + XTP_DPI_X(9); if (pt.x + XTP_DPI_X(9) > rcItem.right - XTP_DPI_X(3)) pt.x = max(rcItem.left + XTP_DPI_X(6), rcItem.right - XTP_DPI_X(3) - XTP_DPI_X(9)); CSize szGlyph(XTP_DPI_X(14), XTP_DPI_Y(14)); CRect rcGlyph(pt.x - szGlyph.cx / 2, pt.y - szGlyph.cy / 2, pt.x + szGlyph.cx / 2, pt.y + szGlyph.cy / 2); if (hdi.fmt & HDF_SORTUP) { XTPPrimitiveDrawer()->DrawSymbol(pDC, xtpPrimitiveSymbolPlayUp, rcGlyph, GetColor(COLOR_3DSHADOW)); } else { XTPPrimitiveDrawer()->DrawSymbol(pDC, xtpPrimitiveSymbolPlayDown, rcGlyph, GetColor(COLOR_3DSHADOW)); } rcText.right = pt.x; } UINT nFormat = DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX; // determine justification for text. switch (hdi.fmt & HDF_JUSTIFYMASK) { case HDF_LEFT: nFormat |= DT_LEFT; rcText.DeflateRect(XTP_DPI_X(9), 0, XTP_DPI_X(6), 0); break; case HDF_CENTER: nFormat |= DT_CENTER; rcText.DeflateRect(XTP_DPI_X(6), 0, XTP_DPI_X(6), 0); break; case HDF_RIGHT: nFormat |= DT_RIGHT; rcText.DeflateRect(XTP_DPI_X(6), 0, XTP_DPI_X(9), 0); break; } if (rcText.Width() > 0) { if (nState == HIS_PRESSED) rcText.OffsetRect(XTP_DPI_X(1), XTP_DPI_Y(1)); // draw text. pDC->SetTextColor(GetColor(COLOR_BTNTEXT)); pClass->DrawThemeText(pDC, HP_HEADERITEM, nState, strCaption, nFormat, &rcText); } }