Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / MFC

XHtmlTree - Tree control with support for HTML, XML, Smart Checkboxes, and Drag & Drop

Rate me:
Please Sign up or sign in to vote.
4.97/5 (164 votes)
1 Jan 2008CPOL22 min read 454.4K   10.1K   372  
XHtmlTree is an MFC control based on CTreeCtrl, with support for HTML text, web links, APP: links, XML load/save, Smart Checkboxes, and Drag & Drop.
#include "stdafx.h"
#include "PPDrawManager.h"

#pragma warning(push, 3)

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/*
	DIBs use RGBQUAD format:
		0xbb 0xgg 0xrr 0x00
*/
#ifndef CLR_TO_RGBQUAD
#define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPPDrawManager::CPPDrawManager()
{

}

CPPDrawManager::~CPPDrawManager()
{

}

void CPPDrawManager::GetSizeOfIcon(HICON hIcon, LPSIZE pSize) const
{
	pSize->cx = 0;
	pSize->cy = 0;
	if (hIcon != NULL)
	{
		ICONINFO ii;
		// Gets icon dimension
		::ZeroMemory(&ii, sizeof(ICONINFO));
		if (::GetIconInfo(hIcon, &ii))
		{
			pSize->cx = (DWORD)(ii.xHotspot * 2);
			pSize->cy = (DWORD)(ii.yHotspot * 2);
			//release icon mask bitmaps
			if(ii.hbmMask)
				::DeleteObject(ii.hbmMask);
			if(ii.hbmColor)
				::DeleteObject(ii.hbmColor);
		} //if
	} //if
} //End GetSizeOfIcon

void CPPDrawManager::GetSizeOfBitmap(HBITMAP hBitmap, LPSIZE pSize) const
{
	pSize->cx = 0;
	pSize->cy = 0;
	if (hBitmap != NULL)
	{
		BITMAP	csBitmapSize;
		// Get bitmap size
		int nRetValue = ::GetObject(hBitmap, sizeof(csBitmapSize), &csBitmapSize);
		if (nRetValue)
		{
			pSize->cx = (DWORD)csBitmapSize.bmWidth;
			pSize->cy = (DWORD)csBitmapSize.bmHeight;
		} //if
	} //if
} //End GetSizeOfBitmap

void CPPDrawManager::AlphaBitBlt(HDC hDestDC, int nDestX, int nDestY, DWORD dwWidth, DWORD dwHeight, HDC hSrcDC, int nSrcX, int nSrcY, int percent /* = 100 */)
{
	_ASSERT ((NULL != hDestDC) || (NULL != hSrcDC));

	if (percent >= 100)
	{
		::BitBlt(hDestDC, nDestX, nDestY, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		return;
	} //if

	HDC hTempDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hTempDC)
		return;
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	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))
	{
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hSrcDib);
		::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		::SelectObject (hTempDC, hOldTempBmp);
		
		//Creates Destination DIB
		LPBITMAPINFO lpbiDest;
		// Fill in the BITMAPINFOHEADER
		lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
		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 (
			hDestDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
			NULL, NULL);
		
		if ((NULL != hDestDib) && (NULL != pDestBits))
		{
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDestDC, nDestX, nDestY, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			double src_darken = (double)percent / 100.0;
			double dest_darken = 1.0 - src_darken;
			
			for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
			{
				*pDestBits = PixelAlpha(*pSrcBits, src_darken, *pDestBits, dest_darken);
			} //for
			
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hDestDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			delete [] lpbiDest;
			::DeleteObject(hDestDib);
		} //if
		delete [] lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if

	::DeleteDC(hTempDC);
} //End AlphaBitBlt

void CPPDrawManager::AlphaChannelBitBlt(HDC hDestDC, int nDestX, int nDestY, DWORD dwWidth, DWORD dwHeight, HDC hSrcDC, int nSrcX, int nSrcY)
{
	_ASSERT ((NULL != hDestDC) || (NULL != hSrcDC));

	HDC hTempDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hTempDC)
		return;
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	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))
	{
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hSrcDib);
		::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		::SelectObject (hTempDC, hOldTempBmp);
		
		//Creates Destination DIB
		LPBITMAPINFO lpbiDest;
		// Fill in the BITMAPINFOHEADER
		lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
		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 (
			hDestDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
			NULL, NULL);
		
		if ((NULL != hDestDib) && (NULL != pDestBits))
		{
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDestDC, nDestX, nDestY, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			double src_darken;
			BYTE nAlpha;
			
			for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
			{
				nAlpha = LOBYTE(*pSrcBits >> 24);
				src_darken = (double)nAlpha / 255.0;
				*pDestBits = PixelAlpha(*pSrcBits, src_darken, *pDestBits, 1.0 - src_darken);
			} //for
			
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hDestDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			delete [] lpbiDest;
			::DeleteObject(hDestDib);
		} //if
		delete [] lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if

	::DeleteDC(hTempDC);
} //End of AlphaChannelBitBlt

