You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2193 lines
51 KiB
C++

2 years ago
// 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<UINT, UINT, CString, CString&> 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);
}
}
//////////////////////////////////////////////////////////////////////////