// XTPDrawHelpers.cpp: implementation of the CXTPDrawHelpers class. // // This file is a part of the XTREME TOOLKIT PRO 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 "resource.h" #include "XTPSystemHelpers.h" #include "XTPColorManager.h" #include "XTPDrawHelpers.h" #include "XTPResourceManager.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif HHOOK CXTPMouseMonitor::m_hHookMouse = 0; CWnd* CXTPMouseMonitor::m_pWndMonitor = 0; typedef BOOL (WINAPI *PFNSETLAYEREDWINDOWATTRIBUTES) (HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags); #ifndef LWA_ALPHA #define LWA_ALPHA 0x00000002 #endif #ifndef WS_EX_LAYERED #define WS_EX_LAYERED 0x00080000 #endif ////////////////////////////////////////////////////////////////////////// // CXTPMouseMonitor ////////////////////////////////////////////////////////////////////////// void CXTPMouseMonitor::SetupHook(CWnd* pWndMonitor) { if (pWndMonitor && m_hHookMouse == 0) { m_hHookMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, 0, GetCurrentThreadId ()); } if (!pWndMonitor && m_hHookMouse) { UnhookWindowsHookEx(m_hHookMouse); m_hHookMouse = 0; } m_pWndMonitor = pWndMonitor; } BOOL CXTPMouseMonitor::IsMouseHooked() { return m_pWndMonitor != NULL; } LRESULT CALLBACK CXTPMouseMonitor::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode != HC_ACTION || !m_pWndMonitor) return CallNextHookEx(m_hHookMouse, nCode, wParam, lParam); CXTPWindowRect rc(m_pWndMonitor); if (!rc.PtInRect(((PMOUSEHOOKSTRUCT)lParam)->pt)) { switch (wParam) { case WM_LBUTTONDOWN: case WM_NCLBUTTONDOWN: case WM_RBUTTONDOWN: case WM_NCRBUTTONDOWN: case WM_MBUTTONDOWN: case WM_NCMBUTTONDOWN: m_pWndMonitor->GetOwner()->SetFocus(); return TRUE; } } return CallNextHookEx(m_hHookMouse, nCode, wParam, lParam); } //=========================================================================== // CXTPClientCursorPos class //=========================================================================== CXTPTransparentBitmap::CXTPTransparentBitmap(HBITMAP hBitmap) : m_hBitmap(hBitmap) { } // Not foolproof, but works 99% of the time :). Assumes the top // left pixel is the transparent color. COLORREF CXTPTransparentBitmap::GetTransparentColor() const { CBitmap* pBitmap = CBitmap::FromHandle(m_hBitmap); if (pBitmap != NULL) { CXTPCompatibleDC dc(NULL, pBitmap); return dc.GetPixel(0, 0); } return (COLORREF)-1; } HICON CXTPTransparentBitmap::ConvertToIcon() const { if (m_hBitmap == NULL) return NULL; COLORREF crTransparent = GetTransparentColor(); BITMAP bmp; if (!::GetObject(m_hBitmap, sizeof(BITMAP), &bmp)) return NULL; if (bmp.bmHeight == 0 || bmp.bmWidth == 0) return NULL; CImageList il; il.Create(bmp.bmWidth, bmp.bmHeight, ILC_COLOR24 | ILC_MASK, 0, 1); il.Add(CBitmap::FromHandle(m_hBitmap), crTransparent); ASSERT(il.GetImageCount() == 1); return il.ExtractIcon(0); } //=========================================================================== // CXTPClientCursorPos class //=========================================================================== CXTPClientCursorPos::CXTPClientCursorPos(CWnd* pWnd) { GetCursorPos(this); pWnd->ScreenToClient(this); } //=========================================================================== // CXTPEmptySize class //=========================================================================== CXTPEmptySize::CXTPEmptySize() { SetSizeEmpty(); } void CXTPEmptySize::SetSizeEmpty() { cx = 0; cy = 0; } const SIZE& CXTPEmptySize::operator=(const SIZE& srcSize) { cx = srcSize.cx; cy = srcSize.cy; return *this; } //=========================================================================== // CXTPEmptyRect class //=========================================================================== CXTPEmptyRect::CXTPEmptyRect() { SetRectEmpty(); } //=========================================================================== // CXTPWindowRect class //=========================================================================== CXTPWindowRect::CXTPWindowRect(HWND hWnd) { if (::IsWindow(hWnd)) ::GetWindowRect(hWnd, this); else SetRectEmpty(); } CXTPWindowRect::CXTPWindowRect(const CWnd* pWnd) { if (::IsWindow(pWnd->GetSafeHwnd())) ::GetWindowRect(pWnd->GetSafeHwnd(), this); else SetRectEmpty(); } //=========================================================================== // CXTPClientRect class //=========================================================================== CXTPClientRect::CXTPClientRect(HWND hWnd) { if (::IsWindow(hWnd)) ::GetClientRect(hWnd, this); else SetRectEmpty(); } CXTPClientRect::CXTPClientRect(const CWnd* pWnd) { if (::IsWindow(pWnd->GetSafeHwnd())) ::GetClientRect(pWnd->GetSafeHwnd(), this); else SetRectEmpty(); } //=========================================================================== // CXTPBufferDC class //=========================================================================== CXTPBufferDC::CXTPBufferDC(HDC hDestDC, const CRect& rcPaint) : m_hDestDC (hDestDC) { m_rect = rcPaint; Attach (::CreateCompatibleDC (m_hDestDC)); if (!m_hDC) return; m_bitmap.Attach (::CreateCompatibleBitmap( m_hDestDC, m_rect.right, m_rect.bottom)); m_hOldBitmap = ::SelectObject (m_hDC, m_bitmap); } CXTPBufferDC::CXTPBufferDC(HDC hDestDC, const CRect& rcPaint, const CXTPPaintManagerColorGradient& clrBack, const BOOL bHorz /*=FALSE*/) : m_hDestDC (hDestDC) { m_rect = rcPaint; Attach (::CreateCompatibleDC (m_hDestDC)); if (!m_hDC) return; m_bitmap.Attach (::CreateCompatibleBitmap( m_hDestDC, m_rect.right, m_rect.bottom)); m_hOldBitmap = ::SelectObject (m_hDC, m_bitmap); if (!clrBack.IsNull()) { XTPDrawHelpers()->GradientFill(this, m_rect, clrBack, bHorz); } } CXTPBufferDC::CXTPBufferDC(CPaintDC& paintDC) { m_hDestDC = paintDC.GetSafeHdc(); m_rect = paintDC.m_ps.rcPaint; Attach (::CreateCompatibleDC (m_hDestDC)); if (!m_hDC) return; m_bitmap.Attach (::CreateCompatibleBitmap( m_hDestDC, max(1, m_rect.right), max(1, m_rect.bottom))); m_hOldBitmap = ::SelectObject (m_hDC, m_bitmap); CRgn rgn; rgn.CreateRectRgnIndirect(&m_rect); SelectClipRgn(&rgn); } CXTPBufferDC::~CXTPBufferDC() { if (!m_hDC) return; if (m_hDestDC) { ::BitBlt (m_hDestDC, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), m_hDC, m_rect.left, m_rect.top, SRCCOPY); } ::SelectObject (m_hDC, m_hOldBitmap); } void CXTPBufferDC::Discard() { m_hDestDC = 0; } CDC* CXTPBufferDC::GetDestDC() { return CDC::FromHandle(m_hDestDC); } void CXTPBufferDC::TakeSnapshot() { ::BitBlt (m_hDC, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), m_hDestDC, m_rect.left, m_rect.top, SRCCOPY); } //=========================================================================== // CXTPBufferDC class //=========================================================================== CXTPBufferDCEx::CXTPBufferDCEx(HDC hDestDC, const CRect rcPaint) : m_hDestDC (hDestDC) { m_rect = rcPaint; Attach (::CreateCompatibleDC (m_hDestDC)); m_bitmap = ::CreateCompatibleBitmap( m_hDestDC, m_rect.Width(), m_rect.Height()); m_hOldBitmap = ::SelectObject (m_hDC, m_bitmap); SetViewportOrg(-rcPaint.left, -rcPaint.top); } CXTPBufferDCEx::~CXTPBufferDCEx() { SetViewportOrg(0, 0); ::BitBlt (m_hDestDC, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), m_hDC, 0, 0, SRCCOPY); ::SelectObject (m_hDC, m_hOldBitmap); ::DeleteObject(m_bitmap); } //=========================================================================== // CXTPBitmapDC class //=========================================================================== CXTPBitmapDC::CXTPBitmapDC(CDC* pDC, CBitmap* pBitmap) : m_hDC(pDC->GetSafeHdc()) { m_hOldBitmap = SelectObject(m_hDC, pBitmap->GetSafeHandle()); } CXTPBitmapDC::CXTPBitmapDC(CDC* pDC, HBITMAP hBitmap) : m_hDC(pDC->GetSafeHdc()) { m_hOldBitmap = SelectObject(m_hDC, hBitmap); } CXTPBitmapDC::~CXTPBitmapDC() { ::SelectObject(m_hDC, m_hOldBitmap); } void CXTPBitmapDC::SetBitmap(CBitmap* pBitmap) { ::SelectObject(m_hDC, m_hOldBitmap); m_hOldBitmap = SelectObject(m_hDC, pBitmap->GetSafeHandle()); } //=========================================================================== // CXTPFontDC class //=========================================================================== CXTPFontDC::CXTPFontDC(CDC* pDC, CFont* pFont) { ASSERT(pDC); m_pDC = pDC; m_pOldFont = NULL; m_clrOldTextColor = COLORREF_NULL; if (pFont) { SetFont(pFont); } } CXTPFontDC::CXTPFontDC(CDC* pDC, CFont* pFont, COLORREF clrTextColor) { ASSERT(pDC); ASSERT(clrTextColor != COLORREF_NULL); m_pDC = pDC; m_pOldFont = NULL; m_clrOldTextColor = COLORREF_NULL; if (pFont) { SetFont(pFont); } SetColor(clrTextColor); } CXTPFontDC::~CXTPFontDC() { ReleaseFont(); ReleaseColor(); } void CXTPFontDC::SetFont(CFont* pFont) { if (m_pDC && pFont) { CFont* pFontPrev = m_pDC->SelectObject(pFont); if (!m_pOldFont && pFontPrev) { m_pOldFont = pFontPrev; } } } void CXTPFontDC::SetColor(COLORREF clrTextColor) { ASSERT(clrTextColor != COLORREF_NULL); ASSERT(m_pDC); if (m_pDC && clrTextColor != COLORREF_NULL) { COLORREF clrTextColorPrev= m_pDC->SetTextColor(clrTextColor); if (m_clrOldTextColor == COLORREF_NULL) { m_clrOldTextColor = clrTextColorPrev; } } } void CXTPFontDC::SetFontColor(CFont* pFont, COLORREF clrTextColor) { SetFont(pFont); SetColor(clrTextColor); } void CXTPFontDC::ReleaseFont() { ASSERT(m_pDC); if (m_pDC && m_pOldFont) { m_pDC->SelectObject(m_pOldFont); m_pOldFont = NULL; } } void CXTPFontDC::ReleaseColor() { ASSERT(m_pDC); if (m_pDC && m_clrOldTextColor != COLORREF_NULL) { m_pDC->SetTextColor(m_clrOldTextColor); m_clrOldTextColor = COLORREF_NULL; } } //=========================================================================== // CXTPPenDC class //=========================================================================== CXTPPenDC::CXTPPenDC(CDC* pDC, CPen* pPen) : m_hDC(pDC->GetSafeHdc()) { m_hOldPen = (HPEN)::SelectObject(m_hDC, pPen->GetSafeHandle()); } CXTPPenDC::CXTPPenDC(HDC hDC, COLORREF crColor) : m_hDC (hDC) { VERIFY(m_pen.CreatePen (PS_SOLID, 1, crColor)); m_hOldPen = (HPEN)::SelectObject (m_hDC, m_pen); } CXTPPenDC::~CXTPPenDC () { ::SelectObject (m_hDC, m_hOldPen); } void CXTPPenDC::Color(COLORREF crColor) { ::SelectObject (m_hDC, m_hOldPen); VERIFY(m_pen.DeleteObject()); VERIFY(m_pen.CreatePen (PS_SOLID, 1, crColor)); m_hOldPen = (HPEN)::SelectObject (m_hDC, m_pen); } COLORREF CXTPPenDC::Color() { LOGPEN logPen; m_pen.GetLogPen(&logPen); return logPen.lopnColor; } //=========================================================================== // CXTPBrushDC class //=========================================================================== CXTPBrushDC::CXTPBrushDC(HDC hDC, COLORREF crColor) : m_hDC (hDC) { VERIFY(m_brush.CreateSolidBrush (crColor)); m_hOldBrush = (HBRUSH)::SelectObject (m_hDC, m_brush); } CXTPBrushDC::~CXTPBrushDC() { ::SelectObject(m_hDC, m_hOldBrush); } void CXTPBrushDC::Color(COLORREF crColor) { ::SelectObject(m_hDC, m_hOldBrush); VERIFY(m_brush.DeleteObject()); VERIFY(m_brush.CreateSolidBrush(crColor)); m_hOldBrush = (HBRUSH)::SelectObject (m_hDC, m_brush); } //=========================================================================== // CXTPCompatibleDC class //=========================================================================== CXTPCompatibleDC::CXTPCompatibleDC(CDC* pDC, CBitmap* pBitmap) { CreateCompatibleDC(pDC); m_hOldBitmap = (HBITMAP)::SelectObject(GetSafeHdc(), pBitmap->GetSafeHandle()); } CXTPCompatibleDC::CXTPCompatibleDC(CDC* pDC, HBITMAP hBitmap) { CreateCompatibleDC(pDC); m_hOldBitmap = (HBITMAP)::SelectObject(GetSafeHdc(), hBitmap); } CXTPCompatibleDC::~CXTPCompatibleDC() { ::SelectObject(GetSafeHdc(), m_hOldBitmap); DeleteDC(); } //=========================================================================== // CXTPSplitterTracker class //=========================================================================== CXTPSplitterTracker::CXTPSplitterTracker(BOOL bSolid /*= FALSE*/, BOOL bDesktopDC /*= TRUE*/) { m_bSolid = bSolid; m_rcBoundRect.SetRectEmpty(); m_pDC = 0; m_bDesktopDC = bDesktopDC; m_pWnd = NULL; m_pSplitterWnd = NULL; m_pfnSetLayeredWindowAttributes = NULL; HMODULE hLib = GetModuleHandle(_T("USER32")); if (hLib) { m_pfnSetLayeredWindowAttributes = (PVOID) ::GetProcAddress(hLib, "SetLayeredWindowAttributes"); } } void CXTPSplitterTracker::OnInvertTracker(CRect rect) { ASSERT(!rect.IsRectEmpty()); if (!m_bDesktopDC) { m_pWnd->ScreenToClient(rect); } if (m_pSplitterWnd) { m_pSplitterWnd->SetWindowPos(0, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER); return; } if (!m_pDC) return; if (m_bSolid) { m_pDC->InvertRect(rect); } else { CBrush* pDitherBrush = CDC::GetHalftoneBrush(); CBrush* pBrush = (CBrush*)m_pDC->SelectObject(pDitherBrush); m_pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT); m_pDC->SelectObject(pBrush); } } BOOL CXTPSplitterTracker::Track(CWnd* pTrackWnd, CRect rcAvail, CRect& rectTracker, CPoint point, BOOL bHoriz) { pTrackWnd->SetCapture(); m_pDC = 0; m_pSplitterWnd = NULL; if (m_rcBoundRect.IsRectEmpty() && m_bDesktopDC && XTPSystemVersion()->IsWinVistaOrGreater() && m_pfnSetLayeredWindowAttributes && !XTPColorManager()->IsLowResolution()) { m_pSplitterWnd = new CWnd(); m_pSplitterWnd->CreateEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH)), 0, WS_POPUP, CRect(0, 0, 0, 0), NULL, 0); ((PFNSETLAYEREDWINDOWATTRIBUTES)m_pfnSetLayeredWindowAttributes)(m_pSplitterWnd->m_hWnd, 0, 100, LWA_ALPHA); } else { if (m_bDesktopDC) m_pWnd = CWnd::GetDesktopWindow(); else m_pWnd = pTrackWnd; if (m_pWnd->LockWindowUpdate()) m_pDC = m_pWnd->GetDCEx(NULL, DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); else m_pDC = m_pWnd->GetDCEx(NULL, DCX_WINDOW | DCX_CACHE); ASSERT(m_pDC != NULL); } CPoint ptOffset = bHoriz ? CPoint(rectTracker.left - point.x, 0) : CPoint(0, rectTracker.top - point.y); OnInvertTracker(rectTracker); if (!m_rcBoundRect.IsRectEmpty()) OnInvertTracker(m_rcBoundRect); BOOL bAccept = FALSE; while (CWnd::GetCapture() == pTrackWnd) { MSG msg; if (!GetMessage(&msg, NULL, 0, 0)) break; if (msg.message == WM_MOUSEMOVE) { point = CPoint(msg.lParam); pTrackWnd->ClientToScreen(&point); point += ptOffset; point.x = max(min(point.x, rcAvail.right), rcAvail.left); point.y = max(min(point.y, rcAvail.bottom), rcAvail.top); if (bHoriz) { if (rectTracker.left != point.x) { OnInvertTracker(rectTracker); rectTracker.OffsetRect(point.x - rectTracker.left, 0); OnInvertTracker(rectTracker); } } else { if (rectTracker.top != point.y) { OnInvertTracker(rectTracker); rectTracker.OffsetRect(0, point.y - rectTracker.top); OnInvertTracker(rectTracker); } } } else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) break; else if (msg.message == WM_LBUTTONUP) { bAccept = TRUE; break; } else ::DispatchMessage(&msg); } if (!m_rcBoundRect.IsRectEmpty()) OnInvertTracker(m_rcBoundRect); OnInvertTracker(rectTracker); if (CWnd::GetCapture() == pTrackWnd) ReleaseCapture(); if (m_pSplitterWnd) { m_pSplitterWnd->DestroyWindow(); delete m_pSplitterWnd; m_pSplitterWnd = NULL; } else { m_pWnd->UnlockWindowUpdate(); if (m_pDC != NULL) { m_pWnd->ReleaseDC(m_pDC); m_pDC = NULL; } } return bAccept; } //=========================================================================== // CXTPDrawHelpers class //=========================================================================== CXTPDrawHelpers::CXTPDrawHelpers() { m_pfnFastGradientFill = 0; m_pfnAlphaBlend = 0; m_pfnTransparentBlt = 0; // Don't use CXTPModuleHandle to reduce dependence between common source m_hMsImgDll = ::LoadLibrary(_T("msimg32.dll")); if (m_hMsImgDll) { m_pfnFastGradientFill = (PFNGRADIENTFILL)GetProcAddress(m_hMsImgDll, "GradientFill"); m_pfnAlphaBlend = (PFNALPHABLEND)::GetProcAddress(m_hMsImgDll, "AlphaBlend"); m_pfnTransparentBlt = (PFNTRANSPARENTBLT)::GetProcAddress(m_hMsImgDll, "TransparentBlt"); } } CXTPDrawHelpers* AFX_CDECL XTPDrawHelpers() { static CXTPDrawHelpers s_instance; // singleton return &s_instance; } CXTPDrawHelpers::~CXTPDrawHelpers() { if (m_hMsImgDll != NULL) { //::FreeLibrary(m_hMsImgDll); Dangerous to call FreeLibrary in destructor of static object. } } BOOL CXTPDrawHelpers::GradientFill(HDC hdc, PTRIVERTEX pVertex, ULONG dwNumVertex, PVOID pMesh, ULONG dwNumMesh, ULONG dwMode) { if (m_pfnFastGradientFill) { return (*m_pfnFastGradientFill)(hdc, pVertex, dwNumVertex, pMesh, dwNumMesh, dwMode); } return FALSE; } void CXTPDrawHelpers::GradientFillSlow(CDC* pDC, LPCRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz) { int cx = max(1, lpRect->right - lpRect->left); int cy = max(1, lpRect->bottom - lpRect->top); CRect rc; pDC->GetClipBox(&rc); if (rc.IsRectEmpty()) rc = *lpRect; else rc.IntersectRect(rc, lpRect); if (bHorz) { for (int nX = rc.left; nX < rc.right; nX++) { pDC->FillSolidRect(nX, rc.top, 1, rc.Height(), BlendColors( crFrom, crTo, (double)(1.0 - ((nX - lpRect->left) / (double)cx)))); } } else { for (int nY = rc.top; nY < rc.bottom; nY++) { pDC->FillSolidRect(rc.left, nY, rc.Width(), 1, BlendColors( crFrom, crTo, (double)(1.0 - ((nY - lpRect->top)) / (double)cy))); } } } void CXTPDrawHelpers::GradientFillFast(CDC* pDC, LPCRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz) { TRIVERTEX vert[2]; vert[0].x = lpRect->left; vert[0].y = lpRect->top; vert[0].Red = (COLOR16)(GetRValue(crFrom) << 8); vert[0].Green = (COLOR16)(GetGValue(crFrom) << 8); vert[0].Blue = (COLOR16)(GetBValue(crFrom) << 8); vert[0].Alpha = 0x0000; vert[1].x = lpRect->right; vert[1].y = lpRect->bottom; vert[1].Red = (COLOR16)(GetRValue(crTo) << 8); vert[1].Green = (COLOR16)(GetGValue(crTo) << 8); vert[1].Blue = (COLOR16)(GetBValue(crTo) << 8); vert[1].Alpha = 0x0000; GRADIENT_RECT gRect = { 0, 1 }; GradientFill(*pDC, vert, 2, &gRect, 1, bHorz ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V); } void CXTPDrawHelpers::GradientFill(CDC* pDC, LPCRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz) { if (!lpRect) return; if (::IsRectEmpty(lpRect)) return; if (IsLowResolution(pDC->GetSafeHdc())) { pDC->FillSolidRect(lpRect, crFrom); } else if (crFrom == crTo) { pDC->FillSolidRect(lpRect, crFrom); } else if ((m_pfnFastGradientFill == NULL) || (IsContextRTL(pDC) && XTPSystemVersion()->IsWin9x())) { GradientFillSlow(pDC, lpRect, crFrom, crTo, bHorz); } else { GradientFillFast(pDC, lpRect, crFrom, crTo, bHorz); } } void CXTPDrawHelpers::GradientFill(CDC* pDC, LPCRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz, LPCRECT lpRectClip) { CRect rc(lpRect); if (lpRectClip == NULL) { GradientFill(pDC, lpRect, crFrom, crTo, bHorz); return; } COLORREF crFrom1 = crFrom; if (bHorz) { if (rc.top < lpRectClip->top) { rc.top = lpRectClip->top; } if (rc.bottom > lpRectClip->bottom) { rc.bottom = lpRectClip->bottom; } if ((rc.left > lpRectClip->right) || (rc.right < lpRectClip->left)) return; if (rc.left < lpRectClip->left) { rc.left = lpRectClip->left; crFrom = BlendColors(crFrom, crTo, (float)(lpRect->right - lpRectClip->left) / (float)(lpRect->right - lpRect->left)); } if (rc.right > lpRectClip->right) { rc.right = lpRectClip->right; crTo = BlendColors(crFrom1, crTo, (float)(lpRect->right - lpRectClip->right) / (float)(lpRect->right - lpRect->left)); } GradientFill(pDC, rc, crFrom, crTo, bHorz); } else { if (rc.left < lpRectClip->left) { rc.left = lpRectClip->left; } if (rc.right > lpRectClip->right) { rc.right = lpRectClip->right; } if ((rc.top > lpRectClip->bottom) || (rc.bottom < lpRectClip->top)) return; if (rc.top < lpRectClip->top) { rc.top = lpRectClip->top; crFrom = BlendColors(crFrom, crTo, (float)(lpRect->bottom - lpRectClip->top) / (float)(lpRect->bottom - lpRect->top)); } if (rc.bottom > lpRectClip->bottom) { rc.bottom = lpRectClip->bottom; crTo = BlendColors(crFrom1, crTo, (float)(lpRect->bottom - lpRectClip->bottom) / (float)(lpRect->bottom - lpRect->top)); } GradientFill(pDC, rc, crFrom, crTo, bHorz); } } void CXTPDrawHelpers::GradientFill(CDC* pDC, LPCRECT lpRect, const CXTPPaintManagerColorGradient& grc, BOOL bHorz, LPCRECT lpRectClip) { // using gradient factor color gradient fill if (grc.fGradientFactor != 0.5f) { COLORREF clrMid = BlendColors(grc.clrLight, grc.clrDark, grc.fGradientFactor); if (bHorz) { CRect rcLeft(lpRect); rcLeft.right -= rcLeft.Width()/2; GradientFill(pDC, &rcLeft, grc.clrLight, clrMid, bHorz, lpRectClip); CRect rcRight(lpRect); rcRight.left = rcLeft.right; GradientFill(pDC, &rcRight, clrMid, grc.clrDark, bHorz, lpRectClip); } else { CRect rcTop(lpRect); rcTop.bottom -= rcTop.Height()/2; GradientFill(pDC, &rcTop, grc.clrLight, clrMid, bHorz, lpRectClip); CRect rcBottom(lpRect); rcBottom.top = rcTop.bottom; GradientFill(pDC, &rcBottom, clrMid, grc.clrDark, bHorz, lpRectClip); } } // using 2 color gradient fill else { GradientFill(pDC, lpRect, grc.clrLight, grc.clrDark, bHorz, lpRectClip); } } void CXTPDrawHelpers::ExcludeCorners(CDC* pDC, CRect rc) { pDC->ExcludeClipRect(rc.left, rc.top, rc.left + 1, rc.top + 1); pDC->ExcludeClipRect(rc.right - 1, rc.top, rc.right, rc.top + 1); pDC->ExcludeClipRect(rc.left, rc.bottom - 1, rc.left + 1, rc.bottom); pDC->ExcludeClipRect(rc.right - 1, rc.bottom - 1, rc.right, rc.bottom); } void CXTPDrawHelpers::StripMnemonics(CString& strClear) { for (int i = 0; i < strClear.GetLength(); i++) { if (strClear[i] == _T('&')) // Converts "&&" to "&" and "&&&&" to "&&" { strClear.Delete(i); } } } void CXTPDrawHelpers::StripMnemonics(LPTSTR lpszClear) { if (lpszClear == NULL || lpszClear == LPSTR_TEXTCALLBACK) return; LPTSTR lpszResult = lpszClear; while (*lpszClear) { if (*lpszClear == _T('&') && *(lpszClear + 1) != _T('&')) { lpszClear++; continue; } *lpszResult++ = *lpszClear++; } *lpszResult = 0; } void CXTPDrawHelpers::BlurPoints(CDC* pDC, LPPOINT pts, int nCount) { for (int i = 0; i < nCount; i += 2) { CPoint ptBlur = pts[i]; CPoint ptDirection(pts[i].x + pts[i + 1].x, pts[i].y + pts[i + 1].y); COLORREF clrBlur = pDC->GetPixel(ptDirection); COLORREF clrDirection = pDC->GetPixel(ptBlur); pDC->SetPixel(ptBlur, RGB( (GetRValue(clrBlur) + GetRValue(clrDirection)) / 2, (GetGValue(clrBlur) + GetGValue(clrDirection)) / 2, (GetBValue(clrBlur) + GetBValue(clrDirection)) / 2)); } } COLORREF CXTPDrawHelpers::BlendColors(COLORREF crA, COLORREF crB, double fAmountA) { double fAmountB = (1.0 - fAmountA); int btR = (int)(GetRValue(crA) * fAmountA + GetRValue(crB) * fAmountB); int btG = (int)(GetGValue(crA) * fAmountA + GetGValue(crB) * fAmountB); int btB = (int)(GetBValue(crA) * fAmountA + GetBValue(crB) * fAmountB); return RGB(min(255, btR), (BYTE)min(255, btG), (BYTE)min(255, btB)); } COLORREF CXTPDrawHelpers::DarkenColor(long lScale, COLORREF lColor) { long red = MulDiv(GetRValue(lColor), (255 - lScale), 255); long green = MulDiv(GetGValue(lColor), (255 - lScale), 255); long blue = MulDiv(GetBValue(lColor), (255 - lScale), 255); return RGB(red, green, blue); } COLORREF CXTPDrawHelpers::LightenColor(long lScale, COLORREF lColor) { long R = MulDiv(255 - GetRValue(lColor), lScale, 255) + GetRValue(lColor); long G = MulDiv(255 - GetGValue(lColor), lScale, 255) + GetGValue(lColor); long B = MulDiv(255 - GetBValue(lColor), lScale, 255) + GetBValue(lColor); return RGB(R, G, B); } CPoint CXTPDrawHelpers::Dlu2Pix(int dluX, int dluY) { CPoint baseXY(::GetDialogBaseUnits()); CPoint pixXY(0,0); pixXY.x = ::MulDiv(dluX, baseXY.x, 4); pixXY.y = ::MulDiv(dluY, baseXY.y, 8); return pixXY; } COLORREF CXTPDrawHelpers::RGBtoHSL(COLORREF rgb) { int delta, sum; int nH, nS, nL; int r = GetRValue(rgb); int g = GetGValue(rgb); int b = GetBValue(rgb); int cmax = ((r) >= (g) ? ((r) >= (b) ? (r) : (b)) : (g) >= (b) ? (g) : (b)); int cmin = ((r) <= (g) ? ((r) <= (b) ? (r) : (b)) : (g) <= (b) ? (g) : (b)); nL = (cmax + cmin + 1) / 2; if (cmax == cmin) { nH = 255; // H is really undefined nS = 0; } else { delta = cmax - cmin; sum = cmax + cmin; if (nL < 127) nS = ((delta + 1) * 256) / sum; else nS = (delta * 256) / ((2 * 256) - sum); if (r == cmax) nH = ((g - b) * 256) / delta; else if (g == cmax) nH = (2 * 256) + ((b - r) * 256) / delta; else nH = (4 * 256) + ((r - g) * 256) / delta; nH /= 6; if (nH < 0) nH += 256; } nH = nH * 239 / 255; nS = nS * 240 / 255; nL = nL * 240 / 255; return RGB((BYTE)min(nH, 239), (BYTE)min(nS, 240), (BYTE)min(nL, 240)); } void CXTPDrawHelpers::RGBtoHSL(COLORREF clr, double& h, double& s, double& l) { double r = (double)GetRValue(clr)/255.0; double g = (double)GetGValue(clr)/255.0; double b = (double)GetBValue(clr)/255.0; double maxcolor = __max(r, __max(g, b)); double mincolor = __min(r, __min(g, b)); l = (maxcolor + mincolor)/2; if (maxcolor == mincolor) { h = 0; s = 0; } else { if (l < 0.5) s = (maxcolor-mincolor)/(maxcolor + mincolor); else s = (maxcolor-mincolor)/(2.0-maxcolor-mincolor); if (r == maxcolor) h = (g-b)/(maxcolor-mincolor); else if (g == maxcolor) h = 2.0+(b-r)/(maxcolor-mincolor); else h = 4.0+(r-g)/(maxcolor-mincolor); h /= 6.0; if (h < 0.0) h += 1; } } double CXTPDrawHelpers::HueToRGB(double temp1, double temp2, double temp3) { if (temp3 < 0) temp3 = temp3 + 1.0; if (temp3 > 1) temp3 = temp3-1.0; if (6.0*temp3 < 1) return (temp1+(temp2-temp1)*temp3 * 6.0); else if (2.0*temp3 < 1) return temp2; else if (3.0*temp3 < 2.0) return (temp1+(temp2-temp1)*((2.0/3.0)-temp3)*6.0); return temp1; } int CXTPDrawHelpers::HueToRGB(int m1, int m2, int h) { if (h < 0) h += 255; if (h > 255) h -= 255; if ((6 * h) < 255) return ((m1 + ((m2 - m1) / 255 * h * 6)) / 255); if ((2 * h) < 255) return m2 / 255; if ((3 * h) < (2 * 255)) return ((m1 + (m2 - m1) / 255 * ((255 * 2 / 3) - h) * 6) / 255); return (m1 / 255); } COLORREF CXTPDrawHelpers::HSLtoRGB(COLORREF hsl) { int r, g, b; int m1, m2; int nH = GetRValue(hsl) * 255 / 239; int nS = GetGValue(hsl) * 255 / 240; int nL = GetBValue(hsl) * 255 / 240; if (nS == 0) r = g = b = nL; else { if (nL <= 127) m2 = nL * (255 + nS); else m2 = (nL + nS - ((nL * nS) / 255)) * 255; m1 = (2 * 255 * nL) - m2; r = HueToRGB(m1, m2, nH + (255 / 3)); g = HueToRGB(m1, m2, nH); b = HueToRGB(m1, m2, nH - (255 / 3)); } return RGB((BYTE)min(r, 255), (BYTE)min(g, 255), (BYTE)min(b, 255)); } COLORREF CXTPDrawHelpers::HSLtoRGB(double h, double s, double l) { double r, g, b; double temp1, temp2; if (s == 0) { r = g = b = l; } else { if (l < 0.5) temp2 = l*(1.0 + s); else temp2 = l + s-l*s; temp1 = 2.0 * l-temp2; r = HueToRGB(temp1, temp2, h + 1.0/3.0); g = HueToRGB(temp1, temp2, h); b = HueToRGB(temp1, temp2, h - 1.0/3.0); } return RGB((BYTE)(r * 255), (BYTE)(g * 255), (BYTE)(b * 255)); } static int CALLBACK XTPEnumFontFamExProc(ENUMLOGFONTEX* pelf, NEWTEXTMETRICEX* /*lpntm*/, int /*FontType*/, LPVOID pThis) { LPCTSTR strFontName = (LPCTSTR)pThis; CString strFaceName = pelf->elfLogFont.lfFaceName; if (strFaceName.CompareNoCase(strFontName) == 0) return 0; return 1; } BOOL CXTPDrawHelpers::FontExists(LPCTSTR strFaceName) { // Enumerate all styles and charsets of all fonts: LOGFONT lfEnum; ::ZeroMemory(&lfEnum, sizeof(LOGFONT)); lfEnum.lfFaceName[ 0 ] = 0; lfEnum.lfCharSet = DEFAULT_CHARSET; CWindowDC dc(NULL); return ::EnumFontFamiliesEx(dc.m_hDC, &lfEnum, (FONTENUMPROC) XTPEnumFontFamExProc, (LPARAM)strFaceName, 0) == 0; } CString CXTPDrawHelpers::GetDefaultFontName() { LOGFONT lfFont; ZeroMemory(&lfFont, sizeof(LOGFONT)); ::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lfFont); return CString(lfFont.lfFaceName); } CString AFX_CDECL CXTPDrawHelpers::GetVerticalFontName(BOOL bUseOfficeFont) { LOGFONT lfFont; ZeroMemory(&lfFont, sizeof(LOGFONT)); ::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lfFont); bool bUseSystemFont = lfFont.lfCharSet > SYMBOL_CHARSET; if (bUseSystemFont && !XTPSystemVersion()->IsWin2KOrGreater()) bUseSystemFont = FALSE; if (bUseSystemFont && (_tcsicmp(lfFont.lfFaceName, _T("MS Shell Dlg")) == 0)) bUseSystemFont = FALSE; // Can draw it vertically in Windows 2000. CString strVerticalFaceName = _T("Arial"); LPCTSTR strOfficeFont = _T("Tahoma"); if (bUseSystemFont || !FontExists(strVerticalFaceName)) { strVerticalFaceName = lfFont.lfFaceName; } else if (bUseOfficeFont && !bUseSystemFont && FontExists(strOfficeFont)) { strVerticalFaceName = strOfficeFont; } return strVerticalFaceName; } BOOL CXTPDrawHelpers::IsContextRTL(CDC* pDC) { return pDC && IsContextRTL(pDC->GetSafeHdc()); } BOOL CXTPDrawHelpers::IsContextRTL(HDC hDC) { typedef DWORD (CALLBACK* PFNGDIGETLAYOUTPROC)(HDC); static PFNGDIGETLAYOUTPROC s_pfn = (PFNGDIGETLAYOUTPROC)-1; if (s_pfn == (PFNGDIGETLAYOUTPROC)-1) { HINSTANCE hInst = ::GetModuleHandleA("GDI32.DLL"); s_pfn = hInst ? (PFNGDIGETLAYOUTPROC)GetProcAddress(hInst, "GetLayout") : NULL; } return s_pfn ? (*s_pfn)(hDC) : FALSE; } void CXTPDrawHelpers::SetContextRTL(CDC* pDC, BOOL bLayoutRTL) { if (pDC) SetContextRTL(pDC->GetSafeHdc(), bLayoutRTL); } void CXTPDrawHelpers::SetContextRTL(HDC hDC, BOOL bLayoutRTL) { typedef DWORD (CALLBACK* PFNGDISETLAYOUTPROC)(HDC, DWORD); static PFNGDISETLAYOUTPROC s_pfn = (PFNGDISETLAYOUTPROC)-1; if (s_pfn == (PFNGDISETLAYOUTPROC)-1) { HINSTANCE hInst = ::GetModuleHandleA("GDI32.DLL"); s_pfn = hInst ? (PFNGDISETLAYOUTPROC)GetProcAddress(hInst, "SetLayout") : NULL; } if (s_pfn != NULL) { (*s_pfn)(hDC, bLayoutRTL); } } void CXTPDrawHelpers::KeyToLayout(CWnd* pWnd, UINT& nChar) { ASSERT(pWnd); if (!pWnd || !pWnd->GetSafeHwnd()) return; if (nChar == VK_LEFT && pWnd->GetExStyle() & WS_EX_LAYOUTRTL) nChar = VK_RIGHT; else if (nChar == VK_RIGHT && pWnd->GetExStyle() & WS_EX_LAYOUTRTL) nChar = VK_LEFT; } void CXTPDrawHelpers::Triangle(CDC* pDC, CPoint pt0, CPoint pt1, CPoint pt2, COLORREF clr) { CXTPPenDC pen (*pDC, clr); CXTPBrushDC brush (*pDC, clr); Triangle(pDC, pt0, pt1, pt2); } BOOL CXTPDrawHelpers::DrawLine(CDC* pDC, int x, int y, int nLength, int nHeight, COLORREF crLine) { if (pDC->GetSafeHdc()) { CXTPPenDC penDC(*pDC, crLine); pDC->MoveTo(x, y); pDC->LineTo(x + nLength, y + nHeight); return TRUE; } return FALSE; } DWORD CXTPDrawHelpers::GetComCtlVersion() { return XTPSystemVersion()->GetComCtlVersion(); } BOOL CXTPDrawHelpers::IsLowResolution(HDC hDC/* = 0*/) { return XTPColorManager()->IsLowResolution(hDC); } CRect CXTPDrawHelpers::GetWorkArea(LPCRECT rect) { return XTPMultiMonitor()->GetWorkArea(rect); } CRect CXTPDrawHelpers::GetWorkArea(const CWnd* pWnd) { return XTPMultiMonitor()->GetWorkArea(pWnd); } CRect CXTPDrawHelpers::GetScreenArea(const CWnd* pWnd) { return XTPMultiMonitor()->GetScreenArea(pWnd); } CRect CXTPDrawHelpers::GetWorkArea(const POINT& point) { return XTPMultiMonitor()->GetWorkArea(point); } CRect CXTPDrawHelpers::GetWorkArea() { return XTPMultiMonitor()->GetWorkArea(); } BOOL CXTPDrawHelpers::TakeSnapShot(CWnd* pWnd, CBitmap& bmpSnapshot) { if (!::IsWindow(pWnd->GetSafeHwnd())) return FALSE; CWnd *pWndParent = pWnd->GetParent(); if (::IsWindow(pWndParent->GetSafeHwnd())) { if (bmpSnapshot.GetSafeHandle() != NULL) bmpSnapshot.DeleteObject(); //convert our coordinates to our parent coordinates. CXTPWindowRect rc(pWnd); pWndParent->ScreenToClient(&rc); //copy what's on the parents background at this point CDC *pDC = pWndParent->GetDC(); CDC memDC; memDC.CreateCompatibleDC(pDC); bmpSnapshot.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height()); CXTPBitmapDC bitmapDC(&memDC, &bmpSnapshot); memDC.BitBlt(0, 0, rc.Width(), rc.Height(), pDC, rc.left, rc.top, SRCCOPY); pWndParent->ReleaseDC(pDC); return TRUE; } return FALSE; } BOOL CXTPDrawHelpers::DrawTransparentBack(CDC* pDC, CWnd* pWnd, CBitmap& bmpSnapshot) { if (!::IsWindow(pWnd->GetSafeHwnd())) return FALSE; if (::GetWindowLong(pWnd->GetSafeHwnd(), GWL_EXSTYLE) & WS_EX_TRANSPARENT) { // Get background. if (!TakeSnapShot(pWnd, bmpSnapshot)) return FALSE; CXTPClientRect rc(pWnd); CDC memDC; memDC.CreateCompatibleDC(pDC); CXTPBitmapDC bitmapDC(&memDC, &bmpSnapshot); pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY); return TRUE; } return FALSE; } BOOL CXTPDrawHelpers::IsTopParentActive(HWND hWnd) { HWND hwndForeground = ::GetForegroundWindow(); HWND hWndT; while ((hWndT = AfxGetParentOwner(hWnd)) != NULL) { hWnd = hWndT; } HWND hwndActivePopup = ::GetLastActivePopup(hWnd); if (hwndForeground == hwndActivePopup) return TRUE; return FALSE; } void CXTPDrawHelpers::ScreenToWindow(CWnd* pWnd, LPPOINT lpPoint) { RECT rc; ::GetWindowRect(pWnd->GetSafeHwnd(), &rc); lpPoint->y -= rc.top; if (GetWindowLong(pWnd->GetSafeHwnd(), GWL_EXSTYLE) & WS_EX_LAYOUTRTL ) { lpPoint->x = rc.right - lpPoint->x; } else { lpPoint->x -= rc.left; } } BOOL AFX_CDECL CXTPDrawHelpers::RegisterWndClass(HINSTANCE hInstance, LPCTSTR lpszClassName, UINT style, HICON hIcon, HBRUSH hbrBackground) { WNDCLASS wndcls; ZeroMemory(&wndcls, sizeof(wndcls)); wndcls.style = style; wndcls.lpfnWndProc = ::DefWindowProc; wndcls.hInstance = hInstance ? hInstance : AfxGetInstanceHandle(); wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); wndcls.lpszClassName = lpszClassName; wndcls.hIcon = hIcon; wndcls.hbrBackground = hbrBackground; return AfxRegisterClass(&wndcls); } void CXTPDrawHelpers::GetWindowCaption(HWND hWnd, CString& strWindowText) { #ifdef _UNICODE int nLen = (int)::DefWindowProc(hWnd, WM_GETTEXTLENGTH, 0, 0); ::DefWindowProc(hWnd, WM_GETTEXT, nLen + 1, (WPARAM)(LPCTSTR)strWindowText.GetBuffer(nLen)); strWindowText.ReleaseBuffer(); #else int nLen = ::GetWindowTextLength(hWnd); ::GetWindowText(hWnd, strWindowText.GetBufferSetLength(nLen), nLen + 1); strWindowText.ReleaseBuffer(); #endif } BOOL AFX_CDECL XTPTrackMouseEvent(HWND hWndTrack, DWORD dwFlags /*= TME_LEAVE*/, DWORD dwHoverTime /*= HOVER_DEFAULT*/) { ASSERT(::IsWindow(hWndTrack)); TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = dwFlags; tme.dwHoverTime = dwHoverTime; tme.hwndTrack = hWndTrack; return ::_TrackMouseEvent(&tme); } BOOL AFX_CDECL XTPGetPrinterDeviceDefaults(HGLOBAL& ref_hDevMode, HGLOBAL& ref_hDevNames) { CWinApp* pApp = AfxGetApp(); if (pApp) { PRINTDLG _pd; ::ZeroMemory(&_pd, sizeof(_pd)); if (pApp->GetPrinterDeviceDefaults(&_pd)) { ref_hDevMode = _pd.hDevMode; ref_hDevNames = _pd.hDevNames; return TRUE; } } return FALSE; } BOOL CXTPDrawHelpers::GetIconLogFont(LOGFONT* plf) { VERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), plf, 0)); plf->lfCharSet = XTPResourceManager()->GetFontCharset(); return TRUE; } ////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CXTPPrinterInfo, CCmdTarget) CXTPPrinterInfo::CXTPPrinterInfo() { } CXTPPrinterInfo::~CXTPPrinterInfo() { } CString CXTPPrinterInfo::GetName(XTPEnumDeviceName eNameID) { CString strName; HGLOBAL hDevMode = NULL, hDevNames = NULL; if (XTPGetPrinterDeviceDefaults(hDevMode, hDevNames) && hDevNames != NULL) { LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(hDevNames); if (lpDev) { strName = (LPCTSTR)lpDev + _GetNameOffset(lpDev, eNameID); } ::GlobalUnlock(hDevNames); } return strName; } WORD CXTPPrinterInfo::_GetNameOffset(LPDEVNAMES pDevNames, XTPEnumDeviceName eNameID) { ASSERT(pDevNames); if (!pDevNames) return 0; switch (eNameID) { case xtpDevName_Driver: return pDevNames->wDriverOffset; case xtpDevName_Device: return pDevNames->wDeviceOffset; case xtpDevName_Port: return pDevNames->wOutputOffset; }; ASSERT(FALSE); return 0; } ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CXTPPrintPageHeaderFooter, CCmdTarget) CXTPPrintPageHeaderFooter::CXTPPrintPageHeaderFooter(CXTPPrintOptions* pOwner, BOOL bHeader) { ASSERT(pOwner); m_bHeader = bHeader; m_pOwner = pOwner; VERIFY(CXTPDrawHelpers::GetIconLogFont(&m_lfFont)); m_clrColor = RGB(0, 0, 0); } CXTPPrintPageHeaderFooter::~CXTPPrintPageHeaderFooter() { } void CXTPPrintPageHeaderFooter::Set(const CXTPPrintPageHeaderFooter* pSrc) { ASSERT(pSrc); if (!pSrc) return; m_lfFont = pSrc->m_lfFont; m_clrColor = pSrc->m_clrColor; m_strFormatString = pSrc->m_strFormatString; m_strLeft = pSrc->m_strLeft; m_strCenter = pSrc->m_strCenter; m_strRight = pSrc->m_strRight; } void CXTPPrintPageHeaderFooter::Clear() { VERIFY(CXTPDrawHelpers::GetIconLogFont(&m_lfFont)); m_clrColor = RGB(0, 0, 0); m_strFormatString.Empty(); m_strLeft.Empty(); m_strCenter.Empty(); m_strRight.Empty(); } BOOL CXTPPrintPageHeaderFooter::IsEmpty() { return m_strLeft.IsEmpty() && m_strCenter.IsEmpty() && m_strRight.IsEmpty(); } //=========================================================================== // &w Window title // // &d Date in short format (as specified by Regional Settings in Control Panel) // &D Date in long format (as specified by Regional Settings in Control Panel) // // &t Time in the format specified by Regional Settings in Control Panel // &T Time in 24-hour format // // &p Current page number // &P Total number of pages // &# Ordinal page number (even for WYSIWYG mode) // // &b The text immediately following these characters as centered. // &b&b The text immediately following the first "&b" as centered, and the text following the second "&b" as right-justified. // // && A single ampersand (&) //=========================================================================== void CXTPPrintPageHeaderFooter::FormatTexts(CPrintInfo* pInfo, LPCTSTR pcszWndTitle, int nVirtualPage) { ASSERT(pInfo); if (m_strFormatString.IsEmpty() || !pInfo) return; LCID lcidLocale = m_pOwner ? m_pOwner->GetActiveLCID() : LOCALE_USER_DEFAULT; CString strFormat = m_strFormatString; strFormat.Replace(_T("&&"), _T("\1")); CString str_p, str_P = _T("*"); if (nVirtualPage > 0) str_p.Format(_T("%d-%d"), pInfo->m_nCurPage, nVirtualPage); else str_p.Format(_T("%d"), pInfo->m_nCurPage); if (pInfo->GetMaxPage() != 65535) str_P.Format(_T("%d"), pInfo->GetMaxPage()); strFormat.Replace(_T("&p"), str_p); strFormat.Replace(_T("&P"), str_P); strFormat.Replace(_T("\\n"), _T("\n")); _SplitFormatLCR(strFormat); _FormatDateTime(m_strLeft, lcidLocale); _FormatDateTime(m_strCenter, lcidLocale); _FormatDateTime(m_strRight, lcidLocale); if (pcszWndTitle) { m_strLeft.Replace(_T("&w"), pcszWndTitle); m_strCenter.Replace(_T("&w"), pcszWndTitle); m_strRight.Replace(_T("&w"), pcszWndTitle); } m_strLeft.Replace( _T("\1"), _T("&")); m_strCenter.Replace(_T("\1"), _T("&")); m_strRight.Replace(_T("\1"), _T("&")); } CString CXTPPrintPageHeaderFooter::GetParentFrameTitle(CWnd* pWnd) { CString strTitle; ASSERT(pWnd); if (!pWnd) return strTitle; pWnd->GetWindowText(strTitle); if (strTitle.IsEmpty() || !pWnd->IsFrameWnd()) { if (pWnd->GetParentFrame()) pWnd->GetParentFrame()->GetWindowText(strTitle); if (strTitle.IsEmpty()) { if (pWnd->GetParentOwner()) pWnd->GetParentOwner()->GetWindowText(strTitle); } } return strTitle; } void CXTPPrintPageHeaderFooter::_FormatDateTime(CString& strFormat, LCID lcidLocale) { SYSTEMTIME stNow; ::GetLocalTime(&stNow); const int cnBufferSize = 200; TCHAR szDateFormatShort[cnBufferSize] = {0}; TCHAR szDateFormatLong[cnBufferSize] = {0}; TCHAR szTimeFormat[cnBufferSize] = {0}; TCHAR szTimeFormat24[cnBufferSize] = {0}; ::GetDateFormat(lcidLocale, DATE_SHORTDATE, &stNow, NULL, szDateFormatShort, cnBufferSize); ::GetDateFormat(lcidLocale, DATE_LONGDATE, &stNow, NULL, szDateFormatLong, cnBufferSize); ::GetTimeFormat(lcidLocale, 0, &stNow, NULL, szTimeFormat, cnBufferSize); DWORD dwFlags24h = TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER; ::GetTimeFormat(lcidLocale, dwFlags24h, &stNow, NULL, szTimeFormat24, cnBufferSize); strFormat.Replace(_T("&d"), szDateFormatShort); // &d Date in short format (as specified by Regional Settings in Control Panel) strFormat.Replace(_T("&D"), szDateFormatLong); // &D Date in long format (as specified by Regional Settings in Control Panel) strFormat.Replace(_T("&t"), szTimeFormat); // &t Time in the format specified by Regional Settings in Control Panel strFormat.Replace(_T("&T"), szTimeFormat24); // &T Time in 24-hour format } void CXTPPrintPageHeaderFooter::_SplitFormatLCR(CString strFormat) { m_strLeft.Empty(); m_strCenter.Empty(); m_strRight.Empty(); int nAmpBidx = strFormat.Find(_T("&b")); if (nAmpBidx < 0) { m_strLeft = strFormat; } else if (nAmpBidx >= 0) { if (nAmpBidx > 0) m_strLeft = strFormat.Left(nAmpBidx); strFormat.Delete(0, nAmpBidx + 2); nAmpBidx = strFormat.Find(_T("&b")); if (nAmpBidx < 0) { m_strCenter = strFormat; } else if (nAmpBidx >= 0) { if (nAmpBidx > 0) m_strCenter = strFormat.Left(nAmpBidx); strFormat.Delete(0, nAmpBidx + 2); m_strRight = strFormat; } } } int CXTPPrintPageHeaderFooter::fnYi(int Xi, int Wi) { int nYi = Wi / Xi; int nYi_ = Wi % Xi; return nYi + (nYi_ ? 1 : 0); } int CXTPPrintPageHeaderFooter::_Calc3ColSizesIfSingleCol(CDC* pDC, int nW, const CString& str1, const CString& str2, const CString& str3, CSize& rsz1, CSize& rsz2, CSize& rsz3) { CString str1trim = str1; CString str2trim = str2; CString str3trim = str3; str1trim.TrimLeft(); str2trim.TrimLeft(); str3trim.TrimLeft(); UINT uFlags = DT_TOP | DT_WORDBREAK | DT_CALCRECT; rsz1 = rsz2 = rsz3 = CSize(0, 0); if (!str1trim.IsEmpty() && str2trim.IsEmpty() && str3trim.IsEmpty()) { CRect rcText1(0, 0, nW, 32000); rsz1.cx = nW; return rsz1.cy = pDC->DrawText(str1, &rcText1, uFlags | DT_LEFT); } if (str1trim.IsEmpty() && !str2trim.IsEmpty() && str3trim.IsEmpty()) { CRect rcText2(0, 0, nW, 32000); rsz2.cx = nW; return rsz2.cy = pDC->DrawText(str2, &rcText2, uFlags | DT_CENTER); } if (str1trim.IsEmpty() && str2trim.IsEmpty() && !str3trim.IsEmpty()) { CRect rcText3(0, 0, nW, 32000); rsz3.cx = nW; return rsz3.cy = pDC->DrawText(str3, &rcText3, uFlags | DT_RIGHT); } return -1; } int CXTPPrintPageHeaderFooter::Calc3ColSizes(CDC* pDC, int nW, const CString& str1, const CString& str2, const CString& str3, CSize& rsz1, CSize& rsz2, CSize& rsz3) { ASSERT(pDC); if (!pDC) return 0; int nIfSingleCol = _Calc3ColSizesIfSingleCol(pDC, nW, str1, str2, str3, rsz1, rsz2, rsz3); if (nIfSingleCol >= 0) return nIfSingleCol; int nW1 = pDC->GetTextExtent(str1).cx; int nW2 = pDC->GetTextExtent(str2).cx; int nW3 = pDC->GetTextExtent(str3).cx; if (!nW || !nW1 && !nW2 && !nW3) return 0; nW1 = max(nW1, 1); nW2 = max(nW2, 1); nW3 = max(nW3, 1); int nYmin = INT_MAX; int nYminMetric = INT_MAX; int nXforYmin[4] = {0, 1, 1, 1}; int nX[4] = {0, 0, 0, 0}; int nX_step = 15; //nW/50; int nX_start = nW/9; int nX_stop = nW/2 - nW/9; for (nX[1] = nX_start; nX[1] <= nX_stop; nX[1] += nX_step) { int nY[4]; //************************ nY[1] = fnYi(nX[1], nW1); int nX2_stop = nW - nX[1] - nW/9; for (nX[2] = nX_start; nX[2] <= nX2_stop; nX[2] += nX_step) { nX[3] = nW - nX[1] - nX[2]; //************************ nY[2] = fnYi(nX[2], nW2); if (nY[2] > nYmin) continue; nY[3] = fnYi(nX[3], nW3); if (nY[3] > nYmin) break; int nY123 = max( max(nY[1], nY[2]), max(nY[1], nY[3]) ); int nM = nW / 3; int nY123Metric = abs(nM - nX[1]) + abs(nM - nX[2]) + abs(nM - nX[3]); if (nY123 < nYmin || nY123 == nYmin && nY123Metric < nYminMetric) { //TRACE(_T("-- =*= %d <= %d, metrics(cur: %d, min: %d) \n"), nY123, nYmin, nY123Metric, nYminMetric); //TRACE(_T("-- prev (%d, %d, %d) \n"), nXforYmin[1], nXforYmin[2], nXforYmin[3]); //TRACE(_T("-- new (%d, %d, %d) \n"), nX[1], nX[2], nX[3]); nYmin = nY123; nYminMetric = nY123Metric; nXforYmin[1] = nX[1]; nXforYmin[2] = nX[2]; nXforYmin[3] = nX[3]; } } } ASSERT(nXforYmin[1] + nXforYmin[2] + nXforYmin[3] <= nW); UINT uFlags = DT_TOP | DT_WORDBREAK | DT_CALCRECT; CRect rcText1(0, 0, nXforYmin[1], 32000); rsz1.cx = nXforYmin[1]; rsz1.cy = pDC->DrawText(str1, &rcText1, uFlags | DT_LEFT); CRect rcText2(0, 0, nXforYmin[2], 32000); rsz2.cx = nXforYmin[2]; rsz2.cy = pDC->DrawText(str2, &rcText2, uFlags | DT_CENTER); CRect rcText3(0, 0, nXforYmin[3], 32000); rsz3.cx = nXforYmin[3]; rsz3.cy = pDC->DrawText(str3, &rcText3, uFlags | DT_RIGHT); return max( max(rsz1.cy, rsz2.cy), max(rsz1.cy, rsz3.cy) ); } void CXTPPrintPageHeaderFooter::Draw(CDC* pDC, CRect& rcRect, BOOL bCalculateOnly) { CFont fntHF; VERIFY(fntHF.CreateFontIndirect(&m_lfFont)); CXTPFontDC autoFont(pDC, &fntHF, m_clrColor); int nWidth = rcRect.Width(); CSize szLeft2, szCenter2, szRight2; int nHeight = Calc3ColSizes(pDC, nWidth, m_strLeft, m_strCenter, m_strRight, szLeft2, szCenter2, szRight2); int nBorderH = nHeight ? 3 : 0; if (m_bHeader) { rcRect.bottom = rcRect.top + nHeight + nBorderH; } else { rcRect.top = rcRect.bottom - nHeight - nBorderH; } if (bCalculateOnly) { return; } int nBkModePrev = pDC->SetBkMode(TRANSPARENT); UINT uFlags = DT_TOP | DT_WORDBREAK | DT_NOPREFIX; CRect rcLeft = rcRect; rcLeft.right = rcLeft.left + szLeft2.cx; pDC->DrawText(m_strLeft, &rcLeft, uFlags | DT_LEFT); CRect rcCenter = rcRect; rcCenter.left = rcLeft.right; rcCenter.right = rcCenter.left + szCenter2.cx; pDC->DrawText(m_strCenter, &rcCenter, uFlags | DT_CENTER); CRect rcRight = rcRect; rcRight.left = rcRight.right - szRight2.cx; pDC->DrawText(m_strRight, &rcRight, uFlags | DT_RIGHT); pDC->SetBkMode(nBkModePrev); } ////////////////////////////////////////////////////////////////////////// // CXTPDpi ////////////////////////////////////////////////////////////////////////// int CXTPDpi::m_iDefaultDpi = 96; // static CXTPDpi* XTPDpiHelper() { static CXTPDpi s_instance; // singleton return &s_instance; } ////////////////////////////////////////////////////////////////////////// //************************************************************* IMPLEMENT_DYNAMIC(CXTPPrintOptions, CCmdTarget) LCID CXTPPrintOptions::GetActiveLCID() { return LOCALE_USER_DEFAULT; } BOOL CXTPPrintOptions::IsMarginsMeasureInches() { TCHAR szResult[5]; int nResult = ::GetLocaleInfo(GetActiveLCID(), LOCALE_IMEASURE, szResult, 4); ASSERT(nResult == 2); long nIsInches = _ttoi(szResult); return nIsInches != 0; } CXTPPrintOptions::CXTPPrintOptions() { BOOL bIsInches = IsMarginsMeasureInches(); int nMargin = bIsInches ? (1000 * 1/2 ) : (10 * 100); m_rcMargins.SetRect(nMargin, nMargin, nMargin, nMargin); m_pPageHeader = new CXTPPrintPageHeaderFooter(this, TRUE); m_pPageFooter = new CXTPPrintPageHeaderFooter(this, FALSE); m_bBlackWhitePrinting = FALSE; m_nBlackWhiteContrast = 0; //#ifdef _XTP_ACTIVEX // EnableAutomation(); // EnableTypeLib(); //#endif } CXTPPrintOptions::~CXTPPrintOptions() { CMDTARGET_RELEASE(m_pPageHeader); CMDTARGET_RELEASE(m_pPageFooter); } void CXTPPrintOptions::Set(const CXTPPrintOptions* pSrc) { ASSERT(pSrc); if (!pSrc) return; m_rcMargins = pSrc->m_rcMargins; if (m_pPageHeader) m_pPageHeader->Set(pSrc->m_pPageHeader); if (m_pPageFooter) m_pPageFooter->Set(pSrc->m_pPageFooter); m_bBlackWhitePrinting = pSrc->m_bBlackWhitePrinting; m_nBlackWhiteContrast = pSrc->m_nBlackWhiteContrast; } CRect CXTPPrintOptions::GetMarginsHimetric() { BOOL bIsInches = IsMarginsMeasureInches(); if (!bIsInches) { return m_rcMargins; } int nMul_i2m = 254; int nDiv_i2m = 100; CRect rcMarginsHimetric; rcMarginsHimetric.left = m_rcMargins.left * nMul_i2m / nDiv_i2m; rcMarginsHimetric.top = m_rcMargins.top * nMul_i2m / nDiv_i2m; rcMarginsHimetric.right = m_rcMargins.right * nMul_i2m / nDiv_i2m; rcMarginsHimetric.bottom = m_rcMargins.bottom * nMul_i2m / nDiv_i2m; return rcMarginsHimetric; } CRect CXTPPrintOptions::GetMarginsLP(CDC* pDC) { ASSERT(pDC); if (!pDC) return CRect(0, 0, 0, 0); CRect rcMarginsHI = GetMarginsHimetric(); CSize szLT(rcMarginsHI.left, rcMarginsHI.top); CSize szRB(rcMarginsHI.right, rcMarginsHI.bottom); pDC->HIMETRICtoLP(&szLT); pDC->HIMETRICtoLP(&szRB); CRect rcLP(szLT.cx, szLT.cy, szRB.cx, szRB.cy); return rcLP; } CXTPPrintPageHeaderFooter* CXTPPrintOptions::GetPageHeader() { return m_pPageHeader; } CXTPPrintPageHeaderFooter* CXTPPrintOptions::GetPageFooter() { return m_pPageFooter; } ///////////////////////////////////////////////////////////////////////////// // Printing Dialog class XTP_PRINT_STATE : public CNoTrackObject { public: // printing abort BOOL m_bUserAbort; }; PROCESS_LOCAL(XTP_PRINT_STATE, g_xtpPrintState) BOOL CALLBACK _XTPAbortProc(HDC, int) { XTP_PRINT_STATE* pState = g_xtpPrintState; MSG msg; while (!pState->m_bUserAbort && ::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) { if (!XTPGetThread()->PumpMessage()) return FALSE; // terminate if WM_QUIT received } return !pState->m_bUserAbort; } CXTPPrintingDialog::CXTPPrintingDialog(CWnd* pParent) { Create(CXTPPrintingDialog::IDD, pParent); // modeless ! g_xtpPrintState->m_bUserAbort = FALSE; } BOOL CXTPPrintingDialog::OnInitDialog() { //SetWindowText(AfxGetAppName()); CenterWindow(); return CDialog::OnInitDialog(); } void CXTPPrintingDialog::OnCancel() { g_xtpPrintState->m_bUserAbort = TRUE; // flag that user aborted print CDialog::OnCancel(); } void CXTPPrintPageHeaderFooter::DoInsertHFFormatSpecifierViaMenu( CWnd* pParent, CEdit* pEdit, CButton* pButton) { CMap menuData; menuData[XTP_ID_HF_FORMAT_D1] = _T("&d"); menuData[XTP_ID_HF_FORMAT_D2] = _T("&D"); menuData[XTP_ID_HF_FORMAT_T1] = _T("&t"); menuData[XTP_ID_HF_FORMAT_T2] = _T("&T"); menuData[XTP_ID_HF_FORMAT_P1] = _T("&p"); menuData[XTP_ID_HF_FORMAT_P2] = _T("&P"); menuData[XTP_ID_HF_FORMAT_B] = _T("&b"); menuData[XTP_ID_HF_FORMAT_W] = _T("&w"); menuData[XTP_ID_HF_FORMAT_UMP] = _T("&&"); menuData[XTP_ID_HF_FORMAT_N] = _T("\\n"); if (!pParent || !pEdit || !pButton) { ASSERT(FALSE); return; } CRect rcButton; pButton->GetWindowRect(&rcButton); CPoint ptMenu(rcButton.left, rcButton.bottom + 1); CMenu menu; CXTPResourceManager::AssertValid(XTPResourceManager()->LoadMenu(&menu, XTP_IDR_MENU_HEADERFOOTER_FORMATS)); // track menu int nMenuResult = menu.GetSubMenu(0)->TrackPopupMenu( TPM_RETURNCMD | TPM_LEFTALIGN |TPM_RIGHTBUTTON, ptMenu.x, ptMenu.y, pParent, NULL); pEdit->SetFocus(); CString strItem = menuData[nMenuResult]; if (!strItem.IsEmpty()) { pEdit->ReplaceSel(strItem, TRUE); } } //////////////////////////////////////////////////////////////////////////