HBITMAP CPPDrawManager::CreateImageEffect(HBITMAP hBitmap, DWORD dwWidth, DWORD dwHeight, DWORD dwEffect, BOOL bUseMask /* = TRUE */, COLORREF clrMask /* = RGB(255, 0, 255) */, COLORREF clrMono /* = RGB(255, 255, 255) */)
{
	HBITMAP hOldSrcBmp = NULL;
	HBITMAP hOldResBmp = NULL;  
	HDC hMainDC = NULL;
	HDC hSrcDC = NULL;
	HDC hResDC = NULL;
	
	hMainDC = ::GetDC(NULL);
	hSrcDC = ::CreateCompatibleDC(hMainDC);
	hResDC = ::CreateCompatibleDC(hMainDC);

	hOldSrcBmp = (HBITMAP)::SelectObject(hSrcDC, hBitmap);

	LPBITMAPINFO lpbi;

	// Fill in the BITMAPINFOHEADER
	lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbi->bmiHeader.biWidth = dwWidth;
	lpbi->bmiHeader.biHeight = dwHeight;
	lpbi->bmiHeader.biPlanes = 1;
	lpbi->bmiHeader.biBitCount = 32;
	lpbi->bmiHeader.biCompression = BI_RGB;
	lpbi->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbi->bmiHeader.biXPelsPerMeter = 0;
	lpbi->bmiHeader.biYPelsPerMeter = 0;
	lpbi->bmiHeader.biClrUsed = 0;
	lpbi->bmiHeader.biClrImportant = 0;

	COLORREF* pBits = NULL;
	HBITMAP hDibBmp = CreateDIBSection (
		hSrcDC, lpbi, DIB_RGB_COLORS, (void **)&pBits,
		NULL, NULL);

	if (hDibBmp == NULL || pBits == NULL)
	{
		delete [] lpbi;
		_ASSERT (FALSE);
		return NULL;
	} //if

	hOldResBmp = (HBITMAP)::SelectObject (hResDC, hDibBmp);
	::BitBlt (hResDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, SRCCOPY);

	clrMask = CLR_TO_RGBQUAD(clrMask);
	clrMono = CLR_TO_RGBQUAD(clrMono);

	DWORD dwAlpha;
	for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, *pBits++)
	{
		COLORREF color = (COLORREF)*pBits;
		//ENG: Extract an original alpha value
		dwAlpha = color & 0xFF000000;
		if (dwAlpha != 0) 
			m_bIsAlpha = TRUE;
		if (bUseMask && (color == clrMask))
		{
			//This is transparent area
			color = RGB(0, 0, 0);
		}
		else 
		{
			//ENG: Color conversion
			if (dwEffect & IMAGE_EFFECT_GRAYEN) color = GrayMirrorColor(color);
			if (dwEffect & IMAGE_EFFECT_DARKEN) color = DarkenColor(color, 0.75);
			if (dwEffect & IMAGE_EFFECT_LIGHTEN) color = LightenColor(color, 0.25);
			if (dwEffect & IMAGE_EFFECT_MONOCHROME) color = clrMono;
		} //if
		if (dwEffect & IMAGE_EFFECT_INVERT) color = InvertColor(color);
		//ENG: Merges a color with an original alpha value
		*pBits = (color | dwAlpha);
	} //for

	::SelectObject(hSrcDC, hOldSrcBmp);
	::SelectObject(hResDC, hOldResBmp);
	::DeleteDC(hSrcDC);
	::DeleteDC(hResDC);
	::ReleaseDC(NULL, hMainDC);
	
	delete [] lpbi;

	return hDibBmp;
} //End CreateImageEffect

//----------------------------------------------------------
// CPPDrawManager::GrayMirrorColor()
//	Graying color in RGBQUAD format
//----------------------------------------------------------
// Parameter:
//	clrColor	- RGBQUAD value from DIB
// Return value:
//	A grayed color in the RGBQUAD format
//----------------------------------------------------------
COLORREF CPPDrawManager::GrayMirrorColor(COLORREF clrColor)
{
	BYTE nGrayColor = (BYTE)((GetBValue(clrColor) * 0.299) + (GetGValue(clrColor) * 0.587) + (GetRValue(clrColor) * 0.114));
	
	return RGB(nGrayColor, nGrayColor, nGrayColor);
} //End of GrayMirrorColor

COLORREF CPPDrawManager::GrayColor(COLORREF clrColor)
{
	BYTE nGrayColor = (BYTE)((GetRValue(clrColor) * 0.299) + (GetGValue(clrColor) * 0.587) + (GetBValue(clrColor) * 0.114));
	
	return RGB(nGrayColor, nGrayColor, nGrayColor);
} //End GrayColor

COLORREF CPPDrawManager::InvertColor(COLORREF clrColor)
{
	return RGB(255 - GetRValue(clrColor), 255 - GetGValue(clrColor), 255 - GetBValue(clrColor));
} //End InvertColor

COLORREF CPPDrawManager::DarkenColor(COLORREF clrColor, double darken)
{
	if (darken >= 0.0 && darken < 1.0)
	{
		BYTE color_r, color_g, color_b;
		color_r = (BYTE)(GetRValue(clrColor) * darken);
		color_g = (BYTE)(GetGValue(clrColor) * darken);
		color_b = (BYTE)(GetBValue(clrColor) * darken);
		clrColor = RGB(color_r, color_g, color_b);
	} //if
	
	return clrColor;
} //End DarkenColor

COLORREF CPPDrawManager::LightenColor(COLORREF clrColor, double lighten)
{
	if (lighten > 0.0 && lighten <= 1.0)
	{
		BYTE color_r, color_g, color_b;
		
		lighten += 1.0;
		color_r = (BYTE)min((DWORD)GetRValue(clrColor) * lighten, 255.0);
		color_g = (BYTE)min((DWORD)GetGValue(clrColor) * lighten, 255.0);
		color_b = (BYTE)min((DWORD)GetBValue(clrColor) * lighten, 255.0);
		clrColor = RGB(color_r, color_g, color_b);
/*		
		lighten *= 255
		color_r = (BYTE)max(0, min(255, (int)((color_r - 128) * 2.0 + 128 + lighten)));
		color_g = (BYTE)max(0, min(255, (int)((color_g - 128) * 2.0 + 128 + lighten)));
		color_b = (BYTE)max(0, min(255, (int)((color_b - 128) * 2.0 + 128 + lighten)));
		clrColor = RGB(color_r, color_g, color_b);
*/
	} //if
	
	return clrColor;
} //End LightenColor

COLORREF CPPDrawManager::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);
	
} //End PixelAlpha

