📄 skinbase.cpp
字号:
// SkinBase.cpp: implementation of the CSkinBase class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SkinBase.h"
#include "wclassdefines.h"
#include "winclasses.h"
//#define ACTIVATE_VIEWER
//#include "imageviewer.h"
#include <afxpriv.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// for transparency
typedef BOOL (WINAPI *LPSetLayeredWindowAttributes)
(
HWND hwnd, // handle to the layered window
COLORREF crKey, // specifies the color key
BYTE bAlpha, // value for the blend function
DWORD dwFlags // action
);
#ifndef SPI_SETMENUFADE
#define SPI_GETMENUFADE 0x1012
#define SPI_SETMENUFADE 0x1013
#endif
#ifndef WS_EX_LAYERED
#define WS_EX_LAYERED 0x00080000
// win 2000 layered windows support
#define LWA_COLORKEY 0x00000001
#define LWA_ALPHA 0x00000002
#define ULW_COLORKEY 0x00000001
#define ULW_ALPHA 0x00000002
#define ULW_OPAQUE 0x00000004
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
int CSkinBase::s_nOSVer = -1;
PFNTRANSPARENTBLT CSkinBase::s_pfnFastTransparentBlt = NULL;
PFNGRADIENTFILL CSkinBase::s_pfnFastGradientFill = NULL;
BOOL CSkinBase::s_bThemingEnabled = (GetOS() >= SBOS_XP);
// don't use fast trasparent blt on win95/98 because msimg32.dll has a resource leak
BOOL CSkinBase::s_bSupportsFastTransparentBlt = (GetOS() < SBOS_ME) ? FALSE : -1;
BOOL CSkinBase::s_bSupportsFastGradientFill = (GetOS() < SBOS_ME) ? FALSE : -1;
CSkinBase::CSkinBase()
{
}
CSkinBase::~CSkinBase()
{
}
int CSkinBase::GetOS()
{
if (s_nOSVer == -1) // first time
{
OSVERSIONINFO vinfo;
vinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
BOOL rslt = GetVersionEx(&vinfo);
if (rslt)
{
switch (vinfo.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT:
switch (vinfo.dwMajorVersion)
{
case 3: // nt351
ASSERT (0); // not supported
break;
case 4: // nt4
s_nOSVer = SBOS_NT4;
break;
case 5: // >= w2k
switch (vinfo.dwMinorVersion)
{
case 0: // w2k
s_nOSVer = SBOS_2K;
break;
case 1: // xp
s_nOSVer = SBOS_XP;
break;
default: // > xp
s_nOSVer = SBOS_XPP;
break;
}
break;
default: // > xp
s_nOSVer = SBOS_XPP;
break;
}
break;
case VER_PLATFORM_WIN32_WINDOWS:
ASSERT (vinfo.dwMajorVersion == 4);
switch (vinfo.dwMinorVersion)
{
case 0: // nt4
s_nOSVer = SBOS_95;
break;
case 10: // xp
s_nOSVer = SBOS_98;
break;
case 90: // > xp
s_nOSVer = SBOS_ME;
break;
default:
ASSERT (0);
break;
}
break;
default:
ASSERT (0);
break;
}
}
}
return s_nOSVer;
}
BOOL CSkinBase::SupportsFastTransparentBlt()
{
if (s_bSupportsFastTransparentBlt == -1) // first time
{
HINSTANCE hInst = LoadLibrary("msimg32.dll");
if (hInst)
{
s_pfnFastTransparentBlt = (PFNTRANSPARENTBLT)GetProcAddress(hInst, "TransparentBlt");
s_bSupportsFastTransparentBlt = (s_pfnFastTransparentBlt != NULL);
}
else
s_bSupportsFastTransparentBlt = FALSE;
}
return s_bSupportsFastTransparentBlt;
}
BOOL CSkinBase::SupportsFastGradientFill()
{
if (s_bSupportsFastGradientFill == -1) // first time
{
HINSTANCE hInst = LoadLibrary("msimg32.dll");
if (hInst)
{
s_pfnFastGradientFill = (PFNGRADIENTFILL)GetProcAddress(hInst, "GradientFill");
s_bSupportsFastGradientFill = (s_pfnFastGradientFill != NULL);
}
else
s_bSupportsFastGradientFill = FALSE;
}
return s_bSupportsFastGradientFill;
}
BOOL CSkinBase::GradientFill(CDC* pDCDest, LPRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz)
{
if (!lpRect)
return FALSE;
if (::IsRectEmpty(lpRect))
return FALSE;
if (crFrom == crTo)
{
pDCDest->FillSolidRect(lpRect, crFrom);
return TRUE;
}
if (GradientFillFast(pDCDest, lpRect, crFrom, crTo, bHorz))
return TRUE;
// else
return GradientFillSlow(pDCDest, lpRect, crFrom, crTo, bHorz);
}
BOOL CSkinBase::TransparentBlt(CDC* pDCDest,
int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
CDC* pDCSrc,
int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
UINT crTransparent)
{
if (nWidthDest < 1)
return FALSE;
if (nWidthSrc < 1)
return FALSE;
if (nHeightDest < 1)
return FALSE;
if (nHeightSrc < 1)
return FALSE;
if (TransparentBltFast(pDCDest,
nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
pDCSrc,
nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
crTransparent))
return TRUE;
// else
return TransparentBltSlow(pDCDest,
nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
pDCSrc,
nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
crTransparent);
}
BOOL CSkinBase::TransparentBltFast(CDC* pDCDest,
int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
CDC* pDCSrc,
int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
UINT crTransparent)
{
if (!SupportsFastTransparentBlt() || !s_pfnFastTransparentBlt)
return FALSE;
return s_pfnFastTransparentBlt(*pDCDest,
nXOriginDest,
nYOriginDest,
nWidthDest,
nHeightDest,
*pDCSrc,
nXOriginSrc,
nYOriginSrc,
nWidthSrc,
nHeightSrc,
crTransparent);
}
BOOL CSkinBase::TransparentBltSlow(CDC* pDCDest,
int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
CDC* pDCSrc,
int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
UINT crTransparent)
{
CDC dcMem, dcMask;
dcMask.CreateCompatibleDC(pDCDest);
dcMem.CreateCompatibleDC(pDCDest);
CBitmap bmMask, bmMem;
// copy src bitmap to mem dc
bmMem.CreateCompatibleBitmap(pDCDest, nWidthSrc, nHeightSrc);
CBitmap* pOldBMMem = dcMem.SelectObject(&bmMem);
dcMem.BitBlt(0, 0, nWidthSrc, nHeightSrc, pDCSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
// ShowDC(dcMem);
// Create monochrome bitmap for the mask
bmMask.CreateBitmap(nWidthSrc, nHeightSrc, 1, 1, NULL);
CBitmap* pOldBMMask = dcMask.SelectObject(&bmMask);
dcMem.SetBkColor(crTransparent);
// Create the mask from the memory DC
dcMask.BitBlt(0, 0, nWidthSrc, nHeightSrc, &dcMem, 0, 0, SRCCOPY);
// ShowDC(dcMask);
// Set the background in dcMem to black. Using SRCPAINT with black
// and any other color results in the other color, thus making
// black the transparent color
dcMem.SetBkColor(RGB(0,0,0));
dcMem.SetTextColor(RGB(255,255,255));
dcMem.BitBlt(0, 0, nWidthSrc, nHeightSrc, &dcMask, 0, 0, SRCAND);
// ShowDC(dcMem);
// Set the foreground to black. See comment above.
// pDCDest->SetStretchBltMode(COLORONCOLOR);
pDCDest->SetStretchBltMode(HALFTONE);
pDCDest->SetBkColor(RGB(255,255,255));
pDCDest->SetTextColor(RGB(0,0,0));
// CPoint ptOrg;
// ::GetBrushOrgEx(*pDCDest, &ptOrg);
// ::SetBrushOrgEx(*pDCDest, 0, 0, &ptOrg);
if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
{
pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
// ShowDC(*pDCDest);
}
else
{
pDCDest->StretchBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
&dcMask, 0, 0, nWidthSrc, nHeightSrc, SRCAND);
// ShowDC(*pDCDest);
}
// Combine the foreground with the background
if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
{
pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMem, 0, 0, SRCPAINT);
// ShowDC(*pDCDest);
}
else
{
pDCDest->StretchBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
&dcMem, 0, 0, nWidthSrc, nHeightSrc, SRCPAINT);
// ShowDC(*pDCDest);
}
dcMask.SelectObject(pOldBMMask);
dcMem.SelectObject(pOldBMMem);
return TRUE;
}
/*
BOOL CSkinBase::TransparentBltSlow(CDC* pDCDest,
int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
CDC* pDCSrc,
int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
UINT crTransparent)
{
CDC dcMem, dcMask;
dcMask.CreateCompatibleDC(pDCDest);
dcMem.CreateCompatibleDC(pDCDest);
CBitmap bmMask, bmMem;
// copy src bitmap to mem dc
bmMem.CreateCompatibleBitmap(pDCDest, nWidthDest, nHeightDest);
CBitmap* pOldBMMem = dcMem.SelectObject(&bmMem);
dcMem.SetStretchBltMode(HALFTONE);
CPoint ptOrg;
::GetBrushOrgEx(dcMem, &ptOrg);
::SetBrushOrgEx(dcMem, 0, 0, &ptOrg);
dcMem.StretchBlt(0, 0, nWidthDest, nHeightDest,
pDCSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
// ShowDC(dcMem);
// Create monochrome bitmap for the mask
bmMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);
CBitmap* pOldBMMask = dcMask.SelectObject(&bmMask);
dcMem.SetBkColor(crTransparent);
// Create the mask from the memory DC
dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMem, 0, 0, SRCCOPY);
// ShowDC(dcMask);
// Set the background in dcMem to black. Using SRCPAINT with black
// and any other color results in the other color, thus making
// black the transparent color
dcMem.SetBkColor(RGB(0,0,0));
dcMem.SetTextColor(RGB(255,255,255));
dcMem.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
// ShowDC(dcMem);
// Set the foreground to black. See comment above.
pDCDest->SetBkColor(RGB(255,255,255));
pDCDest->SetTextColor(RGB(0,0,0));
pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
// ShowDC(*pDCDest);
// Combine the foreground with the background
pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMem, 0, 0, SRCPAINT);
// ShowDC(*pDCDest);
dcMask.SelectObject(pOldBMMask);
dcMem.SelectObject(pOldBMMem);
return TRUE;
}
*/
BOOL CSkinBase::GradientFillFast(CDC* pDCDest, LPRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz)
{
if (!SupportsFastGradientFill() || !s_pfnFastGradientFill)
return FALSE;
TRIVERTEX vert[2];
vert[0].x = lpRect->left;
vert[0].y = lpRect->top;
vert[0].Red = GetRValue(crFrom) << 8;
vert[0].Green = GetGValue(crFrom) << 8;
vert[0].Blue = GetBValue(crFrom) << 8;
vert[0].Alpha = 0x0000;
vert[1].x = lpRect->right;
vert[1].y = lpRect->bottom;
vert[1].Red = GetRValue(crTo) << 8;
vert[1].Green = GetGValue(crTo) << 8;
vert[1].Blue = GetBValue(crTo) << 8;
vert[1].Alpha = 0x0000;
GRADIENT_RECT gRect = { 0, 1 };
return s_pfnFastGradientFill(*pDCDest,
vert,
2,
&gRect,
1,
bHorz ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);
}
BOOL CSkinBase::GradientFillSlow(CDC* pDCDest, LPRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz)
{
if (!pDCDest || !lpRect)
return FALSE;
int nWidth = lpRect->right - lpRect->left;
int nHeight = lpRect->bottom - lpRect->top;
if (bHorz)
{
for (int nX = lpRect->left; nX < lpRect->right; nX++)
pDCDest->FillSolidRect(nX, lpRect->top, 1, nHeight, BlendColors(crFrom, crTo, (lpRect->right - nX) / (float)nWidth));
}
else
{
for (int nY = lpRect->top; nY < lpRect->bottom; nY++)
pDCDest->FillSolidRect(lpRect->left, nY, nWidth, 1, BlendColors(crFrom, crTo, (lpRect->bottom - nY) / (float)nHeight));
}
return TRUE;
}
COLORREF CSkinBase::BlendColors(COLORREF crA, COLORREF crB, float fAmountA)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -