mirror of
https://github.com/balloonwj/TeamTalk.git
synced 2026-10-19 14:51:57 +08:00
2062 lines
90 KiB
C++
2062 lines
90 KiB
C++
#include "StdAfx.h"
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////
|
||
DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that has been opened
|
||
typedef DWORD ZRESULT;
|
||
typedef struct
|
||
{
|
||
int index; // index of this file within the zip
|
||
char name[MAX_PATH]; // filename within the zip
|
||
DWORD attr; // attributes, as in GetFileAttributes.
|
||
FILETIME atime,ctime,mtime;// access, create, modify filetimes
|
||
long comp_size; // sizes of item, compressed and uncompressed. These
|
||
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
|
||
} ZIPENTRY;
|
||
typedef struct
|
||
{
|
||
int index; // index of this file within the zip
|
||
TCHAR name[MAX_PATH]; // filename within the zip
|
||
DWORD attr; // attributes, as in GetFileAttributes.
|
||
FILETIME atime,ctime,mtime;// access, create, modify filetimes
|
||
long comp_size; // sizes of item, compressed and uncompressed. These
|
||
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
|
||
} ZIPENTRYW;
|
||
#define OpenZip OpenZipU
|
||
#define CloseZip(hz) CloseZipU(hz)
|
||
extern HZIP OpenZipU(void *z,unsigned int len,DWORD flags);
|
||
extern ZRESULT CloseZipU(HZIP hz);
|
||
#ifdef _UNICODE
|
||
#define ZIPENTRY ZIPENTRYW
|
||
#define GetZipItem GetZipItemW
|
||
#define FindZipItem FindZipItemW
|
||
#else
|
||
#define GetZipItem GetZipItemA
|
||
#define FindZipItem FindZipItemA
|
||
#endif
|
||
extern ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze);
|
||
extern ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze);
|
||
extern ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);
|
||
extern ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze);
|
||
extern ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags);
|
||
///////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
extern "C"
|
||
{
|
||
extern unsigned char *stbi_load_from_memory(unsigned char const *buffer, int len, int *x, int *y, \
|
||
int *comp, int req_comp);
|
||
extern void stbi_image_free(void *retval_from_stbi_load);
|
||
|
||
};
|
||
|
||
namespace DuiLib {
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
//
|
||
|
||
CRenderClip::~CRenderClip()
|
||
{
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
ASSERT(::GetObjectType(hRgn)==OBJ_REGION);
|
||
ASSERT(::GetObjectType(hOldRgn)==OBJ_REGION);
|
||
::SelectClipRgn(hDC, hOldRgn);
|
||
::DeleteObject(hOldRgn);
|
||
::DeleteObject(hRgn);
|
||
}
|
||
|
||
void CRenderClip::GenerateClip(HDC hDC, RECT rc, CRenderClip& clip)
|
||
{
|
||
RECT rcClip = { 0 };
|
||
::GetClipBox(hDC, &rcClip);
|
||
clip.hOldRgn = ::CreateRectRgnIndirect(&rcClip);
|
||
clip.hRgn = ::CreateRectRgnIndirect(&rc);
|
||
::ExtSelectClipRgn(hDC, clip.hRgn, RGN_AND);
|
||
clip.hDC = hDC;
|
||
clip.rcItem = rc;
|
||
}
|
||
|
||
void CRenderClip::GenerateRoundClip(HDC hDC, RECT rc, RECT rcItem, int width, int height, CRenderClip& clip)
|
||
{
|
||
RECT rcClip = { 0 };
|
||
::GetClipBox(hDC, &rcClip);
|
||
clip.hOldRgn = ::CreateRectRgnIndirect(&rcClip);
|
||
clip.hRgn = ::CreateRectRgnIndirect(&rc);
|
||
HRGN hRgnItem = ::CreateRoundRectRgn(rcItem.left, rcItem.top, rcItem.right + 1, rcItem.bottom + 1, width, height);
|
||
::CombineRgn(clip.hRgn, clip.hRgn, hRgnItem, RGN_AND);
|
||
::ExtSelectClipRgn(hDC, clip.hRgn, RGN_AND);
|
||
clip.hDC = hDC;
|
||
clip.rcItem = rc;
|
||
::DeleteObject(hRgnItem);
|
||
}
|
||
|
||
void CRenderClip::UseOldClipBegin(HDC hDC, CRenderClip& clip)
|
||
{
|
||
::SelectClipRgn(hDC, clip.hOldRgn);
|
||
}
|
||
|
||
void CRenderClip::UseOldClipEnd(HDC hDC, CRenderClip& clip)
|
||
{
|
||
::SelectClipRgn(hDC, clip.hRgn);
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
//
|
||
|
||
static const float OneThird = 1.0f / 3;
|
||
|
||
static void RGBtoHSL(DWORD ARGB, float* H, float* S, float* L) {
|
||
const float
|
||
R = (float)GetRValue(ARGB),
|
||
G = (float)GetGValue(ARGB),
|
||
B = (float)GetBValue(ARGB),
|
||
nR = (R<0?0:(R>255?255:R))/255,
|
||
nG = (G<0?0:(G>255?255:G))/255,
|
||
nB = (B<0?0:(B>255?255:B))/255,
|
||
m = min(min(nR,nG),nB),
|
||
M = max(max(nR,nG),nB);
|
||
*L = (m + M)/2;
|
||
if (M==m) *H = *S = 0;
|
||
else {
|
||
const float
|
||
f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
|
||
i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
|
||
*H = (i-f/(M-m));
|
||
if (*H>=6) *H-=6;
|
||
*H*=60;
|
||
*S = (2*(*L)<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
|
||
}
|
||
}
|
||
|
||
static void HSLtoRGB(DWORD* ARGB, float H, float S, float L) {
|
||
const float
|
||
q = 2*L<1?L*(1+S):(L+S-L*S),
|
||
p = 2*L-q,
|
||
h = H/360,
|
||
tr = h + OneThird,
|
||
tg = h,
|
||
tb = h - OneThird,
|
||
ntr = tr<0?tr+1:(tr>1?tr-1:tr),
|
||
ntg = tg<0?tg+1:(tg>1?tg-1:tg),
|
||
ntb = tb<0?tb+1:(tb>1?tb-1:tb),
|
||
R = 255*(6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f*OneThird-ntr):p))),
|
||
G = 255*(6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f*OneThird-ntg):p))),
|
||
B = 255*(6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f*OneThird-ntb):p)));
|
||
*ARGB &= 0xFF000000;
|
||
*ARGB |= RGB( (BYTE)(R<0?0:(R>255?255:R)), (BYTE)(G<0?0:(G>255?255:G)), (BYTE)(B<0?0:(B>255?255:B)) );
|
||
}
|
||
|
||
static COLORREF PixelAlpha(COLORREF clrSrc, double src_darken, COLORREF clrDest, double dest_darken)
|
||
{
|
||
return RGB (GetRValue (clrSrc) * src_darken + GetRValue (clrDest) * dest_darken,
|
||
GetGValue (clrSrc) * src_darken + GetGValue (clrDest) * dest_darken,
|
||
GetBValue (clrSrc) * src_darken + GetBValue (clrDest) * dest_darken);
|
||
|
||
}
|
||
|
||
static BOOL WINAPI AlphaBitBlt(HDC hDC, int nDestX, int nDestY, int dwWidth, int dwHeight, HDC hSrcDC, \
|
||
int nSrcX, int nSrcY, int wSrc, int hSrc, BLENDFUNCTION ftn)
|
||
{
|
||
HDC hTempDC = ::CreateCompatibleDC(hDC);
|
||
if (NULL == hTempDC)
|
||
return FALSE;
|
||
|
||
//Creates Source DIB
|
||
LPBITMAPINFO lpbiSrc = NULL;
|
||
// Fill in the BITMAPINFOHEADER
|
||
lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
|
||
if (lpbiSrc == NULL)
|
||
{
|
||
::DeleteDC(hTempDC);
|
||
return FALSE;
|
||
}
|
||
lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
lpbiSrc->bmiHeader.biWidth = dwWidth;
|
||
lpbiSrc->bmiHeader.biHeight = dwHeight;
|
||
lpbiSrc->bmiHeader.biPlanes = 1;
|
||
lpbiSrc->bmiHeader.biBitCount = 32;
|
||
lpbiSrc->bmiHeader.biCompression = BI_RGB;
|
||
lpbiSrc->bmiHeader.biSizeImage = dwWidth * dwHeight;
|
||
lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
|
||
lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
|
||
lpbiSrc->bmiHeader.biClrUsed = 0;
|
||
lpbiSrc->bmiHeader.biClrImportant = 0;
|
||
|
||
COLORREF* pSrcBits = NULL;
|
||
HBITMAP hSrcDib = CreateDIBSection (
|
||
hSrcDC, lpbiSrc, DIB_RGB_COLORS, (void **)&pSrcBits,
|
||
NULL, NULL);
|
||
|
||
if ((NULL == hSrcDib) || (NULL == pSrcBits))
|
||
{
|
||
delete [] lpbiSrc;
|
||
::DeleteDC(hTempDC);
|
||
return FALSE;
|
||
}
|
||
|
||
HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hSrcDib);
|
||
::StretchBlt(hTempDC, 0, 0, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, wSrc, hSrc, SRCCOPY);
|
||
::SelectObject (hTempDC, hOldTempBmp);
|
||
|
||
//Creates Destination DIB
|
||
LPBITMAPINFO lpbiDest = NULL;
|
||
// Fill in the BITMAPINFOHEADER
|
||
lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
|
||
if (lpbiDest == NULL)
|
||
{
|
||
delete [] lpbiSrc;
|
||
::DeleteObject(hSrcDib);
|
||
::DeleteDC(hTempDC);
|
||
return FALSE;
|
||
}
|
||
|
||
lpbiDest->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
lpbiDest->bmiHeader.biWidth = dwWidth;
|
||
lpbiDest->bmiHeader.biHeight = dwHeight;
|
||
lpbiDest->bmiHeader.biPlanes = 1;
|
||
lpbiDest->bmiHeader.biBitCount = 32;
|
||
lpbiDest->bmiHeader.biCompression = BI_RGB;
|
||
lpbiDest->bmiHeader.biSizeImage = dwWidth * dwHeight;
|
||
lpbiDest->bmiHeader.biXPelsPerMeter = 0;
|
||
lpbiDest->bmiHeader.biYPelsPerMeter = 0;
|
||
lpbiDest->bmiHeader.biClrUsed = 0;
|
||
lpbiDest->bmiHeader.biClrImportant = 0;
|
||
|
||
COLORREF* pDestBits = NULL;
|
||
HBITMAP hDestDib = CreateDIBSection (
|
||
hDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
|
||
NULL, NULL);
|
||
|
||
if ((NULL == hDestDib) || (NULL == pDestBits))
|
||
{
|
||
delete [] lpbiSrc;
|
||
::DeleteObject(hSrcDib);
|
||
::DeleteDC(hTempDC);
|
||
return FALSE;
|
||
}
|
||
|
||
::SelectObject (hTempDC, hDestDib);
|
||
::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDC, nDestX, nDestY, SRCCOPY);
|
||
::SelectObject (hTempDC, hOldTempBmp);
|
||
|
||
double src_darken;
|
||
BYTE nAlpha;
|
||
|
||
for (int pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
|
||
{
|
||
nAlpha = LOBYTE(*pSrcBits >> 24);
|
||
src_darken = (double) (nAlpha * ftn.SourceConstantAlpha) / 255.0 / 255.0;
|
||
if( src_darken < 0.0 ) src_darken = 0.0;
|
||
*pDestBits = PixelAlpha(*pSrcBits, src_darken, *pDestBits, 1.0 - src_darken);
|
||
} //for
|
||
|
||
::SelectObject (hTempDC, hDestDib);
|
||
::BitBlt (hDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
|
||
::SelectObject (hTempDC, hOldTempBmp);
|
||
|
||
delete [] lpbiDest;
|
||
::DeleteObject(hDestDib);
|
||
|
||
delete [] lpbiSrc;
|
||
::DeleteObject(hSrcDib);
|
||
|
||
::DeleteDC(hTempDC);
|
||
return TRUE;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
//
|
||
|
||
DWORD CRenderEngine::AdjustColor(DWORD dwColor, short H, short S, short L)
|
||
{
|
||
if( H == 180 && S == 100 && L == 100 ) return dwColor;
|
||
float fH, fS, fL;
|
||
float S1 = S / 100.0f;
|
||
float L1 = L / 100.0f;
|
||
RGBtoHSL(dwColor, &fH, &fS, &fL);
|
||
fH += (H - 180);
|
||
fH = fH > 0 ? fH : fH + 360;
|
||
fS *= S1;
|
||
fL *= L1;
|
||
HSLtoRGB(&dwColor, fH, fS, fL);
|
||
return dwColor;
|
||
}
|
||
|
||
TImageInfo* CRenderEngine::LoadImage(STRINGorID bitmap, LPCTSTR type, DWORD mask)
|
||
{
|
||
LPBYTE pData = NULL;
|
||
DWORD dwSize = 0;
|
||
|
||
do
|
||
{
|
||
if( type == NULL ) {
|
||
CDuiString sFile = CPaintManagerUI::GetResourcePath();
|
||
if( CPaintManagerUI::GetResourceZip().IsEmpty() ) {
|
||
sFile += bitmap.m_lpstr;
|
||
HANDLE hFile = ::CreateFile(sFile.GetData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
|
||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||
if( hFile == INVALID_HANDLE_VALUE ) break;
|
||
dwSize = ::GetFileSize(hFile, NULL);
|
||
if( dwSize == 0 ) break;
|
||
|
||
DWORD dwRead = 0;
|
||
pData = new BYTE[ dwSize ];
|
||
::ReadFile( hFile, pData, dwSize, &dwRead, NULL );
|
||
::CloseHandle( hFile );
|
||
|
||
if( dwRead != dwSize ) {
|
||
delete[] pData;
|
||
pData = NULL;
|
||
break;
|
||
}
|
||
}
|
||
else {
|
||
sFile += CPaintManagerUI::GetResourceZip();
|
||
HZIP hz = NULL;
|
||
if( CPaintManagerUI::IsCachedResourceZip() ) hz = (HZIP)CPaintManagerUI::GetResourceZipHandle();
|
||
else hz = OpenZip((void*)sFile.GetData(), 0, 2);
|
||
if( hz == NULL ) break;
|
||
ZIPENTRY ze;
|
||
int i;
|
||
if( FindZipItem(hz, bitmap.m_lpstr, true, &i, &ze) != 0 ) break;
|
||
dwSize = ze.unc_size;
|
||
if( dwSize == 0 ) break;
|
||
pData = new BYTE[ dwSize ];
|
||
int res = UnzipItem(hz, i, pData, dwSize, 3);
|
||
if( res != 0x00000000 && res != 0x00000600) {
|
||
delete[] pData;
|
||
pData = NULL;
|
||
if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz);
|
||
break;
|
||
}
|
||
if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz);
|
||
}
|
||
}
|
||
else {
|
||
HRSRC hResource = ::FindResource(CPaintManagerUI::GetResourceDll(), bitmap.m_lpstr, type);
|
||
if( hResource == NULL ) break;
|
||
HGLOBAL hGlobal = ::LoadResource(CPaintManagerUI::GetResourceDll(), hResource);
|
||
if( hGlobal == NULL ) {
|
||
FreeResource(hResource);
|
||
break;
|
||
}
|
||
|
||
dwSize = ::SizeofResource(CPaintManagerUI::GetResourceDll(), hResource);
|
||
if( dwSize == 0 ) break;
|
||
pData = new BYTE[ dwSize ];
|
||
::CopyMemory(pData, (LPBYTE)::LockResource(hGlobal), dwSize);
|
||
::FreeResource(hResource);
|
||
}
|
||
} while (0);
|
||
|
||
while (!pData)
|
||
{
|
||
//读不到图片, 则直接去读取bitmap.m_lpstr指向的路径
|
||
HANDLE hFile = ::CreateFile(bitmap.m_lpstr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
|
||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||
if( hFile == INVALID_HANDLE_VALUE ) break;
|
||
dwSize = ::GetFileSize(hFile, NULL);
|
||
if( dwSize == 0 ) break;
|
||
|
||
DWORD dwRead = 0;
|
||
pData = new BYTE[ dwSize ];
|
||
::ReadFile( hFile, pData, dwSize, &dwRead, NULL );
|
||
::CloseHandle( hFile );
|
||
|
||
if( dwRead != dwSize ) {
|
||
delete[] pData;
|
||
pData = NULL;
|
||
}
|
||
break;
|
||
}
|
||
if (!pData)
|
||
{
|
||
//::MessageBox(0, _T("读取图片数据失败!"), _T("抓BUG"), MB_OK);
|
||
return NULL;
|
||
}
|
||
|
||
LPBYTE pImage = NULL;
|
||
int x,y,n;
|
||
pImage = stbi_load_from_memory(pData, dwSize, &x, &y, &n, 4);
|
||
delete[] pData;
|
||
if( !pImage ) {
|
||
//::MessageBox(0, _T("解析图片失败"), _T("抓BUG"), MB_OK);
|
||
return NULL;
|
||
}
|
||
|
||
BITMAPINFO bmi;
|
||
::ZeroMemory(&bmi, sizeof(BITMAPINFO));
|
||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
bmi.bmiHeader.biWidth = x;
|
||
bmi.bmiHeader.biHeight = -y;
|
||
bmi.bmiHeader.biPlanes = 1;
|
||
bmi.bmiHeader.biBitCount = 32;
|
||
bmi.bmiHeader.biCompression = BI_RGB;
|
||
bmi.bmiHeader.biSizeImage = x * y * 4;
|
||
|
||
bool bAlphaChannel = false;
|
||
LPBYTE pDest = NULL;
|
||
HBITMAP hBitmap = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDest, NULL, 0);
|
||
if( !hBitmap ) {
|
||
//::MessageBox(0, _T("CreateDIBSection失败"), _T("抓BUG"), MB_OK);
|
||
return NULL;
|
||
}
|
||
|
||
for( int i = 0; i < x * y; i++ )
|
||
{
|
||
pDest[i*4 + 3] = pImage[i*4 + 3];
|
||
if( pDest[i*4 + 3] < 255 )
|
||
{
|
||
pDest[i*4] = (BYTE)(DWORD(pImage[i*4 + 2])*pImage[i*4 + 3]/255);
|
||
pDest[i*4 + 1] = (BYTE)(DWORD(pImage[i*4 + 1])*pImage[i*4 + 3]/255);
|
||
pDest[i*4 + 2] = (BYTE)(DWORD(pImage[i*4])*pImage[i*4 + 3]/255);
|
||
bAlphaChannel = true;
|
||
}
|
||
else
|
||
{
|
||
pDest[i*4] = pImage[i*4 + 2];
|
||
pDest[i*4 + 1] = pImage[i*4 + 1];
|
||
pDest[i*4 + 2] = pImage[i*4];
|
||
}
|
||
|
||
if( *(DWORD*)(&pDest[i*4]) == mask ) {
|
||
pDest[i*4] = (BYTE)0;
|
||
pDest[i*4 + 1] = (BYTE)0;
|
||
pDest[i*4 + 2] = (BYTE)0;
|
||
pDest[i*4 + 3] = (BYTE)0;
|
||
bAlphaChannel = true;
|
||
}
|
||
}
|
||
|
||
stbi_image_free(pImage);
|
||
|
||
TImageInfo* data = new TImageInfo;
|
||
data->hBitmap = hBitmap;
|
||
data->nX = x;
|
||
data->nY = y;
|
||
data->alphaChannel = bAlphaChannel;
|
||
return data;
|
||
}
|
||
|
||
void CRenderEngine::FreeImage(const TImageInfo* bitmap)
|
||
{
|
||
if (bitmap->hBitmap) {
|
||
::DeleteObject(bitmap->hBitmap) ;
|
||
}
|
||
delete bitmap ;
|
||
}
|
||
|
||
void CRenderEngine::DrawImage(HDC hDC, HBITMAP hBitmap, const RECT& rc, const RECT& rcPaint,
|
||
const RECT& rcBmpPart, const RECT& rcCorners, bool alphaChannel,
|
||
BYTE uFade, bool hole, bool xtiled, bool ytiled)
|
||
{
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
|
||
typedef BOOL (WINAPI *LPALPHABLEND)(HDC, int, int, int, int,HDC, int, int, int, int, BLENDFUNCTION);
|
||
static LPALPHABLEND lpAlphaBlend = (LPALPHABLEND) ::GetProcAddress(::GetModuleHandle(_T("msimg32.dll")), "AlphaBlend");
|
||
|
||
if( lpAlphaBlend == NULL ) lpAlphaBlend = AlphaBitBlt;
|
||
if( hBitmap == NULL ) return;
|
||
|
||
HDC hCloneDC = ::CreateCompatibleDC(hDC);
|
||
HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hCloneDC, hBitmap);
|
||
::SetStretchBltMode(hDC, HALFTONE);
|
||
|
||
RECT rcTemp = {0};
|
||
RECT rcDest = {0};
|
||
if( lpAlphaBlend && (alphaChannel || uFade < 255) ) {
|
||
BLENDFUNCTION bf = { AC_SRC_OVER, 0, uFade, AC_SRC_ALPHA };
|
||
// middle
|
||
if( !hole ) {
|
||
rcDest.left = rc.left + rcCorners.left;
|
||
rcDest.top = rc.top + rcCorners.top;
|
||
rcDest.right = rc.right - rc.left - rcCorners.left - rcCorners.right;
|
||
rcDest.bottom = rc.bottom - rc.top - rcCorners.top - rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
if( !xtiled && !ytiled ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, \
|
||
rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right, \
|
||
rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom, bf);
|
||
}
|
||
else if( xtiled && ytiled ) {
|
||
LONG lWidth = rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right;
|
||
LONG lHeight = rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom;
|
||
int iTimesX = (rcDest.right - rcDest.left + lWidth - 1) / lWidth;
|
||
int iTimesY = (rcDest.bottom - rcDest.top + lHeight - 1) / lHeight;
|
||
for( int j = 0; j < iTimesY; ++j ) {
|
||
LONG lDestTop = rcDest.top + lHeight * j;
|
||
LONG lDestBottom = rcDest.top + lHeight * (j + 1);
|
||
LONG lDrawHeight = lHeight;
|
||
if( lDestBottom > rcDest.bottom ) {
|
||
lDrawHeight -= lDestBottom - rcDest.bottom;
|
||
lDestBottom = rcDest.bottom;
|
||
}
|
||
for( int i = 0; i < iTimesX; ++i ) {
|
||
LONG lDestLeft = rcDest.left + lWidth * i;
|
||
LONG lDestRight = rcDest.left + lWidth * (i + 1);
|
||
LONG lDrawWidth = lWidth;
|
||
if( lDestRight > rcDest.right ) {
|
||
lDrawWidth -= lDestRight - rcDest.right;
|
||
lDestRight = rcDest.right;
|
||
}
|
||
lpAlphaBlend(hDC, rcDest.left + lWidth * i, rcDest.top + lHeight * j,
|
||
lDestRight - lDestLeft, lDestBottom - lDestTop, hCloneDC,
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, lDrawWidth, lDrawHeight, bf);
|
||
}
|
||
}
|
||
}
|
||
else if( xtiled ) {
|
||
LONG lWidth = rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right;
|
||
int iTimes = (rcDest.right - rcDest.left + lWidth - 1) / lWidth;
|
||
for( int i = 0; i < iTimes; ++i ) {
|
||
LONG lDestLeft = rcDest.left + lWidth * i;
|
||
LONG lDestRight = rcDest.left + lWidth * (i + 1);
|
||
LONG lDrawWidth = lWidth;
|
||
if( lDestRight > rcDest.right ) {
|
||
lDrawWidth -= lDestRight - rcDest.right;
|
||
lDestRight = rcDest.right;
|
||
}
|
||
lpAlphaBlend(hDC, lDestLeft, rcDest.top, lDestRight - lDestLeft, rcDest.bottom,
|
||
hCloneDC, rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, \
|
||
lDrawWidth, rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom, bf);
|
||
}
|
||
}
|
||
else { // ytiled
|
||
LONG lHeight = rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom;
|
||
int iTimes = (rcDest.bottom - rcDest.top + lHeight - 1) / lHeight;
|
||
for( int i = 0; i < iTimes; ++i ) {
|
||
LONG lDestTop = rcDest.top + lHeight * i;
|
||
LONG lDestBottom = rcDest.top + lHeight * (i + 1);
|
||
LONG lDrawHeight = lHeight;
|
||
if( lDestBottom > rcDest.bottom ) {
|
||
lDrawHeight -= lDestBottom - rcDest.bottom;
|
||
lDestBottom = rcDest.bottom;
|
||
}
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top + lHeight * i, rcDest.right, lDestBottom - lDestTop,
|
||
hCloneDC, rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, \
|
||
rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right, lDrawHeight, bf);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// left-top
|
||
if( rcCorners.left > 0 && rcCorners.top > 0 ) {
|
||
rcDest.left = rc.left;
|
||
rcDest.top = rc.top;
|
||
rcDest.right = rcCorners.left;
|
||
rcDest.bottom = rcCorners.top;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left, rcBmpPart.top, rcCorners.left, rcCorners.top, bf);
|
||
}
|
||
}
|
||
// top
|
||
if( rcCorners.top > 0 ) {
|
||
rcDest.left = rc.left + rcCorners.left;
|
||
rcDest.top = rc.top;
|
||
rcDest.right = rc.right - rc.left - rcCorners.left - rcCorners.right;
|
||
rcDest.bottom = rcCorners.top;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.top, rcBmpPart.right - rcBmpPart.left - \
|
||
rcCorners.left - rcCorners.right, rcCorners.top, bf);
|
||
}
|
||
}
|
||
// right-top
|
||
if( rcCorners.right > 0 && rcCorners.top > 0 ) {
|
||
rcDest.left = rc.right - rcCorners.right;
|
||
rcDest.top = rc.top;
|
||
rcDest.right = rcCorners.right;
|
||
rcDest.bottom = rcCorners.top;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.right - rcCorners.right, rcBmpPart.top, rcCorners.right, rcCorners.top, bf);
|
||
}
|
||
}
|
||
// left
|
||
if( rcCorners.left > 0 ) {
|
||
rcDest.left = rc.left;
|
||
rcDest.top = rc.top + rcCorners.top;
|
||
rcDest.right = rcCorners.left;
|
||
rcDest.bottom = rc.bottom - rc.top - rcCorners.top - rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left, rcBmpPart.top + rcCorners.top, rcCorners.left, rcBmpPart.bottom - \
|
||
rcBmpPart.top - rcCorners.top - rcCorners.bottom, bf);
|
||
}
|
||
}
|
||
// right
|
||
if( rcCorners.right > 0 ) {
|
||
rcDest.left = rc.right - rcCorners.right;
|
||
rcDest.top = rc.top + rcCorners.top;
|
||
rcDest.right = rcCorners.right;
|
||
rcDest.bottom = rc.bottom - rc.top - rcCorners.top - rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.right - rcCorners.right, rcBmpPart.top + rcCorners.top, rcCorners.right, \
|
||
rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom, bf);
|
||
}
|
||
}
|
||
// left-bottom
|
||
if( rcCorners.left > 0 && rcCorners.bottom > 0 ) {
|
||
rcDest.left = rc.left;
|
||
rcDest.top = rc.bottom - rcCorners.bottom;
|
||
rcDest.right = rcCorners.left;
|
||
rcDest.bottom = rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left, rcBmpPart.bottom - rcCorners.bottom, rcCorners.left, rcCorners.bottom, bf);
|
||
}
|
||
}
|
||
// bottom
|
||
if( rcCorners.bottom > 0 ) {
|
||
rcDest.left = rc.left + rcCorners.left;
|
||
rcDest.top = rc.bottom - rcCorners.bottom;
|
||
rcDest.right = rc.right - rc.left - rcCorners.left - rcCorners.right;
|
||
rcDest.bottom = rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.bottom - rcCorners.bottom, \
|
||
rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right, rcCorners.bottom, bf);
|
||
}
|
||
}
|
||
// right-bottom
|
||
if( rcCorners.right > 0 && rcCorners.bottom > 0 ) {
|
||
rcDest.left = rc.right - rcCorners.right;
|
||
rcDest.top = rc.bottom - rcCorners.bottom;
|
||
rcDest.right = rcCorners.right;
|
||
rcDest.bottom = rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
lpAlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.right - rcCorners.right, rcBmpPart.bottom - rcCorners.bottom, rcCorners.right, \
|
||
rcCorners.bottom, bf);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (rc.right - rc.left == rcBmpPart.right - rcBmpPart.left \
|
||
&& rc.bottom - rc.top == rcBmpPart.bottom - rcBmpPart.top \
|
||
&& rcCorners.left == 0 && rcCorners.right == 0 && rcCorners.top == 0 && rcCorners.bottom == 0)
|
||
{
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rc) ) {
|
||
::BitBlt(hDC, rcTemp.left, rcTemp.top, rcTemp.right - rcTemp.left, rcTemp.bottom - rcTemp.top, \
|
||
hCloneDC, rcBmpPart.left + rcTemp.left - rc.left, rcBmpPart.top + rcTemp.top - rc.top, SRCCOPY);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// middle
|
||
if( !hole ) {
|
||
rcDest.left = rc.left + rcCorners.left;
|
||
rcDest.top = rc.top + rcCorners.top;
|
||
rcDest.right = rc.right - rc.left - rcCorners.left - rcCorners.right;
|
||
rcDest.bottom = rc.bottom - rc.top - rcCorners.top - rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
if( !xtiled && !ytiled ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, \
|
||
rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right, \
|
||
rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom, SRCCOPY);
|
||
}
|
||
else if( xtiled && ytiled ) {
|
||
LONG lWidth = rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right;
|
||
LONG lHeight = rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom;
|
||
int iTimesX = (rcDest.right - rcDest.left + lWidth - 1) / lWidth;
|
||
int iTimesY = (rcDest.bottom - rcDest.top + lHeight - 1) / lHeight;
|
||
for( int j = 0; j < iTimesY; ++j ) {
|
||
LONG lDestTop = rcDest.top + lHeight * j;
|
||
LONG lDestBottom = rcDest.top + lHeight * (j + 1);
|
||
LONG lDrawHeight = lHeight;
|
||
if( lDestBottom > rcDest.bottom ) {
|
||
lDrawHeight -= lDestBottom - rcDest.bottom;
|
||
lDestBottom = rcDest.bottom;
|
||
}
|
||
for( int i = 0; i < iTimesX; ++i ) {
|
||
LONG lDestLeft = rcDest.left + lWidth * i;
|
||
LONG lDestRight = rcDest.left + lWidth * (i + 1);
|
||
LONG lDrawWidth = lWidth;
|
||
if( lDestRight > rcDest.right ) {
|
||
lDrawWidth -= lDestRight - rcDest.right;
|
||
lDestRight = rcDest.right;
|
||
}
|
||
::BitBlt(hDC, rcDest.left + lWidth * i, rcDest.top + lHeight * j, \
|
||
lDestRight - lDestLeft, lDestBottom - lDestTop, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, SRCCOPY);
|
||
}
|
||
}
|
||
}
|
||
else if( xtiled ) {
|
||
LONG lWidth = rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right;
|
||
int iTimes = (rcDest.right - rcDest.left + lWidth - 1) / lWidth;
|
||
for( int i = 0; i < iTimes; ++i ) {
|
||
LONG lDestLeft = rcDest.left + lWidth * i;
|
||
LONG lDestRight = rcDest.left + lWidth * (i + 1);
|
||
LONG lDrawWidth = lWidth;
|
||
if( lDestRight > rcDest.right ) {
|
||
lDrawWidth -= lDestRight - rcDest.right;
|
||
lDestRight = rcDest.right;
|
||
}
|
||
::StretchBlt(hDC, lDestLeft, rcDest.top, lDestRight - lDestLeft, rcDest.bottom,
|
||
hCloneDC, rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, \
|
||
lDrawWidth, rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom, SRCCOPY);
|
||
}
|
||
}
|
||
else { // ytiled
|
||
LONG lHeight = rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom;
|
||
int iTimes = (rcDest.bottom - rcDest.top + lHeight - 1) / lHeight;
|
||
for( int i = 0; i < iTimes; ++i ) {
|
||
LONG lDestTop = rcDest.top + lHeight * i;
|
||
LONG lDestBottom = rcDest.top + lHeight * (i + 1);
|
||
LONG lDrawHeight = lHeight;
|
||
if( lDestBottom > rcDest.bottom ) {
|
||
lDrawHeight -= lDestBottom - rcDest.bottom;
|
||
lDestBottom = rcDest.bottom;
|
||
}
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top + lHeight * i, rcDest.right, lDestBottom - lDestTop,
|
||
hCloneDC, rcBmpPart.left + rcCorners.left, rcBmpPart.top + rcCorners.top, \
|
||
rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right, lDrawHeight, SRCCOPY);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// left-top
|
||
if( rcCorners.left > 0 && rcCorners.top > 0 ) {
|
||
rcDest.left = rc.left;
|
||
rcDest.top = rc.top;
|
||
rcDest.right = rcCorners.left;
|
||
rcDest.bottom = rcCorners.top;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left, rcBmpPart.top, rcCorners.left, rcCorners.top, SRCCOPY);
|
||
}
|
||
}
|
||
// top
|
||
if( rcCorners.top > 0 ) {
|
||
rcDest.left = rc.left + rcCorners.left;
|
||
rcDest.top = rc.top;
|
||
rcDest.right = rc.right - rc.left - rcCorners.left - rcCorners.right;
|
||
rcDest.bottom = rcCorners.top;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.top, rcBmpPart.right - rcBmpPart.left - \
|
||
rcCorners.left - rcCorners.right, rcCorners.top, SRCCOPY);
|
||
}
|
||
}
|
||
// right-top
|
||
if( rcCorners.right > 0 && rcCorners.top > 0 ) {
|
||
rcDest.left = rc.right - rcCorners.right;
|
||
rcDest.top = rc.top;
|
||
rcDest.right = rcCorners.right;
|
||
rcDest.bottom = rcCorners.top;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.right - rcCorners.right, rcBmpPart.top, rcCorners.right, rcCorners.top, SRCCOPY);
|
||
}
|
||
}
|
||
// left
|
||
if( rcCorners.left > 0 ) {
|
||
rcDest.left = rc.left;
|
||
rcDest.top = rc.top + rcCorners.top;
|
||
rcDest.right = rcCorners.left;
|
||
rcDest.bottom = rc.bottom - rc.top - rcCorners.top - rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left, rcBmpPart.top + rcCorners.top, rcCorners.left, rcBmpPart.bottom - \
|
||
rcBmpPart.top - rcCorners.top - rcCorners.bottom, SRCCOPY);
|
||
}
|
||
}
|
||
// right
|
||
if( rcCorners.right > 0 ) {
|
||
rcDest.left = rc.right - rcCorners.right;
|
||
rcDest.top = rc.top + rcCorners.top;
|
||
rcDest.right = rcCorners.right;
|
||
rcDest.bottom = rc.bottom - rc.top - rcCorners.top - rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.right - rcCorners.right, rcBmpPart.top + rcCorners.top, rcCorners.right, \
|
||
rcBmpPart.bottom - rcBmpPart.top - rcCorners.top - rcCorners.bottom, SRCCOPY);
|
||
}
|
||
}
|
||
// left-bottom
|
||
if( rcCorners.left > 0 && rcCorners.bottom > 0 ) {
|
||
rcDest.left = rc.left;
|
||
rcDest.top = rc.bottom - rcCorners.bottom;
|
||
rcDest.right = rcCorners.left;
|
||
rcDest.bottom = rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left, rcBmpPart.bottom - rcCorners.bottom, rcCorners.left, rcCorners.bottom, SRCCOPY);
|
||
}
|
||
}
|
||
// bottom
|
||
if( rcCorners.bottom > 0 ) {
|
||
rcDest.left = rc.left + rcCorners.left;
|
||
rcDest.top = rc.bottom - rcCorners.bottom;
|
||
rcDest.right = rc.right - rc.left - rcCorners.left - rcCorners.right;
|
||
rcDest.bottom = rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.left + rcCorners.left, rcBmpPart.bottom - rcCorners.bottom, \
|
||
rcBmpPart.right - rcBmpPart.left - rcCorners.left - rcCorners.right, rcCorners.bottom, SRCCOPY);
|
||
}
|
||
}
|
||
// right-bottom
|
||
if( rcCorners.right > 0 && rcCorners.bottom > 0 ) {
|
||
rcDest.left = rc.right - rcCorners.right;
|
||
rcDest.top = rc.bottom - rcCorners.bottom;
|
||
rcDest.right = rcCorners.right;
|
||
rcDest.bottom = rcCorners.bottom;
|
||
rcDest.right += rcDest.left;
|
||
rcDest.bottom += rcDest.top;
|
||
if( ::IntersectRect(&rcTemp, &rcPaint, &rcDest) ) {
|
||
rcDest.right -= rcDest.left;
|
||
rcDest.bottom -= rcDest.top;
|
||
::StretchBlt(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, hCloneDC, \
|
||
rcBmpPart.right - rcCorners.right, rcBmpPart.bottom - rcCorners.bottom, rcCorners.right, \
|
||
rcCorners.bottom, SRCCOPY);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
::SelectObject(hCloneDC, hOldBitmap);
|
||
::DeleteDC(hCloneDC);
|
||
}
|
||
|
||
|
||
bool DrawImage(HDC hDC, CPaintManagerUI* pManager, const RECT& rc, const RECT& rcPaint, const CDuiString& sImageName, \
|
||
const CDuiString& sImageResType, RECT rcItem, RECT rcBmpPart, RECT rcCorner, DWORD dwMask, BYTE bFade, \
|
||
bool bHole, bool bTiledX, bool bTiledY)
|
||
{
|
||
if (sImageName.IsEmpty()) {
|
||
return false;
|
||
}
|
||
const TImageInfo* data = NULL;
|
||
if( sImageResType.IsEmpty() ) {
|
||
data = pManager->GetImageEx((LPCTSTR)sImageName, NULL, dwMask);
|
||
}
|
||
else {
|
||
data = pManager->GetImageEx((LPCTSTR)sImageName, (LPCTSTR)sImageResType, dwMask);
|
||
}
|
||
if( !data ) return false;
|
||
|
||
if( rcBmpPart.left == 0 && rcBmpPart.right == 0 && rcBmpPart.top == 0 && rcBmpPart.bottom == 0 ) {
|
||
rcBmpPart.right = data->nX;
|
||
rcBmpPart.bottom = data->nY;
|
||
}
|
||
if (rcBmpPart.right > data->nX) rcBmpPart.right = data->nX;
|
||
if (rcBmpPart.bottom > data->nY) rcBmpPart.bottom = data->nY;
|
||
|
||
RECT rcTemp;
|
||
if( !::IntersectRect(&rcTemp, &rcItem, &rc) ) return true;
|
||
if( !::IntersectRect(&rcTemp, &rcItem, &rcPaint) ) return true;
|
||
|
||
CRenderEngine::DrawImage(hDC, data->hBitmap, rcItem, rcPaint, rcBmpPart, rcCorner, pManager->IsBackgroundTransparent() ? true : data->alphaChannel, bFade, bHole, bTiledX, bTiledY);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CRenderEngine::DrawImageString(HDC hDC, CPaintManagerUI* pManager, const RECT& rc, const RECT& rcPaint,
|
||
LPCTSTR pStrImage, LPCTSTR pStrModify)
|
||
{
|
||
if ((pManager == NULL) || (hDC == NULL)) return false;
|
||
|
||
// 1、aaa.jpg
|
||
// 2、file='aaa.jpg' res='' restype='0' dest='0,0,0,0' source='0,0,0,0' corner='0,0,0,0'
|
||
// mask='#FF0000' fade='255' hole='false' xtiled='false' ytiled='false'
|
||
|
||
CDuiString sImageName = pStrImage;
|
||
CDuiString sImageResType;
|
||
RECT rcItem = rc;
|
||
RECT rcBmpPart = {0};
|
||
RECT rcCorner = {0};
|
||
DWORD dwMask = 0;
|
||
BYTE bFade = 0xFF;
|
||
bool bHole = false;
|
||
bool bTiledX = false;
|
||
bool bTiledY = false;
|
||
|
||
int image_count = 0;
|
||
|
||
CDuiString sItem;
|
||
CDuiString sValue;
|
||
LPTSTR pstr = NULL;
|
||
|
||
for( int i = 0; i < 2; ++i,image_count = 0 ) {
|
||
if( i == 1)
|
||
pStrImage = pStrModify;
|
||
|
||
if( !pStrImage ) continue;
|
||
|
||
while( *pStrImage != _T('\0') ) {
|
||
sItem.Empty();
|
||
sValue.Empty();
|
||
while( *pStrImage > _T('\0') && *pStrImage <= _T(' ') ) pStrImage = ::CharNext(pStrImage);
|
||
while( *pStrImage != _T('\0') && *pStrImage != _T('=') && *pStrImage > _T(' ') ) {
|
||
LPTSTR pstrTemp = ::CharNext(pStrImage);
|
||
while( pStrImage < pstrTemp) {
|
||
sItem += *pStrImage++;
|
||
}
|
||
}
|
||
while( *pStrImage > _T('\0') && *pStrImage <= _T(' ') ) pStrImage = ::CharNext(pStrImage);
|
||
if( *pStrImage++ != _T('=') ) break;
|
||
while( *pStrImage > _T('\0') && *pStrImage <= _T(' ') ) pStrImage = ::CharNext(pStrImage);
|
||
if( *pStrImage++ != _T('\'') ) break;
|
||
while( *pStrImage != _T('\0') && *pStrImage != _T('\'') ) {
|
||
LPTSTR pstrTemp = ::CharNext(pStrImage);
|
||
while( pStrImage < pstrTemp) {
|
||
sValue += *pStrImage++;
|
||
}
|
||
}
|
||
if( *pStrImage++ != _T('\'') ) break;
|
||
if( !sValue.IsEmpty() ) {
|
||
if( sItem == _T("file") || sItem == _T("res") ) {
|
||
if( image_count > 0 )
|
||
DuiLib::DrawImage(hDC, pManager, rc, rcPaint, sImageName, sImageResType,
|
||
rcItem, rcBmpPart, rcCorner, dwMask, bFade, bHole, bTiledX, bTiledY);
|
||
|
||
sImageName = sValue;
|
||
if( sItem == _T("file") )
|
||
++image_count;
|
||
}
|
||
else if( sItem == _T("restype") ) {
|
||
if( image_count > 0 )
|
||
DuiLib::DrawImage(hDC, pManager, rc, rcPaint, sImageName, sImageResType,
|
||
rcItem, rcBmpPart, rcCorner, dwMask, bFade, bHole, bTiledX, bTiledY);
|
||
|
||
sImageResType = sValue;
|
||
++image_count;
|
||
}
|
||
else if( sItem == _T("dest") ) {
|
||
rcItem.left = rc.left + _tcstol(sValue.GetData(), &pstr, 10); ASSERT(pstr);
|
||
rcItem.top = rc.top + _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
rcItem.right = rc.left + _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
if (rcItem.right > rc.right) rcItem.right = rc.right;
|
||
rcItem.bottom = rc.top + _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
if (rcItem.bottom > rc.bottom) rcItem.bottom = rc.bottom;
|
||
}
|
||
else if( sItem == _T("source") ) {
|
||
rcBmpPart.left = _tcstol(sValue.GetData(), &pstr, 10); ASSERT(pstr);
|
||
rcBmpPart.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
rcBmpPart.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
rcBmpPart.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
}
|
||
else if( sItem == _T("corner") ) {
|
||
rcCorner.left = _tcstol(sValue.GetData(), &pstr, 10); ASSERT(pstr);
|
||
rcCorner.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
rcCorner.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
rcCorner.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
|
||
}
|
||
else if( sItem == _T("mask") ) {
|
||
if( sValue[0] == _T('#')) dwMask = _tcstoul(sValue.GetData() + 1, &pstr, 16);
|
||
else dwMask = _tcstoul(sValue.GetData(), &pstr, 16);
|
||
}
|
||
else if( sItem == _T("fade") ) {
|
||
bFade = (BYTE)_tcstoul(sValue.GetData(), &pstr, 10);
|
||
}
|
||
else if( sItem == _T("hole") ) {
|
||
bHole = (_tcscmp(sValue.GetData(), _T("true")) == 0);
|
||
}
|
||
else if( sItem == _T("xtiled") ) {
|
||
bTiledX = (_tcscmp(sValue.GetData(), _T("true")) == 0);
|
||
}
|
||
else if( sItem == _T("ytiled") ) {
|
||
bTiledY = (_tcscmp(sValue.GetData(), _T("true")) == 0);
|
||
}
|
||
}
|
||
if( *pStrImage++ != _T(' ') ) break;
|
||
}
|
||
}
|
||
|
||
DuiLib::DrawImage(hDC, pManager, rc, rcPaint, sImageName, sImageResType,
|
||
rcItem, rcBmpPart, rcCorner, dwMask, bFade, bHole, bTiledX, bTiledY);
|
||
|
||
return true;
|
||
}
|
||
|
||
void CRenderEngine::DrawColor(HDC hDC, const RECT& rc, DWORD color)
|
||
{
|
||
if( color <= 0x00FFFFFF ) return;
|
||
|
||
Gdiplus::Graphics graphics( hDC );
|
||
Gdiplus::SolidBrush brush(Gdiplus::Color((LOBYTE((color)>>24)), GetBValue(color), GetGValue(color), GetRValue(color)));
|
||
|
||
graphics.FillRectangle(&brush, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
|
||
|
||
// 原来的代码,填充的背景色不包含透明通道,在透明模式下输出的图片和文字会出现问题,所以改为gdi+填充背景色
|
||
// if( color <= 0x00FFFFFF ) return;
|
||
// if( color >= 0xFF000000 )
|
||
// {
|
||
// ::SetBkColor(hDC, RGB(GetBValue(color), GetGValue(color), GetRValue(color)));
|
||
// ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
|
||
// }
|
||
// else
|
||
// {
|
||
// // Create a new 32bpp bitmap with room for an alpha channel
|
||
// BITMAPINFO bmi = { 0 };
|
||
// bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
// bmi.bmiHeader.biWidth = 1;
|
||
// bmi.bmiHeader.biHeight = 1;
|
||
// bmi.bmiHeader.biPlanes = 1;
|
||
// bmi.bmiHeader.biBitCount = 32;
|
||
// bmi.bmiHeader.biCompression = BI_RGB;
|
||
// bmi.bmiHeader.biSizeImage = 1 * 1 * sizeof(DWORD);
|
||
// LPDWORD pDest = NULL;
|
||
// HBITMAP hBitmap = ::CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (LPVOID*) &pDest, NULL, 0);
|
||
// if( !hBitmap ) return;
|
||
//
|
||
// *pDest = color;
|
||
//
|
||
// RECT rcBmpPart = {0, 0, 1, 1};
|
||
// RECT rcCorners = {0};
|
||
// DrawImage(hDC, hBitmap, rc, rc, rcBmpPart, rcCorners, true, 255);
|
||
// ::DeleteObject(hBitmap);
|
||
// }
|
||
|
||
}
|
||
|
||
void CRenderEngine::DrawGradient(HDC hDC, const RECT& rc, DWORD dwFirst, DWORD dwSecond, bool bVertical, int nSteps)
|
||
{
|
||
typedef BOOL (WINAPI *LPALPHABLEND)(HDC, int, int, int, int,HDC, int, int, int, int, BLENDFUNCTION);
|
||
static LPALPHABLEND lpAlphaBlend = (LPALPHABLEND) ::GetProcAddress(::GetModuleHandle(_T("msimg32.dll")), "AlphaBlend");
|
||
if( lpAlphaBlend == NULL ) lpAlphaBlend = AlphaBitBlt;
|
||
typedef BOOL (WINAPI *PGradientFill)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
|
||
static PGradientFill lpGradientFill = (PGradientFill) ::GetProcAddress(::GetModuleHandle(_T("msimg32.dll")), "GradientFill");
|
||
|
||
BYTE bAlpha = (BYTE)(((dwFirst >> 24) + (dwSecond >> 24)) >> 1);
|
||
if( bAlpha == 0 ) return;
|
||
int cx = rc.right - rc.left;
|
||
int cy = rc.bottom - rc.top;
|
||
RECT rcPaint = rc;
|
||
HDC hPaintDC = hDC;
|
||
HBITMAP hPaintBitmap = NULL;
|
||
HBITMAP hOldPaintBitmap = NULL;
|
||
if( bAlpha < 255 ) {
|
||
rcPaint.left = rcPaint.top = 0;
|
||
rcPaint.right = cx;
|
||
rcPaint.bottom = cy;
|
||
hPaintDC = ::CreateCompatibleDC(hDC);
|
||
hPaintBitmap = ::CreateCompatibleBitmap(hDC, cx, cy);
|
||
ASSERT(hPaintDC);
|
||
ASSERT(hPaintBitmap);
|
||
hOldPaintBitmap = (HBITMAP) ::SelectObject(hPaintDC, hPaintBitmap);
|
||
}
|
||
if( lpGradientFill != NULL )
|
||
{
|
||
TRIVERTEX triv[2] =
|
||
{
|
||
{ rcPaint.left, rcPaint.top, GetBValue(dwFirst) << 8, GetGValue(dwFirst) << 8, GetRValue(dwFirst) << 8, 0xFF00 },
|
||
{ rcPaint.right, rcPaint.bottom, GetBValue(dwSecond) << 8, GetGValue(dwSecond) << 8, GetRValue(dwSecond) << 8, 0xFF00 }
|
||
};
|
||
GRADIENT_RECT grc = { 0, 1 };
|
||
lpGradientFill(hPaintDC, triv, 2, &grc, 1, bVertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
|
||
}
|
||
else
|
||
{
|
||
// Determine how many shades
|
||
int nShift = 1;
|
||
if( nSteps >= 64 ) nShift = 6;
|
||
else if( nSteps >= 32 ) nShift = 5;
|
||
else if( nSteps >= 16 ) nShift = 4;
|
||
else if( nSteps >= 8 ) nShift = 3;
|
||
else if( nSteps >= 4 ) nShift = 2;
|
||
int nLines = 1 << nShift;
|
||
for( int i = 0; i < nLines; i++ ) {
|
||
// Do a little alpha blending
|
||
BYTE bR = (BYTE) ((GetBValue(dwSecond) * (nLines - i) + GetBValue(dwFirst) * i) >> nShift);
|
||
BYTE bG = (BYTE) ((GetGValue(dwSecond) * (nLines - i) + GetGValue(dwFirst) * i) >> nShift);
|
||
BYTE bB = (BYTE) ((GetRValue(dwSecond) * (nLines - i) + GetRValue(dwFirst) * i) >> nShift);
|
||
// ... then paint with the resulting color
|
||
HBRUSH hBrush = ::CreateSolidBrush(RGB(bR,bG,bB));
|
||
RECT r2 = rcPaint;
|
||
if( bVertical ) {
|
||
r2.bottom = rc.bottom - ((i * (rc.bottom - rc.top)) >> nShift);
|
||
r2.top = rc.bottom - (((i + 1) * (rc.bottom - rc.top)) >> nShift);
|
||
if( (r2.bottom - r2.top) > 0 ) ::FillRect(hDC, &r2, hBrush);
|
||
}
|
||
else {
|
||
r2.left = rc.right - (((i + 1) * (rc.right - rc.left)) >> nShift);
|
||
r2.right = rc.right - ((i * (rc.right - rc.left)) >> nShift);
|
||
if( (r2.right - r2.left) > 0 ) ::FillRect(hPaintDC, &r2, hBrush);
|
||
}
|
||
::DeleteObject(hBrush);
|
||
}
|
||
}
|
||
if( bAlpha < 255 ) {
|
||
BLENDFUNCTION bf = { AC_SRC_OVER, 0, bAlpha, AC_SRC_ALPHA };
|
||
lpAlphaBlend(hDC, rc.left, rc.top, cx, cy, hPaintDC, 0, 0, cx, cy, bf);
|
||
::SelectObject(hPaintDC, hOldPaintBitmap);
|
||
::DeleteObject(hPaintBitmap);
|
||
::DeleteDC(hPaintDC);
|
||
}
|
||
}
|
||
|
||
void CRenderEngine::DrawLine( HDC hDC, const RECT& rc, int nSize, DWORD dwPenColor,int nStyle /*= PS_SOLID*/ )
|
||
{
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
|
||
LOGPEN lg;
|
||
lg.lopnColor = RGB(GetBValue(dwPenColor), GetGValue(dwPenColor), GetRValue(dwPenColor));
|
||
lg.lopnStyle = nStyle;
|
||
lg.lopnWidth.x = nSize;
|
||
HPEN hPen = CreatePenIndirect(&lg);
|
||
HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
|
||
POINT ptTemp = { 0 };
|
||
::MoveToEx(hDC, rc.left, rc.top, &ptTemp);
|
||
::LineTo(hDC, rc.right, rc.bottom);
|
||
::SelectObject(hDC, hOldPen);
|
||
::DeleteObject(hPen);
|
||
}
|
||
|
||
void CRenderEngine::DrawRect(HDC hDC, const RECT& rc, int nSize, DWORD dwPenColor)
|
||
{
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
HPEN hPen = ::CreatePen(PS_SOLID | PS_INSIDEFRAME, nSize, RGB(GetBValue(dwPenColor), GetGValue(dwPenColor), GetRValue(dwPenColor)));
|
||
HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
|
||
::SelectObject(hDC, ::GetStockObject(HOLLOW_BRUSH));
|
||
::Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
|
||
::SelectObject(hDC, hOldPen);
|
||
::DeleteObject(hPen);
|
||
}
|
||
|
||
void CRenderEngine::DrawRoundRect(HDC hDC, const RECT& rc, int nSize, int width, int height, DWORD dwPenColor)
|
||
{
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
HPEN hPen = ::CreatePen(PS_SOLID | PS_INSIDEFRAME, nSize, RGB(GetBValue(dwPenColor), GetGValue(dwPenColor), GetRValue(dwPenColor)));
|
||
HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
|
||
::SelectObject(hDC, ::GetStockObject(HOLLOW_BRUSH));
|
||
::RoundRect(hDC, rc.left, rc.top, rc.right, rc.bottom, width, height);
|
||
::SelectObject(hDC, hOldPen);
|
||
::DeleteObject(hPen);
|
||
}
|
||
|
||
void CRenderEngine::DrawText(HDC hDC, CPaintManagerUI* pManager, RECT& rc, LPCTSTR pstrText, DWORD dwTextColor, int iFont, UINT uStyle)
|
||
{
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
if( pstrText == NULL || pManager == NULL ) return;
|
||
|
||
if ( pManager->IsBackgroundTransparent() || pManager->IsUseGdiplusText())
|
||
{
|
||
Gdiplus::Graphics graphics( hDC );
|
||
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
|
||
|
||
Gdiplus::Font font(hDC, pManager->GetFont(iFont));
|
||
Gdiplus::RectF rectF((Gdiplus::REAL)rc.left, (Gdiplus::REAL)rc.top, (Gdiplus::REAL)(rc.right - rc.left), (Gdiplus::REAL)(rc.bottom - rc.top));
|
||
Gdiplus::SolidBrush brush(Gdiplus::Color(254, GetBValue(dwTextColor), GetGValue(dwTextColor), GetRValue(dwTextColor)));
|
||
|
||
Gdiplus::StringFormat stringFormat = Gdiplus::StringFormat::GenericTypographic();
|
||
|
||
if ((uStyle & DT_END_ELLIPSIS) != 0) {
|
||
stringFormat.SetTrimming(Gdiplus::StringTrimmingEllipsisCharacter);
|
||
}
|
||
|
||
int formatFlags = 0;
|
||
if ((uStyle & DT_NOCLIP) != 0) {
|
||
formatFlags |= Gdiplus::StringFormatFlagsNoClip;
|
||
}
|
||
if ((uStyle & DT_SINGLELINE) != 0) {
|
||
formatFlags |= Gdiplus::StringFormatFlagsNoWrap;
|
||
}
|
||
|
||
stringFormat.SetFormatFlags(formatFlags);
|
||
|
||
if ((uStyle & DT_LEFT) != 0) {
|
||
stringFormat.SetAlignment(Gdiplus::StringAlignmentNear);
|
||
}
|
||
else if ((uStyle & DT_CENTER) != 0) {
|
||
stringFormat.SetAlignment(Gdiplus::StringAlignmentCenter);
|
||
}
|
||
else if ((uStyle & DT_RIGHT) != 0) {
|
||
stringFormat.SetAlignment(Gdiplus::StringAlignmentFar);
|
||
}
|
||
else {
|
||
stringFormat.SetAlignment(Gdiplus::StringAlignmentNear);
|
||
}
|
||
stringFormat.GenericTypographic();
|
||
if ((uStyle & DT_TOP) != 0) {
|
||
stringFormat.SetLineAlignment(Gdiplus::StringAlignmentNear);
|
||
}
|
||
else if ((uStyle & DT_VCENTER) != 0) {
|
||
stringFormat.SetLineAlignment(Gdiplus::StringAlignmentCenter);
|
||
}
|
||
else if ((uStyle & DT_BOTTOM) != 0) {
|
||
stringFormat.SetLineAlignment(Gdiplus::StringAlignmentFar);
|
||
}
|
||
else {
|
||
stringFormat.SetLineAlignment(Gdiplus::StringAlignmentNear);
|
||
}
|
||
|
||
if ((uStyle & DT_CALCRECT) != 0)
|
||
{
|
||
Gdiplus::RectF bounds;
|
||
graphics.MeasureString(pstrText, -1, &font, rectF, &stringFormat, &bounds);
|
||
|
||
// MeasureString存在计算误差,这里加一像素
|
||
rc.bottom = rc.top + (long)bounds.Height + 1;
|
||
rc.right = rc.left + (long)bounds.Width + 1;
|
||
}
|
||
else
|
||
{
|
||
graphics.DrawString(pstrText, -1, &font, rectF, &stringFormat, &brush);
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
::SetBkMode(hDC, TRANSPARENT);
|
||
::SetTextColor(hDC, RGB(GetBValue(dwTextColor), GetGValue(dwTextColor), GetRValue(dwTextColor)));
|
||
HFONT hOldFont = (HFONT)::SelectObject(hDC, pManager->GetFont(iFont));
|
||
::DrawText(hDC, pstrText, -1, &rc, uStyle | DT_NOPREFIX);
|
||
::SelectObject(hDC, hOldFont);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
void CRenderEngine::DrawHtmlText(HDC hDC, CPaintManagerUI* pManager, RECT& rc, LPCTSTR pstrText, DWORD dwTextColor, RECT* prcLinks, CDuiString* sLinks, int& nLinkRects, UINT uStyle)
|
||
{
|
||
// 考虑到在xml编辑器中使用<>符号不方便,可以使用{}符号代替
|
||
// 支持标签嵌套(如<l><b>text</b></l>),但是交叉嵌套是应该避免的(如<l><b>text</l></b>)
|
||
// The string formatter supports a kind of "mini-html" that consists of various short tags:
|
||
//
|
||
// Bold: <b>text</b>
|
||
// Color: <c #xxxxxx>text</c> where x = RGB in hex
|
||
// Font: <f x>text</f> where x = font id
|
||
// Italic: <i>text</i>
|
||
// Image: <i x y z> where x = image name and y = imagelist num and z(optional) = imagelist id
|
||
// Link: <a x>text</a> where x(optional) = link content, normal like app:notepad or http:www.xxx.com
|
||
// NewLine <n>
|
||
// Paragraph: <p x>text</p> where x = extra pixels indent in p
|
||
// Raw Text: <r>text</r>
|
||
// Selected: <s>text</s>
|
||
// Underline: <u>text</u>
|
||
// X Indent: <x i> where i = hor indent in pixels
|
||
// Y Indent: <y i> where i = ver indent in pixels
|
||
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
if( pstrText == NULL || pManager == NULL ) return;
|
||
if( ::IsRectEmpty(&rc) ) return;
|
||
|
||
bool bDraw = (uStyle & DT_CALCRECT) == 0;
|
||
|
||
CStdPtrArray aFontArray(10);
|
||
CStdPtrArray aColorArray(10);
|
||
CStdPtrArray aPIndentArray(10);
|
||
|
||
RECT rcClip = { 0 };
|
||
::GetClipBox(hDC, &rcClip);
|
||
HRGN hOldRgn = ::CreateRectRgnIndirect(&rcClip);
|
||
HRGN hRgn = ::CreateRectRgnIndirect(&rc);
|
||
if( bDraw ) ::ExtSelectClipRgn(hDC, hRgn, RGN_AND);
|
||
|
||
TEXTMETRIC* pTm = &pManager->GetDefaultFontInfo()->tm;
|
||
HFONT hOldFont = (HFONT) ::SelectObject(hDC, pManager->GetDefaultFontInfo()->hFont);
|
||
::SetBkMode(hDC, TRANSPARENT);
|
||
::SetTextColor(hDC, RGB(GetBValue(dwTextColor), GetGValue(dwTextColor), GetRValue(dwTextColor)));
|
||
DWORD dwBkColor = pManager->GetDefaultSelectedBkColor();
|
||
::SetBkColor(hDC, RGB(GetBValue(dwBkColor), GetGValue(dwBkColor), GetRValue(dwBkColor)));
|
||
|
||
// If the drawstyle include a alignment, we'll need to first determine the text-size so
|
||
// we can draw it at the correct position...
|
||
if( ((uStyle & DT_CENTER) != 0 || (uStyle & DT_RIGHT) != 0 || (uStyle & DT_VCENTER) != 0 || (uStyle & DT_BOTTOM) != 0) && (uStyle & DT_CALCRECT) == 0 ) {
|
||
RECT rcText = { 0, 0, 9999, 100 };
|
||
int nLinks = 0;
|
||
DrawHtmlText(hDC, pManager, rcText, pstrText, dwTextColor, NULL, NULL, nLinks, uStyle | DT_CALCRECT);
|
||
if( (uStyle & DT_SINGLELINE) != 0 ){
|
||
if( (uStyle & DT_CENTER) != 0 ) {
|
||
rc.left = rc.left + ((rc.right - rc.left) / 2) - ((rcText.right - rcText.left) / 2);
|
||
rc.right = rc.left + (rcText.right - rcText.left);
|
||
}
|
||
if( (uStyle & DT_RIGHT) != 0 ) {
|
||
rc.left = rc.right - (rcText.right - rcText.left);
|
||
}
|
||
}
|
||
if( (uStyle & DT_VCENTER) != 0 ) {
|
||
rc.top = rc.top + ((rc.bottom - rc.top) / 2) - ((rcText.bottom - rcText.top) / 2);
|
||
rc.bottom = rc.top + (rcText.bottom - rcText.top);
|
||
}
|
||
if( (uStyle & DT_BOTTOM) != 0 ) {
|
||
rc.top = rc.bottom - (rcText.bottom - rcText.top);
|
||
}
|
||
}
|
||
|
||
bool bHoverLink = false;
|
||
CDuiString sHoverLink;
|
||
POINT ptMouse = pManager->GetMousePos();
|
||
for( int i = 0; !bHoverLink && i < nLinkRects; i++ ) {
|
||
if( ::PtInRect(prcLinks + i, ptMouse) ) {
|
||
sHoverLink = *(CDuiString*)(sLinks + i);
|
||
bHoverLink = true;
|
||
}
|
||
}
|
||
|
||
POINT pt = { rc.left, rc.top };
|
||
int iLinkIndex = 0;
|
||
int cyLine = pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1);
|
||
int cyMinHeight = 0;
|
||
int cxMaxWidth = 0;
|
||
POINT ptLinkStart = { 0 };
|
||
bool bLineEnd = false;
|
||
bool bInRaw = false;
|
||
bool bInLink = false;
|
||
bool bInSelected = false;
|
||
int iLineLinkIndex = 0;
|
||
|
||
// 排版习惯是图文底部对齐,所以每行绘制都要分两步,先计算高度,再绘制
|
||
CStdPtrArray aLineFontArray;
|
||
CStdPtrArray aLineColorArray;
|
||
CStdPtrArray aLinePIndentArray;
|
||
LPCTSTR pstrLineBegin = pstrText;
|
||
bool bLineInRaw = false;
|
||
bool bLineInLink = false;
|
||
bool bLineInSelected = false;
|
||
int cyLineHeight = 0;
|
||
bool bLineDraw = false; // 行的第二阶段:绘制
|
||
while( *pstrText != _T('\0') ) {
|
||
if( pt.x >= rc.right || *pstrText == _T('\n') || bLineEnd ) {
|
||
if( *pstrText == _T('\n') ) pstrText++;
|
||
if( bLineEnd ) bLineEnd = false;
|
||
if( !bLineDraw ) {
|
||
if( bInLink && iLinkIndex < nLinkRects ) {
|
||
::SetRect(&prcLinks[iLinkIndex++], ptLinkStart.x, ptLinkStart.y, MIN(pt.x, rc.right), pt.y + cyLine);
|
||
CDuiString *pStr1 = (CDuiString*)(sLinks + iLinkIndex - 1);
|
||
CDuiString *pStr2 = (CDuiString*)(sLinks + iLinkIndex);
|
||
*pStr2 = *pStr1;
|
||
}
|
||
for( int i = iLineLinkIndex; i < iLinkIndex; i++ ) {
|
||
prcLinks[i].bottom = pt.y + cyLine;
|
||
}
|
||
if( bDraw ) {
|
||
bInLink = bLineInLink;
|
||
iLinkIndex = iLineLinkIndex;
|
||
}
|
||
}
|
||
else {
|
||
if( bInLink && iLinkIndex < nLinkRects ) iLinkIndex++;
|
||
bLineInLink = bInLink;
|
||
iLineLinkIndex = iLinkIndex;
|
||
}
|
||
if( (uStyle & DT_SINGLELINE) != 0 && (!bDraw || bLineDraw) ) break;
|
||
if( bDraw ) bLineDraw = !bLineDraw; // !
|
||
pt.x = rc.left;
|
||
if( !bLineDraw ) pt.y += cyLine;
|
||
if( pt.y > rc.bottom && bDraw ) break;
|
||
ptLinkStart = pt;
|
||
cyLine = pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1);
|
||
if( pt.x >= rc.right ) break;
|
||
}
|
||
else if( !bInRaw && ( *pstrText == _T('<') || *pstrText == _T('{') )
|
||
&& ( pstrText[1] >= _T('a') && pstrText[1] <= _T('z') )
|
||
&& ( pstrText[2] == _T(' ') || pstrText[2] == _T('>') || pstrText[2] == _T('}') ) ) {
|
||
pstrText++;
|
||
LPCTSTR pstrNextStart = NULL;
|
||
switch( *pstrText ) {
|
||
case _T('a'): // Link
|
||
{
|
||
pstrText++;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
if( iLinkIndex < nLinkRects && !bLineDraw ) {
|
||
CDuiString *pStr = (CDuiString*)(sLinks + iLinkIndex);
|
||
pStr->Empty();
|
||
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('}') ) {
|
||
LPCTSTR pstrTemp = ::CharNext(pstrText);
|
||
while( pstrText < pstrTemp) {
|
||
*pStr += *pstrText++;
|
||
}
|
||
}
|
||
}
|
||
|
||
DWORD clrColor = pManager->GetDefaultLinkFontColor();
|
||
if( bHoverLink && iLinkIndex < nLinkRects ) {
|
||
CDuiString *pStr = (CDuiString*)(sLinks + iLinkIndex);
|
||
if( sHoverLink == *pStr ) clrColor = pManager->GetDefaultLinkHoverFontColor();
|
||
}
|
||
//else if( prcLinks == NULL ) {
|
||
// if( ::PtInRect(&rc, ptMouse) )
|
||
// clrColor = pManager->GetDefaultLinkHoverFontColor();
|
||
//}
|
||
aColorArray.Add((LPVOID)clrColor);
|
||
::SetTextColor(hDC, RGB(GetBValue(clrColor), GetGValue(clrColor), GetRValue(clrColor)));
|
||
TFontInfo* pFontInfo = pManager->GetDefaultFontInfo();
|
||
if( aFontArray.GetSize() > 0 ) pFontInfo = (TFontInfo*)aFontArray.GetAt(aFontArray.GetSize() - 1);
|
||
if( pFontInfo->bUnderline == false ) {
|
||
HFONT hFont = pManager->GetFont(pFontInfo->sFontName, pFontInfo->iSize, pFontInfo->bBold, true, pFontInfo->bItalic);
|
||
if( hFont == NULL ) hFont = pManager->AddFont(pFontInfo->sFontName, pFontInfo->iSize, pFontInfo->bBold, true, pFontInfo->bItalic);
|
||
pFontInfo = pManager->GetFontInfo(hFont);
|
||
aFontArray.Add(pFontInfo);
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
}
|
||
ptLinkStart = pt;
|
||
bInLink = true;
|
||
}
|
||
break;
|
||
case _T('b'): // Bold
|
||
{
|
||
pstrText++;
|
||
TFontInfo* pFontInfo = pManager->GetDefaultFontInfo();
|
||
if( aFontArray.GetSize() > 0 ) pFontInfo = (TFontInfo*)aFontArray.GetAt(aFontArray.GetSize() - 1);
|
||
if( pFontInfo->bBold == false ) {
|
||
HFONT hFont = pManager->GetFont(pFontInfo->sFontName, pFontInfo->iSize, true, pFontInfo->bUnderline, pFontInfo->bItalic);
|
||
if( hFont == NULL ) hFont = pManager->AddFont(pFontInfo->sFontName, pFontInfo->iSize, true, pFontInfo->bUnderline, pFontInfo->bItalic);
|
||
pFontInfo = pManager->GetFontInfo(hFont);
|
||
aFontArray.Add(pFontInfo);
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
}
|
||
}
|
||
break;
|
||
case _T('c'): // Color
|
||
{
|
||
pstrText++;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
if( *pstrText == _T('#')) pstrText++;
|
||
DWORD clrColor = _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 16);
|
||
aColorArray.Add((LPVOID)clrColor);
|
||
::SetTextColor(hDC, RGB(GetBValue(clrColor), GetGValue(clrColor), GetRValue(clrColor)));
|
||
}
|
||
break;
|
||
case _T('f'): // Font
|
||
{
|
||
pstrText++;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
LPCTSTR pstrTemp = pstrText;
|
||
int iFont = (int) _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
//if( isdigit(*pstrText) ) { // debug版本会引起异常
|
||
if( pstrTemp != pstrText ) {
|
||
TFontInfo* pFontInfo = pManager->GetFontInfo(iFont);
|
||
aFontArray.Add(pFontInfo);
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
}
|
||
else {
|
||
CDuiString sFontName;
|
||
int iFontSize = 10;
|
||
CDuiString sFontAttr;
|
||
bool bBold = false;
|
||
bool bUnderline = false;
|
||
bool bItalic = false;
|
||
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('}') && *pstrText != _T(' ') ) {
|
||
pstrTemp = ::CharNext(pstrText);
|
||
while( pstrText < pstrTemp) {
|
||
sFontName += *pstrText++;
|
||
}
|
||
}
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
if( isdigit(*pstrText) ) {
|
||
iFontSize = (int) _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
}
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('}') ) {
|
||
pstrTemp = ::CharNext(pstrText);
|
||
while( pstrText < pstrTemp) {
|
||
sFontAttr += *pstrText++;
|
||
}
|
||
}
|
||
sFontAttr.MakeLower();
|
||
if( sFontAttr.Find(_T("bold")) >= 0 ) bBold = true;
|
||
if( sFontAttr.Find(_T("underline")) >= 0 ) bUnderline = true;
|
||
if( sFontAttr.Find(_T("italic")) >= 0 ) bItalic = true;
|
||
HFONT hFont = pManager->GetFont(sFontName, iFontSize, bBold, bUnderline, bItalic);
|
||
if( hFont == NULL ) hFont = pManager->AddFont(sFontName, iFontSize, bBold, bUnderline, bItalic);
|
||
TFontInfo* pFontInfo = pManager->GetFontInfo(hFont);
|
||
aFontArray.Add(pFontInfo);
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
}
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
}
|
||
break;
|
||
case _T('i'): // Italic or Image
|
||
{
|
||
pstrNextStart = pstrText - 1;
|
||
pstrText++;
|
||
CDuiString sImageString = pstrText;
|
||
int iWidth = 0;
|
||
int iHeight = 0;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
const TImageInfo* pImageInfo = NULL;
|
||
CDuiString sName;
|
||
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('}') && *pstrText != _T(' ') ) {
|
||
LPCTSTR pstrTemp = ::CharNext(pstrText);
|
||
while( pstrText < pstrTemp) {
|
||
sName += *pstrText++;
|
||
}
|
||
}
|
||
if( sName.IsEmpty() ) { // Italic
|
||
pstrNextStart = NULL;
|
||
TFontInfo* pFontInfo = pManager->GetDefaultFontInfo();
|
||
if( aFontArray.GetSize() > 0 ) pFontInfo = (TFontInfo*)aFontArray.GetAt(aFontArray.GetSize() - 1);
|
||
if( pFontInfo->bItalic == false ) {
|
||
HFONT hFont = pManager->GetFont(pFontInfo->sFontName, pFontInfo->iSize, pFontInfo->bBold, pFontInfo->bUnderline, true);
|
||
if( hFont == NULL ) hFont = pManager->AddFont(pFontInfo->sFontName, pFontInfo->iSize, pFontInfo->bBold, pFontInfo->bUnderline, true);
|
||
pFontInfo = pManager->GetFontInfo(hFont);
|
||
aFontArray.Add(pFontInfo);
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
}
|
||
}
|
||
else {
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
int iImageListNum = (int) _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
if( iImageListNum <= 0 ) iImageListNum = 1;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
int iImageListIndex = (int) _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
if( iImageListIndex < 0 || iImageListIndex >= iImageListNum ) iImageListIndex = 0;
|
||
|
||
if( _tcsstr(sImageString.GetData(), _T("file=\'")) != NULL || _tcsstr(sImageString.GetData(), _T("res=\'")) != NULL ) {
|
||
CDuiString sImageResType;
|
||
CDuiString sImageName;
|
||
LPCTSTR pStrImage = sImageString.GetData();
|
||
CDuiString sItem;
|
||
CDuiString sValue;
|
||
while( *pStrImage != _T('\0') ) {
|
||
sItem.Empty();
|
||
sValue.Empty();
|
||
while( *pStrImage > _T('\0') && *pStrImage <= _T(' ') ) pStrImage = ::CharNext(pStrImage);
|
||
while( *pStrImage != _T('\0') && *pStrImage != _T('=') && *pStrImage > _T(' ') ) {
|
||
LPTSTR pstrTemp = ::CharNext(pStrImage);
|
||
while( pStrImage < pstrTemp) {
|
||
sItem += *pStrImage++;
|
||
}
|
||
}
|
||
while( *pStrImage > _T('\0') && *pStrImage <= _T(' ') ) pStrImage = ::CharNext(pStrImage);
|
||
if( *pStrImage++ != _T('=') ) break;
|
||
while( *pStrImage > _T('\0') && *pStrImage <= _T(' ') ) pStrImage = ::CharNext(pStrImage);
|
||
if( *pStrImage++ != _T('\'') ) break;
|
||
while( *pStrImage != _T('\0') && *pStrImage != _T('\'') ) {
|
||
LPTSTR pstrTemp = ::CharNext(pStrImage);
|
||
while( pStrImage < pstrTemp) {
|
||
sValue += *pStrImage++;
|
||
}
|
||
}
|
||
if( *pStrImage++ != _T('\'') ) break;
|
||
if( !sValue.IsEmpty() ) {
|
||
if( sItem == _T("file") || sItem == _T("res") ) {
|
||
sImageName = sValue;
|
||
}
|
||
else if( sItem == _T("restype") ) {
|
||
sImageResType = sValue;
|
||
}
|
||
}
|
||
if( *pStrImage++ != _T(' ') ) break;
|
||
}
|
||
|
||
pImageInfo = pManager->GetImageEx((LPCTSTR)sImageName, sImageResType);
|
||
}
|
||
else
|
||
pImageInfo = pManager->GetImageEx((LPCTSTR)sName);
|
||
|
||
if( pImageInfo ) {
|
||
iWidth = pImageInfo->nX;
|
||
iHeight = pImageInfo->nY;
|
||
if( iImageListNum > 1 ) iWidth /= iImageListNum;
|
||
|
||
if( pt.x + iWidth > rc.right && pt.x > rc.left && (uStyle & DT_SINGLELINE) == 0 ) {
|
||
bLineEnd = true;
|
||
}
|
||
else {
|
||
pstrNextStart = NULL;
|
||
if( bDraw && bLineDraw ) {
|
||
CDuiRect rcImage(pt.x, pt.y + cyLineHeight - iHeight, pt.x + iWidth, pt.y + cyLineHeight);
|
||
if( iHeight < cyLineHeight ) {
|
||
rcImage.bottom -= (cyLineHeight - iHeight) / 2;
|
||
rcImage.top = rcImage.bottom - iHeight;
|
||
}
|
||
CDuiRect rcBmpPart(0, 0, iWidth, iHeight);
|
||
rcBmpPart.left = iWidth * iImageListIndex;
|
||
rcBmpPart.right = iWidth * (iImageListIndex + 1);
|
||
CDuiRect rcCorner(0, 0, 0, 0);
|
||
DrawImage(hDC, pImageInfo->hBitmap, rcImage, rcImage, rcBmpPart, rcCorner, \
|
||
pImageInfo->alphaChannel, 255);
|
||
}
|
||
|
||
cyLine = MAX(iHeight, cyLine);
|
||
pt.x += iWidth;
|
||
cyMinHeight = pt.y + iHeight;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
}
|
||
}
|
||
else pstrNextStart = NULL;
|
||
}
|
||
}
|
||
break;
|
||
case _T('n'): // Newline
|
||
{
|
||
pstrText++;
|
||
if( (uStyle & DT_SINGLELINE) != 0 ) break;
|
||
bLineEnd = true;
|
||
}
|
||
break;
|
||
case _T('p'): // Paragraph
|
||
{
|
||
pstrText++;
|
||
if( pt.x > rc.left ) bLineEnd = true;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
int cyLineExtra = (int)_tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
aPIndentArray.Add((LPVOID)cyLineExtra);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + cyLineExtra);
|
||
}
|
||
break;
|
||
case _T('r'): // Raw Text
|
||
{
|
||
pstrText++;
|
||
bInRaw = true;
|
||
}
|
||
break;
|
||
case _T('s'): // Selected text background color
|
||
{
|
||
pstrText++;
|
||
bInSelected = !bInSelected;
|
||
if( bDraw && bLineDraw ) {
|
||
if( bInSelected ) ::SetBkMode(hDC, OPAQUE);
|
||
else ::SetBkMode(hDC, TRANSPARENT);
|
||
}
|
||
}
|
||
break;
|
||
case _T('u'): // Underline text
|
||
{
|
||
pstrText++;
|
||
TFontInfo* pFontInfo = pManager->GetDefaultFontInfo();
|
||
if( aFontArray.GetSize() > 0 ) pFontInfo = (TFontInfo*)aFontArray.GetAt(aFontArray.GetSize() - 1);
|
||
if( pFontInfo->bUnderline == false ) {
|
||
HFONT hFont = pManager->GetFont(pFontInfo->sFontName, pFontInfo->iSize, pFontInfo->bBold, true, pFontInfo->bItalic);
|
||
if( hFont == NULL ) hFont = pManager->AddFont(pFontInfo->sFontName, pFontInfo->iSize, pFontInfo->bBold, true, pFontInfo->bItalic);
|
||
pFontInfo = pManager->GetFontInfo(hFont);
|
||
aFontArray.Add(pFontInfo);
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
}
|
||
}
|
||
break;
|
||
case _T('x'): // X Indent
|
||
{
|
||
pstrText++;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
int iWidth = (int) _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
pt.x += iWidth;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
}
|
||
break;
|
||
case _T('y'): // Y Indent
|
||
{
|
||
pstrText++;
|
||
while( *pstrText > _T('\0') && *pstrText <= _T(' ') ) pstrText = ::CharNext(pstrText);
|
||
cyLine = (int) _tcstol(pstrText, const_cast<LPTSTR*>(&pstrText), 10);
|
||
}
|
||
break;
|
||
}
|
||
if( pstrNextStart != NULL ) pstrText = pstrNextStart;
|
||
else {
|
||
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('}') ) pstrText = ::CharNext(pstrText);
|
||
pstrText = ::CharNext(pstrText);
|
||
}
|
||
}
|
||
else if( !bInRaw && ( *pstrText == _T('<') || *pstrText == _T('{') ) && pstrText[1] == _T('/') )
|
||
{
|
||
pstrText++;
|
||
pstrText++;
|
||
switch( *pstrText )
|
||
{
|
||
case _T('c'):
|
||
{
|
||
pstrText++;
|
||
aColorArray.Remove(aColorArray.GetSize() - 1);
|
||
DWORD clrColor = dwTextColor;
|
||
if( aColorArray.GetSize() > 0 ) clrColor = (int)aColorArray.GetAt(aColorArray.GetSize() - 1);
|
||
::SetTextColor(hDC, RGB(GetBValue(clrColor), GetGValue(clrColor), GetRValue(clrColor)));
|
||
}
|
||
break;
|
||
case _T('p'):
|
||
pstrText++;
|
||
if( pt.x > rc.left ) bLineEnd = true;
|
||
aPIndentArray.Remove(aPIndentArray.GetSize() - 1);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
break;
|
||
case _T('s'):
|
||
{
|
||
pstrText++;
|
||
bInSelected = !bInSelected;
|
||
if( bDraw && bLineDraw ) {
|
||
if( bInSelected ) ::SetBkMode(hDC, OPAQUE);
|
||
else ::SetBkMode(hDC, TRANSPARENT);
|
||
}
|
||
}
|
||
break;
|
||
case _T('a'):
|
||
{
|
||
if( iLinkIndex < nLinkRects ) {
|
||
if( !bLineDraw ) ::SetRect(&prcLinks[iLinkIndex], ptLinkStart.x, ptLinkStart.y, MIN(pt.x, rc.right), pt.y + pTm->tmHeight + pTm->tmExternalLeading);
|
||
iLinkIndex++;
|
||
}
|
||
aColorArray.Remove(aColorArray.GetSize() - 1);
|
||
DWORD clrColor = dwTextColor;
|
||
if( aColorArray.GetSize() > 0 ) clrColor = (int)aColorArray.GetAt(aColorArray.GetSize() - 1);
|
||
::SetTextColor(hDC, RGB(GetBValue(clrColor), GetGValue(clrColor), GetRValue(clrColor)));
|
||
bInLink = false;
|
||
}
|
||
case _T('b'):
|
||
case _T('f'):
|
||
case _T('i'):
|
||
case _T('u'):
|
||
{
|
||
pstrText++;
|
||
aFontArray.Remove(aFontArray.GetSize() - 1);
|
||
TFontInfo* pFontInfo = (TFontInfo*)aFontArray.GetAt(aFontArray.GetSize() - 1);
|
||
if( pFontInfo == NULL ) pFontInfo = pManager->GetDefaultFontInfo();
|
||
if( pTm->tmItalic && pFontInfo->bItalic == false ) {
|
||
ABC abc;
|
||
::GetCharABCWidths(hDC, _T(' '), _T(' '), &abc);
|
||
pt.x += abc.abcC / 2; // 简单修正一下斜体混排的问题, 正确做法应该是http://support.microsoft.com/kb/244798/en-us
|
||
}
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
cyLine = MAX(cyLine, pTm->tmHeight + pTm->tmExternalLeading + (int)aPIndentArray.GetAt(aPIndentArray.GetSize() - 1));
|
||
}
|
||
break;
|
||
}
|
||
while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('}') ) pstrText = ::CharNext(pstrText);
|
||
pstrText = ::CharNext(pstrText);
|
||
}
|
||
else if( !bInRaw && *pstrText == _T('<') && pstrText[2] == _T('>') && (pstrText[1] == _T('{') || pstrText[1] == _T('}')) )
|
||
{
|
||
SIZE szSpace = { 0 };
|
||
::GetTextExtentPoint32(hDC, &pstrText[1], 1, &szSpace);
|
||
if( bDraw && bLineDraw ) ::TextOut(hDC, pt.x, pt.y + cyLineHeight - pTm->tmHeight - pTm->tmExternalLeading, &pstrText[1], 1);
|
||
pt.x += szSpace.cx;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
pstrText++;pstrText++;pstrText++;
|
||
}
|
||
else if( !bInRaw && *pstrText == _T('{') && pstrText[2] == _T('}') && (pstrText[1] == _T('<') || pstrText[1] == _T('>')) )
|
||
{
|
||
SIZE szSpace = { 0 };
|
||
::GetTextExtentPoint32(hDC, &pstrText[1], 1, &szSpace);
|
||
if( bDraw && bLineDraw ) ::TextOut(hDC, pt.x, pt.y + cyLineHeight - pTm->tmHeight - pTm->tmExternalLeading, &pstrText[1], 1);
|
||
pt.x += szSpace.cx;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
pstrText++;pstrText++;pstrText++;
|
||
}
|
||
else if( !bInRaw && *pstrText == _T(' ') )
|
||
{
|
||
SIZE szSpace = { 0 };
|
||
::GetTextExtentPoint32(hDC, _T(" "), 1, &szSpace);
|
||
// Still need to paint the space because the font might have
|
||
// underline formatting.
|
||
if( bDraw && bLineDraw ) ::TextOut(hDC, pt.x, pt.y + cyLineHeight - pTm->tmHeight - pTm->tmExternalLeading, _T(" "), 1);
|
||
pt.x += szSpace.cx;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
pstrText++;
|
||
}
|
||
else
|
||
{
|
||
POINT ptPos = pt;
|
||
int cchChars = 0;
|
||
int cchSize = 0;
|
||
int cchLastGoodWord = 0;
|
||
int cchLastGoodSize = 0;
|
||
LPCTSTR p = pstrText;
|
||
LPCTSTR pstrNext;
|
||
SIZE szText = { 0 };
|
||
if( !bInRaw && *p == _T('<') || *p == _T('{') ) p++, cchChars++, cchSize++;
|
||
while( *p != _T('\0') && *p != _T('\n') ) {
|
||
// This part makes sure that we're word-wrapping if needed or providing support
|
||
// for DT_END_ELLIPSIS. Unfortunately the GetTextExtentPoint32() call is pretty
|
||
// slow when repeated so often.
|
||
// TODO: Rewrite and use GetTextExtentExPoint() instead!
|
||
if( bInRaw ) {
|
||
if( ( *p == _T('<') || *p == _T('{') ) && p[1] == _T('/')
|
||
&& p[2] == _T('r') && ( p[3] == _T('>') || p[3] == _T('}') ) ) {
|
||
p += 4;
|
||
bInRaw = false;
|
||
break;
|
||
}
|
||
}
|
||
else {
|
||
if( *p == _T('<') || *p == _T('{') ) break;
|
||
}
|
||
pstrNext = ::CharNext(p);
|
||
cchChars++;
|
||
cchSize += (int)(pstrNext - p);
|
||
szText.cx = cchChars * pTm->tmMaxCharWidth;
|
||
if( pt.x + szText.cx >= rc.right ) {
|
||
::GetTextExtentPoint32(hDC, pstrText, cchSize, &szText);
|
||
}
|
||
if( pt.x + szText.cx > rc.right ) {
|
||
if( pt.x + szText.cx > rc.right && pt.x != rc.left) {
|
||
cchChars--;
|
||
cchSize -= (int)(pstrNext - p);
|
||
}
|
||
if( (uStyle & DT_WORDBREAK) != 0 && cchLastGoodWord > 0 ) {
|
||
cchChars = cchLastGoodWord;
|
||
cchSize = cchLastGoodSize;
|
||
}
|
||
if( (uStyle & DT_END_ELLIPSIS) != 0 && cchChars > 0 ) {
|
||
cchChars -= 1;
|
||
LPCTSTR pstrPrev = ::CharPrev(pstrText, p);
|
||
if( cchChars > 0 ) {
|
||
cchChars -= 1;
|
||
pstrPrev = ::CharPrev(pstrText, pstrPrev);
|
||
cchSize -= (int)(p - pstrPrev);
|
||
}
|
||
else
|
||
cchSize -= (int)(p - pstrPrev);
|
||
pt.x = rc.right;
|
||
}
|
||
bLineEnd = true;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
break;
|
||
}
|
||
if (!( ( p[0] >= _T('a') && p[0] <= _T('z') ) || ( p[0] >= _T('A') && p[0] <= _T('Z') ) )) {
|
||
cchLastGoodWord = cchChars;
|
||
cchLastGoodSize = cchSize;
|
||
}
|
||
if( *p == _T(' ') ) {
|
||
cchLastGoodWord = cchChars;
|
||
cchLastGoodSize = cchSize;
|
||
}
|
||
p = ::CharNext(p);
|
||
}
|
||
|
||
::GetTextExtentPoint32(hDC, pstrText, cchSize, &szText);
|
||
if( bDraw && bLineDraw ) {
|
||
if( (uStyle & DT_SINGLELINE) == 0 && (uStyle & DT_CENTER) != 0 ) {
|
||
ptPos.x += (rc.right - rc.left - szText.cx)/2;
|
||
}
|
||
else if( (uStyle & DT_SINGLELINE) == 0 && (uStyle & DT_RIGHT) != 0) {
|
||
ptPos.x += (rc.right - rc.left - szText.cx);
|
||
}
|
||
::TextOut(hDC, ptPos.x, ptPos.y + cyLineHeight - pTm->tmHeight - pTm->tmExternalLeading, pstrText, cchSize);
|
||
if( pt.x >= rc.right && (uStyle & DT_END_ELLIPSIS) != 0 )
|
||
::TextOut(hDC, ptPos.x + szText.cx, ptPos.y, _T("..."), 3);
|
||
}
|
||
pt.x += szText.cx;
|
||
cxMaxWidth = MAX(cxMaxWidth, pt.x);
|
||
pstrText += cchSize;
|
||
}
|
||
|
||
if( pt.x >= rc.right || *pstrText == _T('\n') || *pstrText == _T('\0') ) bLineEnd = true;
|
||
if( bDraw && bLineEnd ) {
|
||
if( !bLineDraw ) {
|
||
aFontArray.Resize(aLineFontArray.GetSize());
|
||
::CopyMemory(aFontArray.GetData(), aLineFontArray.GetData(), aLineFontArray.GetSize() * sizeof(LPVOID));
|
||
aColorArray.Resize(aLineColorArray.GetSize());
|
||
::CopyMemory(aColorArray.GetData(), aLineColorArray.GetData(), aLineColorArray.GetSize() * sizeof(LPVOID));
|
||
aPIndentArray.Resize(aLinePIndentArray.GetSize());
|
||
::CopyMemory(aPIndentArray.GetData(), aLinePIndentArray.GetData(), aLinePIndentArray.GetSize() * sizeof(LPVOID));
|
||
|
||
cyLineHeight = cyLine;
|
||
pstrText = pstrLineBegin;
|
||
bInRaw = bLineInRaw;
|
||
bInSelected = bLineInSelected;
|
||
|
||
DWORD clrColor = dwTextColor;
|
||
if( aColorArray.GetSize() > 0 ) clrColor = (int)aColorArray.GetAt(aColorArray.GetSize() - 1);
|
||
::SetTextColor(hDC, RGB(GetBValue(clrColor), GetGValue(clrColor), GetRValue(clrColor)));
|
||
TFontInfo* pFontInfo = (TFontInfo*)aFontArray.GetAt(aFontArray.GetSize() - 1);
|
||
if( pFontInfo == NULL ) pFontInfo = pManager->GetDefaultFontInfo();
|
||
pTm = &pFontInfo->tm;
|
||
::SelectObject(hDC, pFontInfo->hFont);
|
||
if( bInSelected ) ::SetBkMode(hDC, OPAQUE);
|
||
}
|
||
else {
|
||
aLineFontArray.Resize(aFontArray.GetSize());
|
||
::CopyMemory(aLineFontArray.GetData(), aFontArray.GetData(), aFontArray.GetSize() * sizeof(LPVOID));
|
||
aLineColorArray.Resize(aColorArray.GetSize());
|
||
::CopyMemory(aLineColorArray.GetData(), aColorArray.GetData(), aColorArray.GetSize() * sizeof(LPVOID));
|
||
aLinePIndentArray.Resize(aPIndentArray.GetSize());
|
||
::CopyMemory(aLinePIndentArray.GetData(), aPIndentArray.GetData(), aPIndentArray.GetSize() * sizeof(LPVOID));
|
||
pstrLineBegin = pstrText;
|
||
bLineInSelected = bInSelected;
|
||
bLineInRaw = bInRaw;
|
||
}
|
||
}
|
||
|
||
ASSERT(iLinkIndex<=nLinkRects);
|
||
}
|
||
|
||
nLinkRects = iLinkIndex;
|
||
|
||
// Return size of text when requested
|
||
if( (uStyle & DT_CALCRECT) != 0 ) {
|
||
rc.bottom = MAX(cyMinHeight, pt.y + cyLine);
|
||
rc.right = MIN(rc.right, cxMaxWidth);
|
||
}
|
||
|
||
if( bDraw ) ::SelectClipRgn(hDC, hOldRgn);
|
||
::DeleteObject(hOldRgn);
|
||
::DeleteObject(hRgn);
|
||
|
||
::SelectObject(hDC, hOldFont);
|
||
}
|
||
|
||
HBITMAP CRenderEngine::GenerateBitmap(CPaintManagerUI* pManager, CControlUI* pControl, RECT rc)
|
||
{
|
||
int cx = rc.right - rc.left;
|
||
int cy = rc.bottom - rc.top;
|
||
|
||
HDC hPaintDC = ::CreateCompatibleDC(pManager->GetPaintDC());
|
||
HBITMAP hPaintBitmap = ::CreateCompatibleBitmap(pManager->GetPaintDC(), rc.right, rc.bottom);
|
||
ASSERT(hPaintDC);
|
||
ASSERT(hPaintBitmap);
|
||
HBITMAP hOldPaintBitmap = (HBITMAP) ::SelectObject(hPaintDC, hPaintBitmap);
|
||
pControl->DoPaint(hPaintDC, rc);
|
||
|
||
BITMAPINFO bmi = { 0 };
|
||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
bmi.bmiHeader.biWidth = cx;
|
||
bmi.bmiHeader.biHeight = cy;
|
||
bmi.bmiHeader.biPlanes = 1;
|
||
bmi.bmiHeader.biBitCount = 32;
|
||
bmi.bmiHeader.biCompression = BI_RGB;
|
||
bmi.bmiHeader.biSizeImage = cx * cy * sizeof(DWORD);
|
||
LPDWORD pDest = NULL;
|
||
HDC hCloneDC = ::CreateCompatibleDC(pManager->GetPaintDC());
|
||
HBITMAP hBitmap = ::CreateDIBSection(pManager->GetPaintDC(), &bmi, DIB_RGB_COLORS, (LPVOID*) &pDest, NULL, 0);
|
||
ASSERT(hCloneDC);
|
||
ASSERT(hBitmap);
|
||
if( hBitmap != NULL )
|
||
{
|
||
HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hCloneDC, hBitmap);
|
||
::BitBlt(hCloneDC, 0, 0, cx, cy, hPaintDC, rc.left, rc.top, SRCCOPY);
|
||
::SelectObject(hCloneDC, hOldBitmap);
|
||
::DeleteDC(hCloneDC);
|
||
::GdiFlush();
|
||
}
|
||
|
||
// Cleanup
|
||
::SelectObject(hPaintDC, hOldPaintBitmap);
|
||
::DeleteObject(hPaintBitmap);
|
||
::DeleteDC(hPaintDC);
|
||
|
||
return hBitmap;
|
||
}
|
||
|
||
SIZE CRenderEngine::GetTextSize( HDC hDC, CPaintManagerUI* pManager , LPCTSTR pstrText, int iFont, UINT uStyle )
|
||
{
|
||
SIZE size = {0,0};
|
||
ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);
|
||
if( pstrText == NULL || pManager == NULL ) return size;
|
||
::SetBkMode(hDC, TRANSPARENT);
|
||
HFONT hOldFont = (HFONT)::SelectObject(hDC, pManager->GetFont(iFont));
|
||
GetTextExtentPoint32(hDC, pstrText, _tcslen(pstrText) , &size);
|
||
::SelectObject(hDC, hOldFont);
|
||
return size;
|
||
}
|
||
|
||
void CRenderEngine::CheckAlphaColor(DWORD& dwColor)
|
||
{
|
||
//RestoreAlphaColor认为0x00000000是真正的透明,其它都是GDI绘制导致的
|
||
//所以在GDI绘制中不能用0xFF000000这个颜色值,现在处理是让它变成RGB(0,0,1)
|
||
//RGB(0,0,1)与RGB(0,0,0)很难分出来
|
||
if((0x00FFFFFF & dwColor) == 0)
|
||
{
|
||
dwColor += 1;
|
||
}
|
||
}
|
||
|
||
void CRenderEngine::ClearAlphaPixel(LPBYTE pBits, int bitsWidth, PRECT rc)
|
||
{
|
||
if(!pBits)
|
||
return;
|
||
|
||
for(int i = rc->top; i < rc->bottom; ++i)
|
||
{
|
||
for(int j = rc->left; j < rc->right; ++j)
|
||
{
|
||
int x = (i*bitsWidth + j) * 4;
|
||
*((unsigned int*)&pBits[x]) = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CRenderEngine::RestoreAlphaColor(LPBYTE pBits, int bitsWidth, PRECT rc)
|
||
{
|
||
for(int i = rc->top; i < rc->bottom; ++i)
|
||
{
|
||
for(int j = rc->left; j < rc->right; ++j)
|
||
{
|
||
int x = (i*bitsWidth + j) * 4;
|
||
if((pBits[x + 3] == 0)&& (pBits[x + 0] != 0 || pBits[x + 1] != 0|| pBits[x + 2] != 0))
|
||
pBits[x + 3] = 255;
|
||
}
|
||
}
|
||
}
|
||
} // namespace DuiLib
|