HICON CPPDrawManager::StretchIcon(HICON hIcon, DWORD dwWidth, DWORD dwHeight)
{
	HICON hStretchedIcon = NULL;
	HDC   hMainDC = NULL;
	HDC   hSrcDC = NULL;
	HDC   hDestDC = NULL;
	BITMAP bmp;
	HBITMAP hOldSrcBitmap = NULL;
	HBITMAP hOldDestBitmap = NULL;
	ICONINFO csOriginal, csStretched;
	
	memset(&csStretched, 0, sizeof(csStretched));	// +++hd

	if (!::GetIconInfo(hIcon, &csOriginal))
		return FALSE;
	
	hMainDC = ::GetDC(NULL);
	hSrcDC = ::CreateCompatibleDC(hMainDC);
	hDestDC = ::CreateCompatibleDC(hMainDC);
	
	if ((NULL == hMainDC) || (NULL == hSrcDC) || (NULL == hDestDC))
		return NULL;
	
	if (::GetObject(csOriginal.hbmColor, sizeof(BITMAP), &bmp))
	{
		DWORD	dwWidthOrg = csOriginal.xHotspot * 2;
		DWORD	dwHeightOrg = csOriginal.yHotspot * 2;
		
		csStretched.hbmColor = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
		if (NULL != csStretched.hbmColor)
		{
			hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, csOriginal.hbmColor);
			hOldDestBitmap = (HBITMAP)::SelectObject(hDestDC, csStretched.hbmColor);
			::StretchBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, dwWidthOrg, dwHeightOrg, SRCCOPY);
			if (::GetObject(csOriginal.hbmMask, sizeof(BITMAP), &bmp))
			{
				csStretched.hbmMask = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
				if (NULL != csStretched.hbmMask)
				{
					::SelectObject(hSrcDC, csOriginal.hbmMask);
					::SelectObject(hDestDC, csStretched.hbmMask);
					::StretchBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, dwWidthOrg, dwHeightOrg, SRCCOPY);
				} //if
			} //if
			::SelectObject(hSrcDC, hOldSrcBitmap);
			::SelectObject(hDestDC, hOldDestBitmap);
			csStretched.fIcon = TRUE;
			hStretchedIcon = ::CreateIconIndirect(&csStretched);
			::DeleteObject(csStretched.hbmColor);
			::DeleteObject(csStretched.hbmMask);
		} //if
	} //if
	
	::DeleteObject(csOriginal.hbmColor);
	::DeleteObject(csOriginal.hbmMask);
	::DeleteDC(hSrcDC);
	::DeleteDC(hDestDC);
	::ReleaseDC(NULL, hMainDC);
	
	return hStretchedIcon;
} //End StretchIcon

void CPPDrawManager::FillGradient (HDC hDC, LPCRECT lpRect, 
								COLORREF colorStart, COLORREF colorFinish, 
								BOOL bHorz/* = TRUE*/)
{
    // this will make 2^6 = 64 fountain steps
    int nShift = 6;
    int nSteps = 1 << nShift;

	RECT r2;
	r2.top = lpRect->top;
	r2.left = lpRect->left;
	r2.right = lpRect->right;
	r2.bottom = lpRect->bottom;

	int nHeight = lpRect->bottom - lpRect->top;
	int nWidth = lpRect->right - lpRect->left;

	for (int i = 0; i < nSteps; i++)
    {
        // do a little alpha blending
        BYTE bR = (BYTE) ((GetRValue(colorStart) * (nSteps - i) +
                   GetRValue(colorFinish) * i) >> nShift);
        BYTE bG = (BYTE) ((GetGValue(colorStart) * (nSteps - i) +
                   GetGValue(colorFinish) * i) >> nShift);
        BYTE bB = (BYTE) ((GetBValue(colorStart) * (nSteps - i) +
                   GetBValue(colorFinish) * i) >> nShift);

		HBRUSH hBrush = ::CreateSolidBrush(RGB(bR, bG, bB));
		
        // then paint with the resulting color

        if (!bHorz)
        {
            r2.top = lpRect->top + ((i * nHeight) >> nShift);
            r2.bottom = lpRect->top + (((i + 1) * nHeight) >> nShift);
            if ((r2.bottom - r2.top) > 0)
                ::FillRect(hDC, &r2, hBrush);
        }
        else
        {
            r2.left = lpRect->left + ((i * nWidth) >> nShift);
            r2.right = lpRect->left + (((i + 1) * nWidth) >> nShift);
            if ((r2.right - r2.left) > 0)
                ::FillRect(hDC, &r2, hBrush);
        } //if
		
		if (NULL != hBrush)
		{
			::DeleteObject(hBrush);
			hBrush = NULL;
		} //if
    } //for
} //End FillGradient

#ifdef USE_SHADE
void CPPDrawManager::SetShade(LPCRECT lpRect, UINT shadeID /* = 0 */, BYTE granularity /* = 8 */, 
						  BYTE coloring /* = 0 */, COLORREF hicr /* = 0 */, COLORREF midcr /* = 0 */, COLORREF locr /* = 0 */)
{
	long	sXSize,sYSize,bytes,j,i,k,h;
	BYTE	*iDst ,*posDst;
	
	sYSize = lpRect->bottom - lpRect->top; 
	sXSize = lpRect->right - lpRect->left; 

	m_dNormal.Create(sXSize,sYSize,8);					//create the default bitmap

	long r,g,b;											//build the shaded palette
	for(i = 0; i < 129; i++)
	{
		r=((128-i)*GetRValue(locr)+i*GetRValue(midcr))/128;
		g=((128-i)*GetGValue(locr)+i*GetGValue(midcr))/128;
		b=((128-i)*GetBValue(locr)+i*GetBValue(midcr))/128;
		m_dNormal.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b);
	} //for
	for(i=1;i<129;i++){
		r=((128-i)*GetRValue(midcr)+i*GetRValue(hicr))/128;
		g=((128-i)*GetGValue(midcr)+i*GetGValue(hicr))/128;
		b=((128-i)*GetBValue(midcr)+i*GetBValue(hicr))/128;
		m_dNormal.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b);
	} //for

	m_dNormal.BlendPalette(hicr,coloring);	//color the palette

	bytes = m_dNormal.GetLineWidth();
	iDst = m_dNormal.GetBits();
	posDst =iDst;
	long a,x,y,d,xs,idxmax,idxmin;

	int grainx2 = RAND_MAX/(max(1,2*granularity));
	idxmax=255-granularity;
	idxmin=granularity;

	switch (shadeID)
	{
//----------------------------------------------------
	case EFFECT_METAL:
		m_dNormal.Clear();
		// create the strokes
		k=40;	//stroke granularity
		for(a=0;a<200;a++){
			x=rand()/(RAND_MAX/sXSize); //stroke postion
			y=rand()/(RAND_MAX/sYSize);	//stroke position
			xs=rand()/(RAND_MAX/min(sXSize,sYSize))/2; //stroke lenght
			d=rand()/(RAND_MAX/k);	//stroke color
			for(i=0;i<xs;i++){
				if (((x-i)>0)&&((y+i)<sYSize))
					m_dNormal.SetPixelIndex(x-i,y+i,(BYTE)d);
				if (((x+i)<sXSize)&&((y-i)>0))
					m_dNormal.SetPixelIndex(sXSize-x+i,y-i,(BYTE)d);
			} //for
		} //for
		//blend strokes with SHS_DIAGONAL
		posDst =iDst;
		a=(idxmax-idxmin-k)/2;
		for(i = 0; i < sYSize; i++) {
			for(j = 0; j < sXSize; j++) {
				d=posDst[j]+((a*i)/sYSize+(a*(sXSize-j))/sXSize);
				posDst[j]=(BYTE)d;
				posDst[j]+=rand()/grainx2;
			} //for
			posDst+=bytes;
		} //for

		break;
//----------------------------------------------------
	case EFFECT_HARDBUMP:	// 
		//set horizontal bump
		for(i = 0; i < sYSize; i++) {
			k=(255*i/sYSize)-127;
			k=(k*(k*k)/128)/128;
			k=(k*(128-granularity*2))/128+128;
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		//set vertical bump
		d=min(16,sXSize/6);	//max edge=16
		a=sYSize*sYSize/4;
		posDst =iDst;
		for(i = 0; i < sYSize; i++) {
			y=i-sYSize/2;
			for(j = 0; j < sXSize; j++) {
				x=j-sXSize/2;
				xs=sXSize/2-d+(y*y*d)/a;
				if (x>xs) posDst[j]=(BYTE)idxmin+(BYTE)(((sXSize-j)*128)/d);
				if ((x+xs)<0) posDst[j]=(BYTE)idxmax-(BYTE)((j*128)/d);
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_SOFTBUMP: //
		for(i = 0; i < sYSize; i++) {
			h=(255*i/sYSize)-127;
			for(j = 0; j < sXSize; j++) {
				k=(255*(sXSize-j)/sXSize)-127;
				k=(h*(h*h)/128)/128+(k*(k*k)/128)/128;
				k=k*(128-granularity)/128+128;
				if (k<idxmin) k=idxmin;
				if (k>idxmax) k=idxmax;
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_VBUMP: // 
		for(j = 0; j < sXSize; j++) {
			k=(255*(sXSize-j)/sXSize)-127;
			k=(k*(k*k)/128)/128;
			k=(k*(128-granularity))/128+128;
			for(i = 0; i < sYSize; i++) {
				posDst[j+i*bytes]=(BYTE)k;
				posDst[j+i*bytes]+=rand()/grainx2-granularity;
			} //for
		} //for
		break;
//----------------------------------------------------
	case EFFECT_HBUMP: //
		for(i = 0; i < sYSize; i++) {
			k=(255*i/sYSize)-127;
			k=(k*(k*k)/128)/128;
			k=(k*(128-granularity))/128+128;
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_DIAGSHADE:	//
		a=(idxmax-idxmin)/2;
		for(i = 0; i < sYSize; i++) {
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)(idxmin+a*i/sYSize+a*(sXSize-j)/sXSize);
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_HSHADE:	//
		a=idxmax-idxmin;
		for(i = 0; i < sYSize; i++) {
			k=a*i/sYSize+idxmin;
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_VSHADE:	//:
		a=idxmax-idxmin;
		for(j = 0; j < sXSize; j++) {
			k=a*(sXSize-j)/sXSize+idxmin;
			for(i = 0; i < sYSize; i++) {
				posDst[j+i*bytes]=(BYTE)k;
				posDst[j+i*bytes]+=rand()/grainx2-granularity;
			} //for
		} //for
		break;
//----------------------------------------------------
	case EFFECT_NOISE:
		for(i = 0; i < sYSize; i++) {
			for(j = 0; j < sXSize; j++) {
				posDst[j]=128+rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
	} //switch
//----------------------------------------------------
} //End SetShade
#endif

void CPPDrawManager::FillEffect(HDC hDC, DWORD dwEffect, LPCRECT lpRect, COLORREF clrBegin, COLORREF clrMid /* = 0 */, COLORREF clrEnd /* = 0 */,  BYTE granularity /* = 0 */, BYTE coloring /* = 0 */)
{
	HBRUSH hBrush = NULL;

	RECT rect;
	rect.left = lpRect->left;
	rect.top = lpRect->top;
	rect.right = lpRect->right;
	rect.bottom = lpRect->bottom;

	int nHeight = rect.bottom - rect.top;
	int nWidth = rect.right - rect.left;
	
	switch (dwEffect)
	{
	default:
		hBrush = ::CreateSolidBrush(clrBegin);
		::FillRect(hDC, lpRect, hBrush);
		break;
	case EFFECT_HGRADIENT:
		FillGradient(hDC, lpRect, clrBegin, clrEnd, TRUE);
		break;
	case EFFECT_VGRADIENT:
		FillGradient(hDC, lpRect, clrBegin, clrEnd, FALSE);
		break;
	case EFFECT_HCGRADIENT:
		rect.right = rect.left + nWidth / 2;
		FillGradient(hDC, &rect, clrBegin, clrEnd, TRUE);
		rect.left = rect.right;
		rect.right = lpRect->right;
		FillGradient(hDC, &rect, clrEnd, clrBegin, TRUE);
		break;
	case EFFECT_3HGRADIENT:
		rect.right = rect.left + nWidth / 2;
		FillGradient(hDC, &rect, clrBegin, clrMid, TRUE);
		rect.left = rect.right;
		rect.right = lpRect->right;
		FillGradient(hDC, &rect, clrMid, clrEnd, TRUE);
		break;
	case EFFECT_VCGRADIENT:
		rect.bottom = rect.top + nHeight / 2;
		FillGradient(hDC, &rect, clrBegin, clrEnd, FALSE);
		rect.top = rect.bottom;
		rect.bottom = lpRect->bottom;
		FillGradient(hDC, &rect, clrEnd, clrBegin, FALSE);
		break;
	case EFFECT_3VGRADIENT:
		rect.bottom = rect.top + nHeight / 2;
		FillGradient(hDC, &rect, clrBegin, clrMid, FALSE);
		rect.top = rect.bottom;
		rect.bottom = lpRect->bottom;
		FillGradient(hDC, &rect, clrMid, clrEnd, FALSE);
		break;
#ifdef USE_SHADE
	case EFFECT_NOISE:
	case EFFECT_DIAGSHADE:
	case EFFECT_HSHADE:
	case EFFECT_VSHADE:
	case EFFECT_HBUMP:
	case EFFECT_VBUMP:
	case EFFECT_SOFTBUMP:
	case EFFECT_HARDBUMP:
	case EFFECT_METAL:
		rect.left = 0;
		rect.top = 0;
		rect.right = nWidth;
		rect.bottom = nHeight;
		SetShade(&rect, dwEffect, granularity, coloring, clrBegin, clrMid, clrEnd);
		m_dNormal.Draw(hDC, lpRect->left, lpRect->top);
		break; 
#endif
	} //switch

	if (NULL != hBrush)
	{
		::DeleteObject(hBrush);
		hBrush = NULL;
	} //if
} //End FillEffect

void CPPDrawManager::MultipleCopy(HDC hDestDC, int nDestX, int nDestY, DWORD dwDestWidth, DWORD dwDestHeight, 
										HDC hSrcDC, int nSrcX, int nSrcY, DWORD dwSrcWidth, DWORD dwSrcHeight)
{
	// Horizontal copying
	int right, bottom;
	int nDestRight = (int)(nDestX + dwDestWidth);
	int nDestBottom = (int)(nDestY + dwDestHeight);
	for (int x = nDestX; x < nDestRight; x+= dwSrcWidth)
	{
		right = min (x + (int)dwSrcWidth, nDestRight);
		// Vertical copying
		for (int y = nDestY; y < nDestBottom; y+= dwSrcHeight)
		{
			bottom = min (y + (int)dwSrcHeight, nDestBottom);
			::BitBlt(hDestDC, x, y, right - x, bottom - y, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		} //for
	} //for
} //End MultipleCopy

void CPPDrawManager::DrawBitmap(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, HBITMAP hSrcBitmap,
					BOOL bUseMask, COLORREF crMask, 
					DWORD dwEffect /* = IMAGE_EFFECT_NONE */, 
					BOOL bShadow /* = FALSE */, 
					DWORD dwCxShadow /* = PPDRAWMANAGER_SHADOW_XOFFSET */, 
					DWORD dwCyShadow /* = PPDRAWMANAGER_SHADOW_YOFFSET */,
					DWORD dwCxDepth /* = PPDRAWMANAGER_SHADOW_XDEPTH */, 
					DWORD dwCyDepth /* = PPDRAWMANAGER_SHADOW_YDEPTH */,
					COLORREF clrShadow /* = PPDRAWMANAGER_SHADOW_COLOR */)
{
	m_bIsAlpha = FALSE;
	if (NULL == hSrcBitmap)
		return;

	SIZE sz;
	GetSizeOfBitmap(hSrcBitmap, &sz);

	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	HDC hDestDC = ::CreateCompatibleDC(hDC);
	
	HBITMAP hBitmapTemp = ::CreateCompatibleBitmap(hDC, dwWidth, dwHeight);

	HBITMAP hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, hSrcBitmap);
	HBITMAP hOldDestBitmap = (HBITMAP)::SelectObject(hDestDC, hBitmapTemp);

	//Scales a bitmap if need
	if (((DWORD)sz.cx != dwWidth) || ((DWORD)sz.cy != dwHeight))
		::StretchBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, sz.cx, sz.cy, SRCCOPY);
	else
		::BitBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, SRCCOPY);

	::SelectObject(hDestDC, hOldDestBitmap);
	
	HBITMAP hMaskBmp = CreateImageEffect(hBitmapTemp, dwWidth, dwHeight, IMAGE_EFFECT_MASK, bUseMask, crMask);
	HBITMAP hBitmap = CreateImageEffect(hBitmapTemp, dwWidth, dwHeight, dwEffect, bUseMask, crMask, clrShadow);
	
	if (bShadow)
	{
		if (dwEffect & IMAGE_EFFECT_SHADOW)
		{
			POINT ptShadow;
			ptShadow.x = x + dwCxShadow;
			ptShadow.y = y + dwCyShadow;
			HBITMAP hShadowBmp =  CreateImageEffect(hBitmapTemp, dwWidth, dwHeight, IMAGE_EFFECT_MASK, bUseMask, crMask, InvertColor(clrShadow));
			DrawShadow(hDC, ptShadow.x, ptShadow.y, dwWidth, dwHeight, hShadowBmp, dwEffect & IMAGE_EFFECT_GRADIENT_SHADOW, dwCxDepth, dwCyDepth);
			::DeleteObject(hShadowBmp);
		}
		else
		{
			x += dwCxShadow;
			y += dwCyShadow;
		} //if
	} //if
	
	if (m_bIsAlpha)
	{
		::SelectObject(hSrcDC, hBitmap);
		AlphaChannelBitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0);
	}
	else
	{
		//Merge the image mask with background
		::SelectObject(hSrcDC, hMaskBmp);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCAND);
		
		//Draw the image
		::SelectObject(hSrcDC, hBitmap);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCPAINT);
	}
	
	::SelectObject(hSrcDC, hOldSrcBitmap);
	
	::DeleteDC(hDestDC);
	::DeleteDC(hSrcDC);

	::DeleteObject(hBitmap);
	::DeleteObject(hMaskBmp);
	::DeleteObject(hBitmapTemp);
} //End DrawBitmap

void CPPDrawManager::DrawIcon(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, HICON hSrcIcon,
  							DWORD dwEffect /* = IMAGE_EFFECT_NONE */, 
							BOOL bShadow /* = FALSE */, 
							DWORD dwCxShadow /* = PPDRAWMANAGER_SHADOW_XOFFSET */, 
							DWORD dwCyShadow /* = PPDRAWMANAGER_SHADOW_YOFFSET */,
							DWORD dwCxDepth /* = PPDRAWMANAGER_SHADOW_XDEPTH */, 
							DWORD dwCyDepth /* = PPDRAWMANAGER_SHADOW_YDEPTH */,
							COLORREF clrShadow /* = PPDRAWMANAGER_SHADOW_COLOR */)
{
	m_bIsAlpha = FALSE;
	if (NULL == hSrcIcon)
		return;

	SIZE sz;
	GetSizeOfIcon(hSrcIcon, &sz);

	HICON hIcon = NULL;

	if (((DWORD)sz.cx == dwWidth) && ((DWORD)sz.cy == dwHeight))
		hIcon = ::CopyIcon(hSrcIcon);
	else hIcon = StretchIcon(hSrcIcon, dwWidth, dwHeight);
	
	ICONINFO csOriginal;

	if (!::GetIconInfo(hIcon, &csOriginal))
		return;

	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	
	HBITMAP hBitmap;
	if (dwEffect & IMAGE_EFFECT_MONOCHROME)
		hBitmap = CreateImageEffect(csOriginal.hbmMask, dwWidth, dwHeight, dwEffect, TRUE, RGB(255, 255, 255), clrShadow);
	else
		hBitmap = CreateImageEffect(csOriginal.hbmColor, dwWidth, dwHeight, dwEffect, TRUE, RGB(0, 0, 0), clrShadow);
	HBITMAP hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, hBitmap);

	if (bShadow)
	{
		if (dwEffect & IMAGE_EFFECT_SHADOW)
		{
			POINT ptShadow;
			ptShadow.x = x + dwCxShadow;
			ptShadow.y = y + dwCyShadow;
			HBITMAP hShadowBmp =  CreateImageEffect(csOriginal.hbmMask, dwWidth, dwHeight, IMAGE_EFFECT_MASK, TRUE, RGB(255, 255, 255), InvertColor(clrShadow));
			DrawShadow(hDC, ptShadow.x, ptShadow.y, dwWidth, dwHeight, hShadowBmp, dwEffect & IMAGE_EFFECT_GRADIENT_SHADOW, dwCxDepth, dwCyDepth);
			::DeleteObject(hShadowBmp);
		}
		else
		{
			x += dwCxShadow;
			y += dwCyShadow;
		} //if
	} //if
	
	if (m_bIsAlpha)
	{
//		::SelectObject(hSrcDC, hBitmap);
		AlphaChannelBitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0);
	}
	else
	{
		//-------------------------------------------------------------------
		// !!! ATTENTION !!!
		// I don't know why a icon uses text's color
		// Therefore I change a text's color to BLACK and after draw I restore
		// original color
		//-------------------------------------------------------------------
		COLORREF crOldColor = ::SetTextColor(hDC, RGB(0, 0, 0));
		//Merge the image mask with background
		::SelectObject(hSrcDC, csOriginal.hbmMask);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCAND);
		//Draw the image
		::SelectObject(hSrcDC, hBitmap);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCPAINT);
		::SetTextColor(hDC, crOldColor);
	} //if

	::SelectObject(hSrcDC, hOldSrcBitmap);
	::DeleteDC(hSrcDC);
	::DeleteObject(hBitmap);
	::DestroyIcon(hIcon);

	::DeleteObject(csOriginal.hbmColor);
	::DeleteObject(csOriginal.hbmMask);
} //End DrawIcon

void CPPDrawManager::DrawShadow(HDC hDestDC, int nDestX, int nDestY, DWORD dwWidth, DWORD dwHeight, HBITMAP hMask, BOOL bGradient /* = FALSE */, DWORD dwDepthX /* = PPDRAWMANAGER_SHADOW_YOFFSET */, DWORD dwDepthY /* = PPDRAWMANAGER_SHADOW_XOFFSET */)
{
	HDC hSrcDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hSrcDC)
		return;

	HDC hTempDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hTempDC)
	{
		::DeleteDC(hSrcDC);
		return;
	} // if
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	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))
	{
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hMask);
		if (bGradient)
		{
			if (!(dwDepthX & 0x1)) dwDepthX++;
			if (!(dwDepthY & 0x1)) dwDepthY++;
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, WHITENESS);
			::StretchBlt (hSrcDC, dwDepthX / 2, dwDepthY / 2, dwWidth - dwDepthX, dwHeight - dwDepthY, hTempDC, 0, 0, dwWidth, dwHeight, SRCCOPY);
		}
		else
		{
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
		} //if
		::SelectObject (hTempDC, hOldTempBmp);
		::SelectObject (hSrcDC, hOldSrcBmp);
		
		//Creates Destination DIB
		LPBITMAPINFO lpbiDest;
		// Fill in the BITMAPINFOHEADER
		lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
		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 (
			hDestDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
			NULL, NULL);
		
		if ((NULL != hDestDib) && (NULL != pDestBits))
		{
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDestDC, nDestX, nDestY, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);
			
			if (bGradient)
			{
				double * depth = new double [dwWidth * dwHeight];
				SmoothMaskImage(dwWidth, dwHeight, pSrcBits, dwDepthX, dwDepthY, depth);
				for(DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pDestBits++)
					*pDestBits = DarkenColor(*pDestBits, *(depth + pixel));
				delete [] depth;
			}
			else
			{
				for(DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
					*pDestBits = DarkenColor(*pDestBits, (double)GetRValue(*pSrcBits) / 255.0);
			} //if
				
			
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hDestDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			delete [] lpbiDest;
			::DeleteObject(hDestDib);
		} //if
		delete [] lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if
	::DeleteDC(hTempDC);
	::DeleteDC(hSrcDC);
} //End DrawIcon

void CPPDrawManager::DrawImageList(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, HBITMAP hSrcBitmap,
					int nIndex, int cx, int cy,
					BOOL bUseMask, COLORREF crMask, 
					DWORD dwEffect /*= IMAGE_EFFECT_NONE*/, 
					BOOL bShadow /*= FALSE*/, 
					DWORD dwCxShadow /*= PPDRAWMANAGER_SHADOW_XOFFSET*/, 
					DWORD dwCyShadow /*= PPDRAWMANAGER_SHADOW_YOFFSET*/,
					DWORD dwCxDepth /*= PPDRAWMANAGER_SHADOW_XDEPTH*/, 
					DWORD dwCyDepth /*= PPDRAWMANAGER_SHADOW_YDEPTH*/,
					COLORREF clrShadow /*= PPDRAWMANAGER_SHADOW_COLOR*/)
{
	if ((NULL == hSrcBitmap) || !cx || !cy)
		return;

	SIZE sz;
	GetSizeOfBitmap(hSrcBitmap, &sz);

	//ENG: Gets a max columns and rows of the images on the bitmap
	//RUS: �������� ������������ ����� ������� � ����� ����������� �� ��������
	int nMaxCol = sz.cx / cx;
	int nMaxRow = sz.cy / cy;
	int nMaxImages = nMaxCol * nMaxRow;

	if ((nIndex < nMaxImages) && nMaxCol && nMaxRow)
	{
		//ENG: Gets an specified image from the bitmap
		//RUS: �������� ��������� ����������� �� �������
		HDC hSrcDC = ::CreateCompatibleDC(hDC);
		HDC hDestDC = ::CreateCompatibleDC(hDC);
		HBITMAP hIconBmp = ::CreateCompatibleBitmap(hDC, cx, cy);
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject(hSrcDC, hSrcBitmap);
		HBITMAP hOldDestBmp = (HBITMAP)::SelectObject(hDestDC, hIconBmp);
		::BitBlt(hDestDC, 0, 0, cx, cy, hSrcDC, (nIndex % nMaxCol) * cx, (nIndex / nMaxCol) * cy, SRCCOPY);
		::SelectObject(hSrcDC, hOldSrcBmp);
		::SelectObject(hDestDC, hOldDestBmp);
		::DeleteDC(hSrcDC);
		::DeleteDC(hDestDC);
		DrawBitmap( hDC, x, y, dwWidth, dwHeight, hIconBmp, 
					bUseMask, crMask, dwEffect, 
					bShadow, dwCxShadow, dwCyShadow, 
					dwCxDepth, dwCyDepth, clrShadow);
		::DeleteObject(hIconBmp);
	} //if
} //End of DrawImageList

void CPPDrawManager::MaskToDepth(HDC hDC, DWORD dwWidth, DWORD dwHeight, HBITMAP hMask, double * pDepth, BOOL bGradient /* = FALSE */, DWORD dwDepthX /* = PPDRAWMANAGER_CXSHADOW */, DWORD dwDepthY /* = PPDRAWMANAGER_CYSHADOW */)
{
	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	if (NULL == hSrcDC)
	{
		::DeleteDC(hSrcDC);
		hSrcDC = NULL;
		return;
	} //if

	HDC hTempDC = ::CreateCompatibleDC(hDC);
	if (NULL == hTempDC)
	{
		::DeleteDC(hTempDC);
		hTempDC = NULL;
		return;
	} //if
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	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))
	{
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hMask);
		if (bGradient)
		{
			if (!(dwDepthX & 0x1)) dwDepthX++;
			if (!(dwDepthY & 0x1)) dwDepthY++;
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, WHITENESS);
			::StretchBlt (hSrcDC, dwDepthX / 2, dwDepthY / 2, dwWidth - dwDepthX, dwHeight - dwDepthY, hTempDC, 0, 0, dwWidth, dwHeight, SRCCOPY);
		}
		else
		{
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
		} //if
		::SelectObject (hTempDC, hOldTempBmp);
		::SelectObject (hSrcDC, hOldSrcBmp);
		
		if (bGradient)
		{
			SmoothMaskImage(dwWidth, dwHeight, pSrcBits, dwDepthX, dwDepthY, pDepth);
		}
		else
		{
			for (DWORD pixel = 0; pixel < (dwHeight * dwWidth); pixel++, pSrcBits++, pDepth++)
			{
				*pDepth = GetRValue(*pSrcBits) / 255;
			} //for
		} //if
		delete [] lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if
	::DeleteDC(hTempDC);
	::DeleteDC(hSrcDC);
} //End MaskToDepth

void CPPDrawManager::DarkenByDepth(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, double * pDepth)
{
	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	if (NULL == hSrcDC)
	{
		::DeleteDC(hSrcDC);
		hSrcDC = NULL;
		return;
	} //if
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	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))
	{
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hDC, x, y, SRCCOPY);
		::SelectObject (hSrcDC, hOldSrcBmp);
		
		for (DWORD pixel = 0; pixel < (dwHeight * dwWidth); pixel++, pSrcBits++, pDepth++)
		{
			*pSrcBits = DarkenColor(*pSrcBits, *pDepth);
		} //for

		hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCCOPY);
		::SelectObject (hSrcDC, hOldSrcBmp);

		delete [] lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if
	::DeleteDC(hSrcDC);
} //DarkenByDepth

void CPPDrawManager::SmoothMaskImage(const int ImageWidth, 
									 const int ImageHeight,
									 const COLORREF* const pInitImg,
									 const int KerWidth,
									 const int KerHeight,
									 double* const pResImg_R /*= NULL*/)
{
	double* const pfBuff1 = new double[(ImageWidth  + KerWidth  - 1) * 
		(ImageHeight + KerHeight - 1)];
	double* const pfBuff2 = new double[(ImageWidth  + KerWidth  - 1) * 
		(ImageHeight + KerHeight - 1)];
	
	// expanding initial image with a padding procdure
	double* p = pfBuff1;
	const COLORREF * pInitImg_It = pInitImg;
	if(NULL != pResImg_R)
	{
		for(int _i = - KerHeight/2; _i < ImageHeight +  KerHeight/2; _i++)
		{
			for(int _j = -KerWidth/2; _j < ImageWidth + KerWidth/2;  _j++, p++)
			{
				if ((_i >= 0) && (_i < ImageHeight) && (_j >= 0) && (_j < ImageWidth))
				{
					*p = GetRValue(*pInitImg_It++);
					//					pInitImg_It++;
				}
				else
					*p = 255;
			} //for
		} //for
		
		//---
		GetPartialSums(pfBuff1,
			(ImageHeight + KerHeight - 1),
			(ImageWidth  + KerWidth  - 1),
			KerHeight,
			KerWidth,
			pfBuff2,
			pResImg_R);
		
		for(int i = 0; i < ImageHeight*ImageWidth; i++)
			*(pResImg_R + i) /= KerHeight*KerWidth*255;
	} //if
	
	
	delete [] pfBuff1;
	delete [] pfBuff2;
} //End SmoothMaskImage

void CPPDrawManager::GetPartialSums(const double* const pM,
									unsigned int nMRows,
									unsigned int nMCols,
									unsigned int nPartRows,
									unsigned int nPartCols,
									double* const pBuff,
									double* const pRes)
{
	const double* it1;
	const double* it2;
	const double* it3;
	
	double* pRowsPartSums;
	const unsigned int nRowsPartSumsMRows = nMRows;
	const unsigned int nRowsPartSumsMCols = nMCols - nPartCols + 1;	
	
	const unsigned int nResMRows = nMRows - nPartRows + 1;
	const unsigned int nResMCols = nMCols - nPartCols + 1;
	
	
	unsigned int i,j;
	double s;
	
	// ��������� ����� �����
	it1          = pM;
	pRowsPartSums = pBuff;
	
	for(i = 0; i < nMRows; i++)
	{
		//-------------
		it2 = it1;
		s = 0;
		for(j = 0;j < nPartCols;j++)s+=*it2++;
		//-------------
		it3 = it1;
		*pRowsPartSums++ = s;
		for(/*j = nPartCols*/; j < nMCols; j++)
		{
			s+=*it2 - *it3;
			*pRowsPartSums++ = s;
			it2++;
			it3++;
		} //for
		//--
		it1 += nMCols;
	} //for
	// ������������ ���������
	const double* it4;
	const double* it5;
	const double* it6;
	
	double* pResIt;
	
	it4    = pBuff;
	pResIt = pRes;
	
	for(j = 0; j < nRowsPartSumsMCols; j++)
	{
		pResIt = pRes + j;
		//-------------
		it5 = it4;
		s = 0;
		for(i = 0; i < nPartRows; i++)
		{
			s += *it5;
			it5 += nRowsPartSumsMCols; 
		} //for
		//-------------
		it6 = it4;
		*pResIt = s;
		pResIt += nRowsPartSumsMCols;
		
		for(; i < nRowsPartSumsMRows; i++)
		{
			s += *it5 - *it6;//cout<<s<<endl;
			*pResIt = s;
			pResIt += nResMCols;
			it5 += nRowsPartSumsMCols;
			it6 += nRowsPartSumsMCols;
		} //for
		//--
		it4 ++;
	} //for
} //End GetPartialSums

void CPPDrawManager::DrawRectangle(HDC hDC, LPRECT lpRect, COLORREF crLight, COLORREF crDark, int nStyle /* = PEN_SOLID */, int nSize /* = 1 */)
{
	DrawRectangle(hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, crLight, crDark, nStyle, nSize);
}

void CPPDrawManager::DrawRectangle(HDC hDC, int left, int top, int right, int bottom, 
								   COLORREF crLight, COLORREF crDark, int nStyle /* = PEN_SOLID */, 
								   int nSize /* = 1 */)
{
	if ((PEN_NULL == nStyle) || (nSize < 1))
		return;

	int nSysPenStyle = PS_SOLID;
	int nDoubleLineOffset = nSize * 2;
	switch (nStyle)
	{
	case PEN_DASH: nSysPenStyle = PS_DASH; break;
	case PEN_DOT: nSysPenStyle = PS_DOT; break;
	case PEN_DASHDOT: nSysPenStyle = PS_DASHDOT; break;
	case PEN_DASHDOTDOT: nSysPenStyle = PS_DASHDOTDOT; break;
	case PEN_DOUBLE:
	case PEN_SOLID:
	default:
		nSysPenStyle = PS_SOLID; 
		break;
	} //switch

	//Insideframe
	left += nSize / 2;
	top += nSize / 2;
	right -= nSize / 2;
	bottom -= nSize / 2;

	//Creates a light pen
	HPEN hPen = ::CreatePen(nSysPenStyle, nSize, crLight);
	HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);

	//Draw light border
	::MoveToEx(hDC, left, bottom, NULL);
	::LineTo(hDC, left, top);
	::LineTo(hDC, right, top);
	if (PEN_DOUBLE == nStyle)
	{
		::MoveToEx(hDC, left + nDoubleLineOffset, bottom - nDoubleLineOffset, NULL);
		::LineTo(hDC, left + nDoubleLineOffset, top + nDoubleLineOffset);
		::LineTo(hDC, right - nDoubleLineOffset, top + nDoubleLineOffset);
	} //if

	//Creates a dark pen if needed
	if (crLight != crDark)
	{
		SelectObject(hDC, hOldPen);
		::DeleteObject(hPen);
		hPen = ::CreatePen(nSysPenStyle, nSize, crDark);
		hOldPen = (HPEN)::SelectObject(hDC, hPen);
	} //if

	//Draw dark border
	::MoveToEx(hDC, right, top, NULL);
	::LineTo(hDC, right, bottom);
	::LineTo(hDC, left, bottom);
	if (PEN_DOUBLE == nStyle)
	{
		::MoveToEx(hDC, right - nDoubleLineOffset, top + nDoubleLineOffset, NULL);
		::LineTo(hDC, right - nDoubleLineOffset, bottom - nDoubleLineOffset);
		::LineTo(hDC, left + nDoubleLineOffset, bottom - nDoubleLineOffset);
	} //if

	SelectObject(hDC, hOldPen);
	::DeleteObject(hPen);
} //End DrawRectangle

void CPPDrawManager::DrawLine(HDC hDC, 
							  int xStart, int yStart, int xEnd, int yEnd, 
							  COLORREF color, int nStyle /* = PEN_SOLID */, 
							  int nSize /* = 1 */) const
{
	if ((PEN_NULL == nStyle) || (nSize < 1))
		return;
	
	int nSysPenStyle;
	int nDoubleLineOffset = nSize * 2;
	switch (nStyle)
	{
	case PEN_DASH: nSysPenStyle = PS_DASH; break;
	case PEN_DOT: nSysPenStyle = PS_DOT; break;
	case PEN_DASHDOT: nSysPenStyle = PS_DASHDOT; break;
	case PEN_DASHDOTDOT: nSysPenStyle = PS_DASHDOTDOT; break;
	case PEN_DOUBLE:
	case PEN_SOLID:
	default:
		nSysPenStyle = PS_SOLID; 
		break;
	} //switch

	HPEN hPen = ::CreatePen(nSysPenStyle, nSize, color);
	HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);

	::MoveToEx(hDC, xStart, yStart, NULL);
	::LineTo(hDC, xEnd, yEnd);
	
	if (PEN_DOUBLE == nStyle)
	{
		if (xStart != xEnd)
		{
			yStart += nDoubleLineOffset;
			yEnd += nDoubleLineOffset;
		} //if
		
		if (yStart != yEnd)
		{
			xStart += nDoubleLineOffset;
			xEnd += nDoubleLineOffset;
		} //if
		::MoveToEx(hDC, xStart, yStart, NULL);
		::LineTo(hDC, xEnd, yEnd);
	} //if
	SelectObject(hDC, hOldPen);
	::DeleteObject(hPen);
} //End DrawLine

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.

Recently, I have moved to Los Angeles where I am doing consulting and development work.

For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions