www.pudn.com > LayeredBitmapCtrl_demo.zip > LayeredBitmapCtrl.cpp


//******************************************************************* 
//  FILE:		LayeredBitmapCtrl.cpp - implementation file 
// 
//  AUTHOR:		Brian H. Conte - email(GhostsOfRage@yahoo.com) 
// 
//  COMPONENTS:	CLayerInfo - Stores information about a layer. 
//				CLayeredBitmapCtrl - CStatic derived class that provides 
//					functionality for bitmap layers, including bitmaps 
//					with a specified transparent color. 
// 
//	COPYRIGHT:	©2003-2004, All Rights Reserved 
// 
//				This code may be used in compiled form in any way you 
//				desire. This file may be redistributed unmodified by 
//				any means PROVIDING it is not sold for profit without 
//				the authors written consent, and providing that this 
//				notice and the authors name and all copyright notices 
//				remains intact. 
// 
//				This file is provided "as is" with no expressed or 
//				implied warranty.  The author accepts no liability 
//				for any damage/loss of business that this product may 
//				cause. 
// 
//  COMMENTS:	This code allows you to add/remove/show/hide bitmap 
//				layers on a static control.  The first layer is not 
//				usually set to transparent because it is used as the 
//				background.  All of the other layers should have the 
//				transparent flag set, otherwise the first layer will 
//				not be visible.  The exception to this is if you have 
//				more than one background layer and you only set the 
//				show flag for one or the other.  This code was written 
//				to support 24-bit bitmap images only.  The standard 
//				template library (STL) is used for the vector support. 
// 
//  REFERENCES:	Windows 2000 Graphics API Black Book, 
//					Authors: Damon Chandler, Michael Fotsch 
//				The C++ Standard Library - A Tutorial and Reference 
//					Author: Nicolai M Josuttis 
// 
//  HISTORY:	 
//				09/25/2003 - Initial release. 
//				10/02/2003 - Fixed a couple of resource leaks. 
//				10/10/2003 - Added ability to move layers around with 
//							 the mouse without changing the order of 
//							 the layers. 
//				10/10/2003 - Modified the drawing functions so that 
//							 the selected layer can be moved, while 
//							 the other layers above remain in the  
//							 same position. 
//				11/16/2003 - Added a Create function to allow the control 
//							 to be dynamically create on a CView, etc. 
//				03/14/2004 - Added a focus rectangle for the currently 
//							 selected layer.  Thanks to X.Q.Wang for 
//							 the suggestion. 
//				04/27/2004 - Added methods to set/get the description, 
//							 transparent color, and location of the 
//							 layer after it has already been added to 
//							 the control. 
//				05/07/2004 - Modified the FindLayer function so that 
//							 the code will compile with VC++ 7.0 .NET 
//							 (Thanks Shilps!) 
//				06/09/2004 - Added code so that only the portion of  
//							 the layers above the tracked layer are redrawn, 
//							 to give the appearance that the tracked 
//							 layer is moving underneath all of the layers 
//							 above. 
//				06/10/2004 - Added the flag m_bShowOnTopWhileTracking which 
//							 speeds up the drawing process because none of 
//							 layers above the tracked layer need to be  
//							 redrawn.  The m_bShowOnTopWhileTracking 
//							 flag is defaulted to true, but the flag 
//							 can be changed at anytime. 
//				06/17/2004 - Changed to version 2.0 since the drawing 
//							 code had been modified so much as well 
//							 the enhancements. 
//				06/21/2004 - Modified the OnPaint function to use the 
//							 reinterpret_cast<> to convert the vector 
//							 iterator to a CLayerInfo pointer.  This  
//							 should fix the VC++ 7.0 compiler errors. 
//				12/07/2004 - Added code to change the background color 
//							 if the control.  Another addition is the 
//							 ability to use the system color for the 
//							 control's background that supports system 
//							 color changes.  Thanks to Michel Wassink 
//							 for the suggestions! 
//				12/08/2004 - Changed to version 2.01 to reflect the 
//							 latest changes. 
//******************************************************************* 
 
#include "stdafx.h" 
#include "LayeredBitmapCtrl.h" 
 
#include  
#include  
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
using namespace std; 
 
 
//******************************************************************* 
//  CLASS:      -	CLayerInfo 
//  COMMENTS:   -	This class contains all of the necessary elements 
//					for a layer object.  The comparison functions are 
//					only provided for sorting the vector in the 
//					CLayeredBitmapCtrl control.  That is why the only 
//					element that is compared is the layer index. 
//******************************************************************* 
 
//******************************************************************* 
//  FUNCTION:   -	CLayerInfo 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	Default constructor. 
//******************************************************************* 
CLayerInfo::CLayerInfo() 
{ 
	m_nLayerID					= 0; 
	m_nLayerIndex				= 0; 
	 
	m_strLayerDesc.Empty(); 
	 
	m_bVisible					= false; 
	m_bTransparent				= false; 
	m_bUseRgn					= false; 
	 
	m_ptTransparentPixel.x		= -1; 
	m_ptTransparentPixel.y		= -1; 
	 
	m_ptLocation.x				= 0; 
	m_ptLocation.y				= 0; 
	 
	m_bTrackingEnabled			= false; 
	m_bTracking					= false; 
	m_bShowOnTopWhileTracking	= true; 
	m_ptTrackingStart.x			= 0; 
	m_ptTrackingStart.y			= 0; 
 
	m_bFocusRectangleEnabled	= false; 
	m_bShowFocusRectangle		= false; 
	m_colFocusRectangle			= RGB( 255, 0, 0 ); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CLayerInfo 
//  RETURNS:    -	 
//  PARAMETERS: -	src - Existing layer object. 
//  COMMENTS:	-	Copy constructor.  Initializes a new layer object 
//					from an existing layer.  This is necessary for use 
//					with the vector. 
//******************************************************************* 
CLayerInfo::CLayerInfo( const CLayerInfo &src ) 
{ 
	this->Copy( src ); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	~CLayerInfo 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	Destructor.  Removes the bitmap and region objects. 
//******************************************************************* 
CLayerInfo::~CLayerInfo() 
{ 
	m_strLayerDesc.Empty(); 
 
	// Need to delete the bmp and rgn. 
	m_bmp.DeleteObject(); 
	m_rgn.DeleteObject(); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	Copy 
//  RETURNS:    -	*this object. 
//  PARAMETERS: -	src - Existing layer object. 
//  COMMENTS:	-	This function makes a copy of an existing layer 
//					into "this" layer object. 
//******************************************************************* 
CLayerInfo &CLayerInfo::Copy( const CLayerInfo &src ) 
{ 
	m_nLayerID					= src.m_nLayerID; 
	m_nLayerIndex				= src.m_nLayerIndex; 
	m_strLayerDesc				= src.m_strLayerDesc; 
	m_bVisible					= src.m_bVisible; 
	m_bUseRgn					= src.m_bUseRgn; 
	m_bTransparent				= src.m_bTransparent; 
	m_colTransparent			= src.m_colTransparent; 
	m_ptTransparentPixel.x		= src.m_ptTransparentPixel.x; 
	m_ptTransparentPixel.y		= src.m_ptTransparentPixel.y; 
	m_ptLocation.x				= src.m_ptLocation.x; 
	m_ptLocation.y				= src.m_ptLocation.y; 
 
	m_bTrackingEnabled			= src.m_bTrackingEnabled; 
	m_bTracking					= src.m_bTracking; 
	m_bShowOnTopWhileTracking	= src.m_bShowOnTopWhileTracking; 
	m_ptTrackingStart			= src.m_ptTrackingStart; 
	 
	m_bFocusRectangleEnabled	= src.m_bFocusRectangleEnabled; 
	m_bShowFocusRectangle		= src.m_bShowFocusRectangle; 
	m_colFocusRectangle			= src.m_colFocusRectangle; 
 
	// Make a copy of the existing bitmap. 
	CopyBitmap( src.m_bmp, m_bmp ); 
 
	// Copy the region if it exists. 
	if ( m_bUseRgn ) 
	{ 
		if ( NULL != src.m_rgn.GetSafeHandle() ) 
		{ 
			// Get the size of the region data. 
			int nDataSize = (int)src.m_rgn.GetRegionData( NULL, 0 ); 
 
			if ( nDataSize > 0 ) 
			{ 
				// Allocate memory to store a copy of the region data. 
				BYTE *pBuffer = new BYTE[nDataSize]; 
				LPRGNDATA pRgnData = reinterpret_cast(pBuffer); 
 
				if ( nDataSize == src.m_rgn.GetRegionData( pRgnData, nDataSize ) ) 
				{ 
					// Make sure that we don't already have a region created. 
					m_rgn.DeleteObject(); 
 
					// Now, create a new region based on the existing region. 
					m_rgn.CreateFromData( NULL, nDataSize, pRgnData ); 
				} 
 
				// Make sure we free the region data memory. 
				delete [] pBuffer; 
			} 
			else 
			{ 
				// If it really doesn't exist set the flag to false. 
				m_bUseRgn	= false; 
			} 
		} 
		else 
		{ 
			// If the region handle was invalid then assume the region doesn't exist. 
			m_bUseRgn	= false; 
		} 
	} 
 
	// Return this object with a copy of the existing region. 
	return *this; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	operator= 
//  RETURNS:    -	*this object. 
//  PARAMETERS: -	src - Existing layer object. 
//  COMMENTS:	-	This function allows one layer object to be assigned 
//					to another layer object. 
//******************************************************************* 
CLayerInfo &CLayerInfo::operator=( const CLayerInfo &src ) 
{ 
	return( Copy(src) ); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	operator== 
//  RETURNS:    -	true, if the layer index of both objects match. 
//					Otherwise, false. 
//  PARAMETERS: -	layerInfo - Layer object used for comparison. 
//  COMMENTS:	-	Compares the current layer object with another 
//					layer object.  This function is used by the vector 
//					for sorting purposes. 
//******************************************************************* 
bool CLayerInfo::operator==( const CLayerInfo &layerInfo ) const 
{ 
	bool bResult = false; 
 
	// Does the layer index match? 
	if ( m_nLayerIndex == layerInfo.m_nLayerIndex ) 
	{ 
		bResult = true; 
	} 
	 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	operator< 
//  RETURNS:    -	true, if the current layer index is less than the 
//					comparison layer object. 
//					Otherwise, false. 
//  PARAMETERS: -	layerInfo - Layer object used for comparison. 
//  COMMENTS:	-	Performs a Less Than comparison with the current 
//					layer object and another layer object.  This 
//					function is used by the vector for sorting purposes. 
//******************************************************************* 
bool CLayerInfo::operator<( const CLayerInfo &layerInfo ) const 
{ 
	bool bResult = false; 
 
	// Is this layer index less than the comparison layer index. 
	if ( m_nLayerIndex < layerInfo.m_nLayerIndex ) 
	{ 
		bResult = true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	operator> 
//  RETURNS:    -	true, if the current layer index is greater than 
//					the comparison layer object. 
//					Otherwise, false. 
//  PARAMETERS: -	layerInfo - Layer object used for comparison. 
//  COMMENTS:	-	Performs a Greater Than comparison with the current 
//					layer object and another layer object.  This 
//					function is used by the vector for sorting purposes. 
//******************************************************************* 
bool CLayerInfo::operator>( const CLayerInfo &layerInfo ) const 
{ 
	bool bResult = false; 
 
	// Is this layer index greater than the comparison layer index. 
	if ( m_nLayerIndex > layerInfo.m_nLayerIndex ) 
	{ 
		bResult = true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CopyBitmap 
//  RETURNS:    -	true - if successful. 
//					false - if unable to retrieve the bitmap structure. 
//  PARAMETERS: -	bmpSrc - Existing source bitmap. 
//					bmpDest - Destination bitmap. 
//  COMMENTS:	-	Copies an existing source bitmap into a new 
//					destination bitmap. 
//******************************************************************* 
bool CLayerInfo::CopyBitmap( const CBitmap &bmpSrc, CBitmap &bmpDest ) 
{ 
	bool bResult = false; 
	BITMAP bm; 
 
	// Attempt to retrieve the existing bitmap structure. 
	if ( 0 == bmpSrc.GetObject( sizeof(BITMAP), &bm ) ) 
	{ 
		return bResult; 
	} 
 
	// Get a handle to the current device context. 
	HDC hDC = ::GetDC( NULL ); 
 
	// Prepare a new bitmap info structure. 
	// Note this function allocates the memory for the structure, 
	// so make sure that the memory gets freed. 
	BITMAPINFO *pBmpInfo = PrepareRGBBitmapInfo( bm.bmWidth, bm.bmHeight ); 
 
	// Don't try to use a NULL pointer. 
	if ( NULL != pBmpInfo ) 
	{ 
		// Allocate a buffer to store the device independent bits from the source bitmap. 
		BYTE *pData = new BYTE[pBmpInfo->bmiHeader.biSizeImage]; 
 
		if ( NULL != pData ) 
		{ 
			// Get the device independent bits from the source bitmap. 
			::GetDIBits( hDC, (HBITMAP)bmpSrc, 0, bm.bmHeight, pData, pBmpInfo, DIB_RGB_COLORS ); 
 
			// Make sure that the destination bitmap is empty. 
			bmpDest.DeleteObject(); 
 
			// Create a temporary bitmap handle with the same dimensions of the source bitmap. 
			HBITMAP hTmpBmp = ::CreateCompatibleBitmap( hDC, bm.bmWidth, bm.bmHeight ); 
 
			// Set the device independent bits from the source bitmap into the temporary bitmap handle. 
			::SetDIBits( hDC, hTmpBmp, 0, bm.bmHeight, pData, pBmpInfo, DIB_RGB_COLORS ); 
			 
			// Detach the old bitmap. 
			bmpDest.Detach(); 
 
			// Attach the temporary bitmap handle to the destination bitmap. 
			bmpDest.Attach( hTmpBmp ); 
 
			// Set the dimensions of the bitmap so that they can be used later. 
			// Otherwise, they will be invalid. 
			bmpDest.SetBitmapDimension( bm.bmWidth, bm.bmHeight ); 
 
			// Free the buffer used to store the bits. 
			delete [] pData; 
 
			// The bitmap was successfully copied. 
			bResult = true; 
		} 
 
		// Free the memory for the bitmap info structure. 
		delete pBmpInfo; 
	} 
 
	// Release the device context. 
	::ReleaseDC( NULL, hDC ); 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CopyBitmapSection 
//  RETURNS:    -	true - if successful. 
//					false - if unable to retrieve the bitmap structure. 
//  PARAMETERS: -	bmpSrc - Existing source bitmap. 
//					bmpDest - Destination bitmap. 
//  COMMENTS:	-	Copies a section from an existing source bitmap  
//					into a new destination bitmap. 
//******************************************************************* 
bool CLayerInfo::CopyBitmapSection( CBitmap &bmpSrc, CBitmap &bmpDest, CRect &rectSection, CDC *pDC /* = NULL */ ) 
{ 
	bool bResult		= false; 
	int nWidth			= rectSection.Width(); 
	int nHeight			= rectSection.Height(); 
	CDC destDC, srcDC; 
	CBitmap *pOldBmp	= NULL; 
	CBitmap *pOldSrcBmp = NULL; 
 
	// Create two device contexts, one for the destination bitmap and one for the source bitmap. 
	destDC.CreateCompatibleDC( pDC ); 
	srcDC.CreateCompatibleDC( pDC ); 
 
	// Make sure that the destination bitmap is empty. 
	bmpDest.DeleteObject(); 
 
	// Create a bitmap that is compatible with the current device context. 
	bmpDest.CreateCompatibleBitmap( pDC, nWidth, nHeight ); 
 
	// Select the bitmaps into the device contexts. 
	pOldSrcBmp	= srcDC.SelectObject( &bmpSrc ); 
	pOldBmp		= destDC.SelectObject( &bmpDest ); 
 
	// Transfer the section of the source bitmap into the destination bitmap. 
	destDC.StretchBlt( 0, 0, nWidth, nHeight, &srcDC, rectSection.left, rectSection.top, 
		rectSection.Width(), rectSection.Height(), SRCCOPY ); 
 
	// Set the dimensions of the bitmap so that they can be used later. 
	// Otherwise, they will be invalid. 
	bmpDest.SetBitmapDimension( nWidth, nHeight ); 
 
	// Clean up the device contexts. 
	destDC.SelectObject( pOldBmp ); 
	srcDC.SelectObject( pOldSrcBmp ); 
 
	// The bitmap section was successfully copied. 
	bResult = true; 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	PrepareRGBBitmapInfo 
//  RETURNS:    -	Pointer to a newly allocated bitmap info structure. 
//  PARAMETERS: -	nWidth - Bitmap width 
//					nHeight - Bitmap height 
//  COMMENTS:	-	Allocates and initializes a bitmap info structures. 
//					This code only works with 24 bit bitmap images. 
//******************************************************************* 
BITMAPINFO *CLayerInfo::PrepareRGBBitmapInfo( int nWidth, int nHeight ) 
{ 
	BITMAPINFO *pBmpInfo = new BITMAPINFO; 
	::ZeroMemory( pBmpInfo, sizeof(BITMAPINFO) ); 
 
	pBmpInfo->bmiHeader.biSize		= sizeof(BITMAPINFOHEADER); 
	pBmpInfo->bmiHeader.biWidth		= nWidth; 
	pBmpInfo->bmiHeader.biHeight	= nHeight; 
	pBmpInfo->bmiHeader.biPlanes	= 1; 
	pBmpInfo->bmiHeader.biBitCount	= 24; 
 
	// This calculation was taken from Ivaylo Byalkov's article about smooth bitmap scaling. 
	pBmpInfo->bmiHeader.biSizeImage	= ((3 * nWidth + 3) & ~3) * nHeight; 
 
	return pBmpInfo; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetColorFromBitmap 
//  RETURNS:    -	color from the specific location in the bitmap. 
//  PARAMETERS: -	ptLocation - Pixel location in the bitmap. 
//					bitmap - Bitmap to retrieve the color from. 
//  COMMENTS:   -	Gets the color from a specific location within 
//					a bitmap. 
//******************************************************************* 
COLORREF CLayerInfo::GetColorFromBitmap( const CPoint &ptLocation, CBitmap &bitmap ) 
{ 
	COLORREF col		= RGB( 0, 0, 0 ); 
	CBitmap *pOldBmp	= NULL; 
	BITMAP bm; 
	CDC imageDC; 
	 
	// See if the bitmap is valid. 
	if ( NULL != bitmap.GetSafeHandle() ) 
	{ 
		if ( bitmap.GetBitmap( &bm ) ) 
		{ 
			// Create a device context to get the pixel information from the bitmap. 
			imageDC.CreateCompatibleDC( NULL ); 
 
			// Select the bitmap into the device context. 
			pOldBmp = imageDC.SelectObject( &bitmap ); 
 
			// Get the color from the bitmap at the specific location. 
			col		= imageDC.GetPixel( ptLocation ); 
 
			// Clean up. 
			imageDC.SelectObject( pOldBmp ); 
		} 
	} 
 
	return col; 
} 
 
 
 
//******************************************************************* 
//  CLASS:      -	CLayeredBitmapCtrl 
//  COMMENTS:   -	This is a CStatic derived class that provides the 
//					ability to add/remove/show/hide bitmap layers on 
//					a static control.  The first layer is not usually 
//					set to transparent because it is used as the 
//					background.  However, with the newly added functions, 
//					the background can be set to any color without the 
//					need for a background layer.  All of the other layers 
//					should have the transparent flag set, otherwise the 
//					first layer will not be visible.  The exception to 
//					this is if you have more than one background layer 
//					and you only set the show flag for one or the other. 
//******************************************************************* 
 
//******************************************************************* 
//  FUNCTION:   -	CLayeredBitmapCtrl 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	Default constructor. 
//******************************************************************* 
CLayeredBitmapCtrl::CLayeredBitmapCtrl() 
{ 
	m_bShowToolTips			= false; 
	m_bToolTipsInitialized	= false; 
	m_bHideTrackingToolTip	= false; 
 
	m_bUseSysColor			= false; 
 
	// Use the default color of black for the control's background. 
	m_colCtrlBG				= RGB( 0, 0, 0 ); 
 
	// First, assume that the control is on a dialog. 
	m_bIsParentDlg			= true; 
 
	m_vecLayerInfo.clear(); 
	m_strToolTip.Empty(); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	~CLayeredBitmapCtrl 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	Destructor.  Frees all of the memory allocated by 
//					the vector the tool tip string. 
//******************************************************************* 
CLayeredBitmapCtrl::~CLayeredBitmapCtrl() 
{ 
	m_vecLayerInfo.clear(); 
	m_strToolTip.Empty(); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	Create 
//  RETURNS:    -	TRUE - if the control was created, otherwise FALSE. 
//  PARAMETERS: -	dwExStyle - Extended window styles. 
//					rect - Control's bounding rectangle. 
//					pParentWnd - Parent window of this control. 
//					nID - Control's unique identifier. 
//  COMMENTS:   -	This function allows the control to be created 
//					dynamically. 
//******************************************************************* 
BOOL CLayeredBitmapCtrl::Create( DWORD dwExStyle, const RECT &rect, CWnd *pParentWnd, UINT nID ) 
{ 
	DWORD dwStyle = WS_CHILD | WS_VISIBLE; 
 
	return CStatic::CreateEx( dwExStyle, NULL, NULL, dwStyle, rect, pParentWnd, nID ); 
} 
 
// Operations 
//******************************************************************* 
//  FUNCTION:   -	InitToolTips 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	Initializes the tool tip for this layered static 
//					control. 
//******************************************************************* 
void CLayeredBitmapCtrl::InitToolTips() 
{ 
	if ( m_bToolTipsInitialized ) 
	{ 
		// Don't try to initialize the tool tip twice. 
		return; 
	} 
 
	// Create and activate the tool tip. 
	m_toolTip.Create( this ); 
	m_toolTip.Activate( TRUE ); 
	 
	// Add the text callback to the tool tip. 
	m_toolTip.AddTool( this, LPSTR_TEXTCALLBACK ); 
 
	// Don't delay when showing the tool tip. 
	m_toolTip.SetDelayTime( 0 ); 
 
	// Indicate that the tool tip has been initialized. 
	m_bToolTipsInitialized = true; 
	return; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	ShowToolTips 
//  RETURNS:    -	 
//  PARAMETERS: -	bShow - true = show tool tips, false = hide. 
//  COMMENTS:	-	Specifies whether or not to display tool tips. 
//******************************************************************* 
void CLayeredBitmapCtrl::ShowToolTips( bool bShow ) 
{ 
	m_bShowToolTips = bShow; 
 
	if ( m_bShowToolTips ) 
	{ 
		// Make sure the tool tips are initialized. 
		InitToolTips(); 
	} 
 
	return; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	ToolTipsEnabled 
//  RETURNS:    -	true - if tool tips are enabled. 
//					Otherwise, false. 
//  PARAMETERS: -	 
//  COMMENTS:	-	Indicates if tool tips are enabled. 
//******************************************************************* 
bool CLayeredBitmapCtrl::ToolTipsEnabled() const 
{ 
	return m_bShowToolTips; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	UseSysColor 
//  RETURNS:    -	 
//  PARAMETERS: -	bUseSysColor - true = use system color and reflect 
//						system color changes, false = use default or 
//						user specified color. 
//					bRedraw - true repaints the control to reflect 
//						any changes, false = don't redraw. 
//  COMMENTS:   -	Specifies whether or not to use the system color 
//					for the background of the control. 
//******************************************************************* 
void CLayeredBitmapCtrl::UseSysColor( bool bUseSysColor, bool bRedraw /* = false */ ) 
{ 
	m_bUseSysColor = bUseSysColor; 
 
	if ( bUseSysColor ) 
	{ 
		CWnd *pParent = GetParent(); 
		 
		if ( NULL != pParent ) 
		{ 
			// Determine if the parent window is a dialog, so that we can use the right color. 
			if ( pParent->IsKindOf( RUNTIME_CLASS(CDialog)) ) 
			{ 
				m_bIsParentDlg = true; 
			} 
			else 
			{ 
				m_bIsParentDlg = false; 
			} 
		} 
 
		// Set the control's background color to the system color. 
		m_colCtrlBG = ::GetSysColor( (true == m_bIsParentDlg) ? COLOR_BTNFACE : COLOR_WINDOW ); 
	} 
	else 
	{ 
		// Set the color to black as the default. 
		m_colCtrlBG = RGB( 0, 0, 0 ); 
	} 
 
	if ( bRedraw ) 
	{ 
		// Redraw the control to reflect any changes to the color. 
		ShowVisibleLayers(); 
	} 
 
	return; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	UsingSysColor 
//  RETURNS:    -	true - if the control is using the system color, 
//						otherwise false. 
//  PARAMETERS: -	 
//  COMMENTS:   -	Indicates if the control is using the system color. 
//******************************************************************* 
bool CLayeredBitmapCtrl::UsingSysColor() const 
{ 
	return m_bUseSysColor; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetCtrlBGColor 
//  RETURNS:    -	 
//  PARAMETERS: -	colCtrlBG - Color to use as the background for the 
//						control. 
//					bRedraw - true repaints the control to reflect 
//						any changes, false = don't redraw. 
//  COMMENTS:   -	Allows the user to change the background color of 
//					the control. 
//******************************************************************* 
void CLayeredBitmapCtrl::SetCtrlBGColor( COLORREF colCtrlBG, bool bRedraw /* = false */ ) 
{ 
	m_colCtrlBG		= colCtrlBG; 
	m_bUseSysColor	= false; 
 
	if ( bRedraw ) 
	{ 
		// Redraw the control to reflect any changes to the color. 
		ShowVisibleLayers(); 
	} 
 
	return; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetCtrlBGColor 
//  RETURNS:    -	Current background color for the control. 
//  PARAMETERS: -	 
//  COMMENTS:   -	Gets the current background color of the control. 
//******************************************************************* 
COLORREF CLayeredBitmapCtrl::GetCtrlBGColor() 
{ 
	return m_colCtrlBG; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	AddLayer 
//  RETURNS:    -	true - if the layer was added to the vector. 
//					false - if the layer already exists in the vector. 
//  PARAMETERS: -	layerInfo - layer object to be added to the  
//					vector of layer objects. 
//  COMMENTS:	-	Adds a layer object to the vector. 
//******************************************************************* 
bool CLayeredBitmapCtrl::AddLayer( CLayerInfo &layerInfo ) 
{ 
	bool bResult	= false; 
	int nLayerIndex = m_vecLayerInfo.size(); 
 
	// See if a layer object already exists with this layer ID. 
	if ( NULL == FindLayer( layerInfo.m_nLayerID ) ) 
	{ 
		// Automatically set the layer index. 
		layerInfo.m_nLayerIndex = nLayerIndex; 
 
		// Add the layer object to the vector. 
		m_vecLayerInfo.push_back( layerInfo ); 
 
		bResult = true; 
	} 
	 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	RemoveLayer 
//  RETURNS:    -	true - if the layer exists and was removed. 
//					false - if the layer wasn't found. 
//  PARAMETERS: -	nLayerID - Layer ID to be removed from the vector. 
//  COMMENTS:	-	Removes a layer from the vector. 
//******************************************************************* 
bool CLayeredBitmapCtrl::RemoveLayer( int nLayerID ) 
{ 
	bool bResult	= false; 
	vector::iterator	layerIter; 
 
	for ( layerIter = m_vecLayerInfo.begin(); layerIter < m_vecLayerInfo.end(); ++layerIter ) 
	{ 
		// Does the layer ID match? 
		if ( layerIter->m_nLayerID == nLayerID ) 
		{ 
			// Remove this layer. 
			m_vecLayerInfo.erase( layerIter ); 
 
			// Indicate that the layer object has been removed. 
			bResult = true; 
 
			// We removed the layer, so get out of the loop. 
			break; 
		} 
	} 
 
	// Don't worry about the return value from the Reindex function because this may have been 
	// the only layer. 
	ReindexLayers(); 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	ReindexLayers 
//  RETURNS:    -	true - if the layer objects are re-indexed. 
//					false - if their are no layer objects. 
//  PARAMETERS: -	 
//  COMMENTS:   -	Allows the layer objects to be re-indexed based 
//					on their position in the vector.  This is necessary 
//					if layers have been removed. 
//******************************************************************* 
bool CLayeredBitmapCtrl::ReindexLayers() 
{ 
	vector::iterator	layerIter; 
	int nLayerIndex = 0; 
 
	if ( m_vecLayerInfo.empty() ) 
	{ 
		return false; 
	} 
 
	// Re-index the layers. 
	for ( layerIter = m_vecLayerInfo.begin(); layerIter < m_vecLayerInfo.end(); ++layerIter ) 
	{ 
		layerIter->m_nLayerIndex = nLayerIndex; 
		nLayerIndex++; 
	} 
 
	return true; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SwapLayers 
//  RETURNS:    -	true - if the layers were swapped. 
//					false - if at least one of the layers could not be found. 
//  PARAMETERS: -	nFirstLayerID - Layer ID of the first layer object. 
//					nSecondLayerID - Layer ID of the first layer object. 
//  COMMENTS:   -	Swaps the indices of two layer objects. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SwapLayers( int nFirstLayerID, int nSecondLayerID ) 
{ 
	bool bResult					= false; 
	int nTmpFirstLayerIndex			= 0; 
	CLayerInfo *pFirstLayerInfo		= NULL; 
	CLayerInfo *pSecondLayerInfo	= NULL; 
 
	// Attempt to locate the first layer object. 
	if ( NULL != (pFirstLayerInfo = FindLayer( nFirstLayerID )) ) 
	{ 
		// Attempt to locate the second layer object. 
		if ( NULL != (pSecondLayerInfo = FindLayer( nSecondLayerID )) ) 
		{ 
			// Swap the layer indices. 
			nTmpFirstLayerIndex				= pFirstLayerInfo->m_nLayerIndex; 
			pFirstLayerInfo->m_nLayerIndex	= pSecondLayerInfo->m_nLayerIndex; 
			pSecondLayerInfo->m_nLayerIndex = nTmpFirstLayerIndex; 
 
			// Re-sort the layers. 
			bResult	= SortLayers(); 
		} 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	MakeTopLayer 
//  RETURNS:    -	true - if the layer was found and moved to the top. 
//					false - if the layer was not found. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	Moves the specified layer to the top of all other 
//					layers. 
//******************************************************************* 
bool CLayeredBitmapCtrl::MakeTopLayer( int nLayerID ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Since the vector size is 1-based we will set this layer's index just passed the 
		// last index. 
		pLayerInfo->m_nLayerIndex = (int)m_vecLayerInfo.size(); 
 
		// Now, re-sort and then re-index the vector to normalize the indices. 
		if ( SortLayers() ) 
		{ 
			bResult = ReindexLayers(); 
		} 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerVisibility 
//  RETURNS:    -	true - if the layer was found and the flag was set. 
//					false - if the layer was not found. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//					bVisible - true = displayed / false = hidden. 
//  COMMENTS:	-	Indicates that this layer will be displayed or 
//					hidden. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerVisibility( int nLayerID, bool bVisible ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the m_bVisible flag to indicate that this layer will be displayed or hidden. 
		pLayerInfo->m_bVisible = bVisible; 
		bResult				= true; 
	} 
	 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerTransparency 
//  RETURNS:    -	true - if the layer was found. 
//					false - if the layer was not found. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//					bTransparent - flag that indicates whether this layer 
//						contains a transparent color.  (Default is false). 
//					colTransparent - Transparent color.  (Default is black). 
//  COMMENTS:	-	Sets the layer's transparency state, as well as the  
//					transparent color if necessary. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerTransparency( int nLayerID, bool bTransparent /*= false */, 
	COLORREF colTransparent /*= RGB(0, 0, 0) */) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the layer's transparent flag and transparent color. 
		pLayerInfo->m_bTransparent		= bTransparent; 
		pLayerInfo->m_colTransparent	= colTransparent; 
		bResult							= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerTransparency 
//  RETURNS:    -	true - if the layer was found. 
//					false - if the layer was not found. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//					bTransparent - flag that indicates whether this layer 
//						contains a transparent color. 
//					ptTransparentPixel - indicates the location of the 
//						transparent colored pixel within the bitmap. 
//  COMMENTS:	-	This is another function for setting the transparency 
//					of a layer object.  The difference is that this 
//					function allows you to choose a pixel location 
//					within the bitmap, to indicate the transparent color. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerTransparency( int nLayerID, bool bTransparent, 
	CPoint &ptTransparentPixel ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the layer's transparent flag and location of the transparent 
		// colored pixel within the bitmap. 
		pLayerInfo->m_bTransparent			= bTransparent; 
		pLayerInfo->m_ptTransparentPixel.x	= ptTransparentPixel.x; 
		pLayerInfo->m_ptTransparentPixel.y	= ptTransparentPixel.y; 
 
		if ( true == bTransparent ) 
		{ 
			// Get the transparent color from the bitmap, then set the layer's transparent color. 
			pLayerInfo->m_colTransparent	=  
				CLayerInfo::GetColorFromBitmap( pLayerInfo->m_ptTransparentPixel, pLayerInfo->m_bmp ); 
		} 
 
		bResult								= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerTransparency 
//  RETURNS:    -	true - if the layer is set to transparent. 
//					false - if the layer is not transparent or not found. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	Indicates if the layer is transparent or not. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerTransparency( int nLayerID ) 
{ 
	bool bTransparent		= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the transparent flag if it is found. 
		bTransparent		= pLayerInfo->m_bTransparent; 
	} 
	 
	return bTransparent; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerTransparencyColor 
//  RETURNS:    -	transparent color. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	Gets the transparent color of the layer object. 
//******************************************************************* 
COLORREF CLayeredBitmapCtrl::GetLayerTransparencyColor( int nLayerID ) 
{ 
	// Default the transparent color to black. 
	COLORREF colTransparent = RGB( 0, 0, 0 ); 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the transparent color if it is found. 
		colTransparent		= pLayerInfo->m_colTransparent; 
	} 
 
	return colTransparent; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerDescription 
//  RETURNS:    -	true - if the layer description is changed. 
//					false - if the layer is not found. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					strLayerDesc - String containing the new description 
//						for a layer object.. 
//  COMMENTS:	-	Sets the description of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerDescription( int nLayerID, CString &strLayerDesc ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the m_strLayerDesc if it is found. 
		pLayerInfo->m_strLayerDesc	= strLayerDesc; 
 
		bResult						= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerDescription 
//  RETURNS:    -	true - if the layer description is retrieved. 
//					false - if the layer is not found. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					strLayerDesc - String containing the layer's description. 
//  COMMENTS:	-	Gets the description of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerDescription( int nLayerID, CString &strLayerDesc ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the m_strLayerDesc if it is found. 
		strLayerDesc		= pLayerInfo->m_strLayerDesc; 
 
		bResult				= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerTracking 
//  RETURNS:    -	true - if the layer's tracking flag is set. 
//					false - if the layer is not found. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//  COMMENTS:	-	Sets the tracking enabled flag of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerTracking( int nLayerID, bool bTrackingEnabled ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the m_bTrackingEnabled if it is found. 
		pLayerInfo->m_bTrackingEnabled	= bTrackingEnabled; 
 
		bResult							= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerTracking 
//  RETURNS:    -	true - if tracking is enabled, false otherwise. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//  COMMENTS:	-	Gets the tracking enabled flag of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerTracking( int nLayerID ) 
{ 
	bool bTrackingEnabled	= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the m_bTrackingEnabled if it is found. 
		bTrackingEnabled	= pLayerInfo->m_bTrackingEnabled; 
	} 
 
	return bTrackingEnabled; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerShowOnTopWhileTracking 
//  RETURNS:    -	true - if the layer's show on top while tracking flag is set. 
//					false - if the layer is not found. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//  COMMENTS:	-	Sets the show on top while tracking flag of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerShowOnTopWhileTracking( int nLayerID, bool bShowOnTopWhileTracking ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the m_bShowOnTopWhileTracking if it is found. 
		pLayerInfo->m_bShowOnTopWhileTracking	= bShowOnTopWhileTracking; 
 
		bResult									= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerShowOnTopWhileTracking 
//  RETURNS:    -	true - if the layer will be displayed above all 
//					visible layers while it is being tracked. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//  COMMENTS:	-	Gets the show on top while tracking flag of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerShowOnTopWhileTracking( int nLayerID ) 
{ 
	bool bShowOnTopWhileTracking	= false; 
	CLayerInfo *pLayerInfo			= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the m_bShowOnTopWhileTracking if it is found. 
		bShowOnTopWhileTracking	= pLayerInfo->m_bShowOnTopWhileTracking; 
	} 
 
	return bShowOnTopWhileTracking; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerLocation 
//  RETURNS:    -	true - if the layer was found, false otherwise. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					ptNewLocation - New location for the layer object. 
//  COMMENTS:	-	Sets the upper-left location point of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerLocation( int nLayerID, const CPoint &ptNewLocation ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
	int nOffsetX			= 0; 
	int nOffsetY			= 0; 
	CPoint ptCurrentLocation; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Save the current location. 
		ptCurrentLocation.x		= pLayerInfo->m_ptLocation.x; 
		ptCurrentLocation.y		= pLayerInfo->m_ptLocation.y; 
 
		// Calculate the region's X offset. 
		if ( ptNewLocation.x >= ptCurrentLocation.x ) 
		{ 
			nOffsetX = ptNewLocation.x - ptCurrentLocation.x; 
		} 
		else 
		{ 
			// If the new location is moving left, make the offset negative. 
			nOffsetX = ptCurrentLocation.x - ptNewLocation.x; 
			nOffsetX *= -1; 
		} 
 
		// Adjust the layer's X location based on the offset. 
		pLayerInfo->m_ptLocation.x		+= nOffsetX; 
 
		// Calculate the region's Y offset. 
		if ( ptNewLocation.y >= ptCurrentLocation.y ) 
		{ 
			nOffsetY = ptNewLocation.y - ptCurrentLocation.y; 
		} 
		else 
		{ 
			// If the new location is moving up, make the offset negative. 
			nOffsetY = ptCurrentLocation.y - ptNewLocation.y; 
			nOffsetY *= -1; 
		} 
 
		// Adjust the layer's Y location based on the offset. 
		pLayerInfo->m_ptLocation.y		+= nOffsetY; 
 
		if ( NULL != pLayerInfo->m_rgn.GetSafeHandle() ) 
		{ 
			// Update the region if it exists. 
			pLayerInfo->m_rgn.OffsetRgn( nOffsetX, nOffsetY ); 
		} 
 
		bResult				= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerLocation 
//  RETURNS:    -	true - if the layer was found, false otherwise. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					ptLocation - Current location for the layer object. 
//  COMMENTS:	-	Gets the upper-left location point of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerLocation( int nLayerID, CPoint &ptLocation ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the m_ptLocation if it is found. 
		ptLocation.x		= pLayerInfo->m_ptLocation.x; 
		ptLocation.y		= pLayerInfo->m_ptLocation.y; 
 
		bResult				= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerSize 
//  RETURNS:    -	true - if the layer was found, false otherwise. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					size - Size of the layer object, (bitmap dimensions). 
//  COMMENTS:	-	Gets the width and height of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerSize( int nLayerID, CSize &size ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the size if it is found. 
		size				= pLayerInfo->m_bmp.GetBitmapDimension(); 
 
		bResult				= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerEnableFocusRectangle 
//  RETURNS:    -	true - if the layer's focus rectangle flag is set. 
//					false - if the layer is not found. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					bEnabled - Indicates if the focus rectangle should be 
//						displayed for this layer. 
//  COMMENTS:	-	Sets the focus rectangle enabled flag of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerEnableFocusRectangle( int nLayerID, bool bEnabled ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the m_bFocusRectangleEnabled if it is found. 
		pLayerInfo->m_bFocusRectangleEnabled	= bEnabled; 
 
		bResult									= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerEnableFocusRectangle 
//  RETURNS:    -	true - if the layer can display a focus rectangle, false otherwise. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//  COMMENTS:	-	Gets the focus rectangle enabled flag of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::GetLayerEnableFocusRectangle( int nLayerID ) 
{ 
	bool bFocusRectangleEnabled	= false; 
	CLayerInfo *pLayerInfo		= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the m_bFocusRectangleEnabled if it is found. 
		bFocusRectangleEnabled	= pLayerInfo->m_bFocusRectangleEnabled; 
	} 
 
	return bFocusRectangleEnabled; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SetLayerFocusRectangleColor 
//  RETURNS:    -	true - if the layer's focus rectangle color is set. 
//					false - if the layer is not found. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//					colFocusRectangle - Indicates the color of the focus 
//					rectangle for this layer. 
//  COMMENTS:	-	Sets the focus rectangle color of a layer object. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SetLayerFocusRectangleColor( int nLayerID, COLORREF colFocusRectangle ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Set the m_colFocusRectangle if it is found. 
		pLayerInfo->m_colFocusRectangle	= colFocusRectangle; 
 
		bResult							= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerFocusRectangleColor 
//  RETURNS:    -	color of the layer's focus rectangle. 
//  PARAMETERS: -	nLayerID - Layer ID of a layer object. 
//  COMMENTS:   -	Gets a the color of the focus rectangle for a 
//					layer. 
//******************************************************************* 
COLORREF CLayeredBitmapCtrl::GetLayerFocusRectangleColor( int nLayerID ) 
{ 
	COLORREF colFocusRectangle	= RGB( 255, 0, 0 ); 
	CLayerInfo *pLayerInfo		= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the m_colFocusRectangle if it is found. 
		colFocusRectangle	= pLayerInfo->m_colFocusRectangle; 
	} 
 
	return colFocusRectangle; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	GetLayerIndex 
//  RETURNS:    -	-1 - if the layer was not found. 
//					Otherwise, the layer index of the layer object. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	Retrieves the layer index of the layer object 
//					based on the layer ID. 
//******************************************************************* 
int CLayeredBitmapCtrl::GetLayerIndex( int nLayerID ) 
{ 
	int nLayerIndex			= -1; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	// Attempt to locate the layer object. 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		// Get the layer index for this layer object. 
		nLayerIndex	= pLayerInfo->m_nLayerIndex; 
	} 
 
	return nLayerIndex; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CalculateCenterOffset 
//  RETURNS:    -	true - if the layer was found. 
//					false - if the layer could not be found. 
//  PARAMETERS: -	pLayerInfo - Pointer to the layer object to be 
//					modified. 
//  COMMENTS:	-	This function calculates the center offset for 
//					a layer, based on the static control's client 
//					rect. 
//******************************************************************* 
bool CLayeredBitmapCtrl::CalculateCenterOffset( CLayerInfo *pLayerInfo ) 
{ 
	bool bResult			= false; 
	BITMAP bm; 
	CRect rect; 
	CPoint ptCenter; 
 
	// Get the static control's client rect. 
	GetClientRect( &rect ); 
 
	// Get the center point of the client rect. 
	ptCenter = rect.CenterPoint(); 
 
	if ( pLayerInfo->m_bmp.GetBitmap( &bm ) ) 
	{ 
		pLayerInfo->m_ptLocation.x	= ptCenter.x - (bm.bmWidth / 2); 
		pLayerInfo->m_ptLocation.y	= ptCenter.y - (bm.bmHeight / 2); 
		bResult						= true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CalculateCenterOffset 
//  RETURNS:    -	true - if the layer was found. 
//					false - if the layer could not be found. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	This function calculates the center offset for 
//					a layer, based on the static control's client 
//					rect. 
// 
//					NOTE: This version of the function can only be used 
//					if the layer has already been added to the vector. 
//					Call the other version of this function if the layer 
//					has not been added yet. 
//******************************************************************* 
bool CLayeredBitmapCtrl::CalculateCenterOffset( int nLayerID ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		bResult = CalculateCenterOffset( pLayerInfo ); 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CreateNonTransparentRgn 
//  RETURNS:    -	true - if region was created. 
//					false - if the pLayerInfo was NULL or unable to 
//						retrieve the bitmap structure. 
//  PARAMETERS: -	pLayerInfo - Pointer to the layer object to be 
//					modified. 
//  COMMENTS:	-	Creates a region composed of the non-transparent 
//					pixels of the layer's bitmap. 
// 
//					NOTE: This function uses a modified version of a 
//					function found in David Forrester article about 
//					a CBitmapDialog which makes a window region based 
//					on a bitmap. 
//******************************************************************* 
bool CLayeredBitmapCtrl::CreateNonTransparentRgn( CLayerInfo *pLayerInfo ) 
{ 
	CDC imageDC; 
	CBitmap *pOldBmp = NULL; 
	BITMAP bm; 
 
	// Does the layer actually exist? 
	if ( NULL == pLayerInfo ) 
	{ 
		return false; 
	} 
	 
	// Make sure that there really is a bitmap. 
	if ( NULL == pLayerInfo->m_bmp.GetSafeHandle() ) 
	{ 
		return false; 
	} 
 
	if ( 0 == pLayerInfo->m_bmp.GetBitmap( &bm ) ) 
	{ 
		// Return, if unable to retrieve the bitmap structure. 
		return false; 
	} 
 
	// Create a device context to get the pixel information from the bitmap. 
	imageDC.CreateCompatibleDC( NULL ); 
 
	// Select the layer's bitmap into the device context. 
	pOldBmp = imageDC.SelectObject( &pLayerInfo->m_bmp ); 
 
	// Set this flag to true because we are creating a region for this layer. 
	pLayerInfo->m_bUseRgn = true; 
 
	// First make sure that we delete any existing region. 
	pLayerInfo->m_rgn.DeleteObject(); 
 
	// Create an empty region that we will add on too. 
	pLayerInfo->m_rgn.CreateRectRgn( 0, 0, 0, 0 ); 
 
	// Make sure we have the transparent color. 
	if ( pLayerInfo->m_ptTransparentPixel.x	> -1 ) 
	{ 
		// Get the transparent color from the bitmap at the specified location. 
		pLayerInfo->m_colTransparent =  
			imageDC.GetPixel( pLayerInfo->m_ptTransparentPixel.x, pLayerInfo->m_ptTransparentPixel.y ); 
	} 
 
	// Use RLE (run-length) style because it goes faster. 
	// Row start is where the first non-transparent pixel is found.  Once 
	// a transparent pixel is found, a line region is created. 
	// Then nRowStart becomes the next non-transparent pixel. 
	int nRowStart; 
 
	// Go through all rows 
	for ( int y = 0; y < bm.bmHeight; y++ ) 
	{ 
		// Start looking at the beginning 
		nRowStart = 0; 
 
		// Go through all columns 
		for ( int x = 0; x < bm.bmWidth; x++ ) 
		{ 
			// If this pixel is transparent 
			if ( pLayerInfo->m_colTransparent == imageDC.GetPixel( x, y ) ) 
			{ 
				if ( nRowStart == x ) 
				{ 
					// If we haven't found a non-transparent pixel yet, keep searching 
					nRowStart++; 
				} 
				else 
				{ 
					// We have found the start (nRowStart) and end (x) of 
					// a non-transparent line.  Add it to the region. 
					CRgn rgnAdd; 
					rgnAdd.CreateRectRgn( nRowStart, y, x, y + 1 ); 
					pLayerInfo->m_rgn.CombineRgn( &pLayerInfo->m_rgn, &rgnAdd, RGN_OR ); 
					nRowStart = x + 1; 
				} 
			} 
		} 
 
		// If the last pixel is still non-transparent, make a region. 
		if ( nRowStart != x ) 
		{ 
			CRgn rgnAdd; 
			rgnAdd.CreateRectRgn( nRowStart, y, x, y + 1 ); 
			pLayerInfo->m_rgn.CombineRgn( &pLayerInfo->m_rgn, &rgnAdd, RGN_OR ); 
		} 
	} 
 
	// Cleanup 
	imageDC.SelectObject( pOldBmp ); 
 
	return true; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CreateNonTransparentRgn 
//  RETURNS:    -	true - if region was created. 
//					false - if the pLayerInfo was NULL or unable to 
//						retrieve the bitmap structure. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	Creates a region composed of the non-transparent 
//					pixels of the layer's bitmap. 
// 
//					NOTE: This version of the function can only be used 
//					if the layer has already been added to the vector. 
//					Call the other version of this function if the layer 
//					has not been added yet. 
//******************************************************************* 
bool CLayeredBitmapCtrl::CreateNonTransparentRgn( int nLayerID ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo	= NULL; 
 
	if ( NULL != (pLayerInfo = FindLayer( nLayerID )) ) 
	{ 
		bResult = CreateNonTransparentRgn( pLayerInfo ); 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	DoLayersIntersect 
//  RETURNS:    -	true - if the layers intersect. 
//					false - if at least one of the layers is not visible 
//						or the layers do not intersect at all. 
//  PARAMETERS: -	pLayerInfo1 - Pointer to the first layer object. 
//					pLayerInfo2 - Pointer to the second layer object. 
//  COMMENTS:   -	Determines if the bounding rectangle for two layers 
//					intersect. 
//******************************************************************* 
bool CLayeredBitmapCtrl::DoLayersIntersect( CLayerInfo *pLayerInfo1, CLayerInfo *pLayerInfo2, 
	CRect *pRectIntersect /* = NULL */ ) 
{ 
	bool bResult = false; 
	CSize sizeLayer1, sizeLayer2; 
	CRect rectLayer1, rectLayer2, rectTmp( 0, 0, 0, 0 ); 
 
	// Make sure that the bitmaps are valid. 
	if ( (NULL == pLayerInfo1->m_bmp.GetSafeHandle()) || (NULL == pLayerInfo2->m_bmp.GetSafeHandle()) ) 
	{ 
		return bResult; 
	} 
 
	// Calculate layer1's actual location within the control. 
	sizeLayer1			= pLayerInfo1->m_bmp.GetBitmapDimension(); 
	rectLayer1.left		= pLayerInfo1->m_ptLocation.x; 
	rectLayer1.top		= pLayerInfo1->m_ptLocation.y; 
	rectLayer1.right	= rectLayer1.left + sizeLayer1.cx; 
	rectLayer1.bottom	= rectLayer1.top + sizeLayer1.cy; 
 
	// Calculate layer2's actual location within the control. 
	sizeLayer2			= pLayerInfo2->m_bmp.GetBitmapDimension(); 
	rectLayer2.left		= pLayerInfo2->m_ptLocation.x; 
	rectLayer2.top		= pLayerInfo2->m_ptLocation.y; 
	rectLayer2.right	= rectLayer2.left + sizeLayer2.cx; 
	rectLayer2.bottom	= rectLayer2.top + sizeLayer2.cy; 
 
	// Normalize the rectangles first. 
	rectLayer1.NormalizeRect(); 
	rectLayer2.NormalizeRect(); 
 
	// Get the intersecting rectangle, if one exists. 
	if ( 0 != rectTmp.IntersectRect( &rectLayer1, &rectLayer2 ) ) 
	{ 
		// Set the flag to true since the rectangles intersect. 
		bResult = true; 
	} 
 
	if ( NULL != pRectIntersect ) 
	{ 
		pRectIntersect->CopyRect( &rectTmp ); 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	DoLayersIntersect 
//  RETURNS:    -	true - if the layers intersect. 
//					false - if unable to retrieve a pointer to both of 
//						the layers, at least one of the layers is not visible 
//						or the layers do not intersect at all. 
//  PARAMETERS: -	nLayerID1 - Layer ID of the first layer object. 
//					nLayerID2 - Layer ID of the second layer object. 
//  COMMENTS:   -	Determines if the bounding rectangle for two layers 
//					intersect. 
// 
//					NOTE: This version of the function can only be used 
//					if the layer has already been added to the vector. 
//					Call the other version of this function if the layer 
//					has not been added yet. 
//******************************************************************* 
bool CLayeredBitmapCtrl::DoLayersIntersect( int nLayerID1, int nLayerID2,  
	CRect *pRectIntersect /* = NULL */ ) 
{ 
	bool bResult			= false; 
	CLayerInfo *pLayerInfo1	= NULL; 
	CLayerInfo *pLayerInfo2	= NULL; 
	CRect rectTmp( 0, 0, 0, 0 ); 
 
	if ( NULL != (pLayerInfo1 = FindLayer( nLayerID1 )) ) 
	{ 
		if ( NULL != (pLayerInfo2 = FindLayer( nLayerID2 )) ) 
		{ 
			bResult = DoLayersIntersect( pLayerInfo1, pLayerInfo2, &rectTmp ); 
		} 
	} 
 
	if ( NULL != pRectIntersect ) 
	{ 
		pRectIntersect->CopyRect( &rectTmp ); 
	} 
 
	return bResult; 
 
} 
 
//******************************************************************* 
//  FUNCTION:   -	SortLayers 
//  RETURNS:    -	true - if the vector is not empty. 
//					false - if the vector is empty. 
//  PARAMETERS: -	 
//  COMMENTS:	-	Sorts the layer objects based on the layer index. 
//					Note: There are no checks to make sure that there 
//					is only one layer object per index, otherwise it 
//					would be difficult to change the layer index because 
//					it would already exist. 
//******************************************************************* 
bool CLayeredBitmapCtrl::SortLayers() 
{ 
	bool bResult	= false; 
 
	// Make sure that at least one layer object exists in the vector. 
	if ( !m_vecLayerInfo.empty() ) 
	{ 
		// Sort the layer objects based on their layer index. 
		sort( m_vecLayerInfo.begin(), m_vecLayerInfo.end() ); 
		bResult = true; 
	} 
 
	return bResult; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	FindLayer 
//  RETURNS:    -	NULL - if the layer object was not found. 
//					Otherwise, a pointer to the layer object that contains 
//					the matching layer ID. 
//  PARAMETERS: -	nLayerID - Layer ID of the layer object. 
//  COMMENTS:	-	Attempts to locate a layer object within the vector 
//					that contains a matching layer ID. 
// 
//					NOTE: This function has been modified to use  
//					reinterpret_cast, because of a compiler error with 
//					VC++ 7.0 .NET (Thanks again Shilps for letting 
//					me know about the error). 
//******************************************************************* 
CLayerInfo *CLayeredBitmapCtrl::FindLayer( int nLayerID ) 
{ 
	CLayerInfo *pLayerInfo = NULL; 
	int nIndex = 0; 
 
	// Search through the vector for a matching layer ID. 
	for ( nIndex = 0; nIndex < (int)m_vecLayerInfo.size(); nIndex++ ) 
	{ 
		if ( m_vecLayerInfo[nIndex].m_nLayerID == nLayerID ) 
		{ 
			// If we found a match, stop looking. 
			pLayerInfo = reinterpret_cast(&m_vecLayerInfo[nIndex]); 
			break; 
		} 
	} 
	 
	return pLayerInfo; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CombineLayers 
//  RETURNS:    -	true - if layers exist. 
//					false - if there are no layers. 
//  PARAMETERS: -	 
//  COMMENTS:	-	Combines all of the visible layer into one bitmap 
//					the will be displayed within the OnPaint function. 
//******************************************************************* 
bool CLayeredBitmapCtrl::CombineLayers() 
{ 
	CDC *pDC					= NULL; 
	 
	CRect rectCtrl; 
	CSize sizeCtrl, sizeLayer; 
 
	int			nIndex			= 0; 
	CLayerInfo	*pCurrentLayer	= NULL; 
 
	// Get a pointer to this control's device context. 
	pDC = GetDC(); 
 
	// Get the client rect from this static control. 
	GetClientRect( &rectCtrl ); 
 
	// Set the sizeCtrl equal to the width and height of the static control's client area. 
	sizeCtrl = CSize::CSize( rectCtrl.Width(), rectCtrl.Height() ); 
 
	// Make sure that the combined bitmap is empty. 
	m_bmpCombined.DeleteObject(); 
 
	// Create the bitmap that will be contain all of the visible layers. 
	m_bmpCombined.CreateCompatibleBitmap( pDC, sizeCtrl.cx, sizeCtrl.cy ); 
	m_bmpCombined.SetBitmapDimension( sizeCtrl.cx, sizeCtrl.cy ); 
 
	// Set the background color of the bitmap. 
	CDC tmpDC; 
	CBitmap *pOldBmp	= NULL; 
 
	tmpDC.CreateCompatibleDC( pDC ); 
	pOldBmp = tmpDC.SelectObject( &m_bmpCombined ); 
 
	// Fill the bitmap with the background color. 
	tmpDC.FillSolidRect( 0, 0, rectCtrl.Width(), rectCtrl.Height(), m_colCtrlBG ); 
 
	// Cleanup. 
	tmpDC.SelectObject( pOldBmp ); 
 
	if ( !m_vecLayerInfo.empty() ) 
	{ 
		// Loop through each of the layers. 
		for ( nIndex = 0; nIndex < m_vecLayerInfo.size(); nIndex++ ) 
		{ 
			pCurrentLayer	= reinterpret_cast(&m_vecLayerInfo[nIndex]); 
 
			// Only visible layers will be added to the combined bitmap. 
			if ( pCurrentLayer->m_bVisible ) 
			{ 
				DrawLayerOnBitmap( &m_bmpCombined, pCurrentLayer ); 
			} 
		} 
	} 
 
	// Final cleanup. 
	ReleaseDC( pDC ); 
 
	return true; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	DrawLayerOnBitmap 
//  RETURNS:    -	true - if the layer is drawn 
//					false - if either parameter is NULL. 
//  PARAMETERS: -	pBmpBackground - An existing bitmap. 
//					pLayerInfo - Pointer to the layer object to be drawn. 
//  COMMENTS:	-	Draws the specified layer onto an existing bitmap. 
//******************************************************************* 
bool CLayeredBitmapCtrl::DrawLayerOnBitmap( CBitmap *pBmpBackground, CLayerInfo *pLayerInfo ) 
{ 
	CDC *pDC = NULL; 
	CDC srcDC, destDC, maskDC, compositeDC, overlayDC; 
	 
	CRect rectCtrl; 
	CSize sizeCtrl, sizeLayer; 
 
	CBitmap *pOldDestBmp = NULL, *pOldSrcBmp = NULL; 
	CBitmap bmpMask, *pOldMaskBmp = NULL; 
	CBitmap bmpComposite, *pOldCompositeBmp = NULL; 
	CBitmap bmpOverlay, *pOldOverlayBmp = NULL; 
	 
	COLORREF colOld; 
	CPalette *pPalette = NULL; 
 
	if ( (NULL == pBmpBackground) || (NULL == pLayerInfo) ) 
	{ 
		return false; 
	} 
 
	// Don't try to add the layer's bitmap if it doesn't exist. 
	if ( NULL == pLayerInfo->m_bmp.GetSafeHandle() ) 
	{ 
		return false; 
	} 
 
	// Get a pointer to this control's device context. 
	pDC = GetDC(); 
 
	// Create some device contexts for bitmap manipulation. 
	// This DC will contain the original bitmap from each layer object. 
	srcDC.CreateCompatibleDC( NULL ); 
 
	// This DC will contain all of the visible layers. 
	destDC.CreateCompatibleDC( NULL ); 
 
	// These DCs will be used to mask out the transparent color. 
	maskDC.CreateCompatibleDC( NULL ); 
	compositeDC.CreateCompatibleDC( NULL ); 
	overlayDC.CreateCompatibleDC( NULL ); 
 
	// Get the client rect from this static control. 
	GetClientRect( &rectCtrl ); 
 
	// Set the sizeCtrl equal to the width and height of the static control's client area. 
	sizeCtrl = CSize::CSize( rectCtrl.Width(), rectCtrl.Height() ); 
 
	// Select the combined bitmap into the destination device context. 
	pOldDestBmp = destDC.SelectObject( pBmpBackground ); 
 
	// Select the current layer's bitmap into the source device context. 
	pOldSrcBmp = srcDC.SelectObject( &(pLayerInfo->m_bmp) ); 
			 
	// Get the size of the layer's bitmap. 
	sizeLayer = pLayerInfo->m_bmp.GetBitmapDimension(); 
	 
	// Determine if this layer contains a transparent color. 
	if ( pLayerInfo->m_bTransparent ) 
	{ 
		// If a transparent pixel location is specified, get the transparent color from that location. 
		if ( -1 != pLayerInfo->m_ptTransparentPixel.x ) 
		{ 
			// Get the transparent color from the bitmap at the specified location. 
			pLayerInfo->m_colTransparent	= srcDC.GetPixel( pLayerInfo->m_ptTransparentPixel ); 
		} 
 
		// Create the bitmap mask, (black and white). 
		bmpMask.CreateBitmap( sizeCtrl.cx, sizeCtrl.cy, 1, 1, NULL ); 
 
		// The overlay and composite bitmaps will be compatible with the  
		// destination device context (combined bitmap). 
		bmpOverlay.CreateCompatibleBitmap( &destDC, sizeCtrl.cx, sizeCtrl.cy ); 
		bmpComposite.CreateCompatibleBitmap( &destDC, sizeCtrl.cx, sizeCtrl.cy ); 
 
		// Select the bitmaps into the appropriate device context. 
		pOldMaskBmp			= maskDC.SelectObject( &bmpMask ); 
		pOldOverlayBmp		= overlayDC.SelectObject( &bmpOverlay ); 
		pOldCompositeBmp	= compositeDC.SelectObject( &bmpComposite ); 
 
		// Set the background color to the transparent color for the source layer's bitmap. 
		colOld = srcDC.SetBkColor( pLayerInfo->m_colTransparent ); 
 
		// Setting the stretch blt mode to COLORONCOLOR removes the transparent lines of pixels.  
		maskDC.SetStretchBltMode( COLORONCOLOR ); 
 
		// Copy the layer's inverted bitmap to the mask device context at the specified location. 
		// By specifying a location the bitmap doesn't always have to start in the upper left-hand 
		// corner of the static control. 
		maskDC.StretchBlt( pLayerInfo->m_ptLocation.x, pLayerInfo->m_ptLocation.y, 
			sizeLayer.cx, sizeLayer.cy, &srcDC, 0, 0, sizeLayer.cx, sizeLayer.cy, NOTSRCCOPY ); 
 
		// Set the background color back to the original color for the mask device context. 
		maskDC.SetBkColor( colOld ); 
 
		// Copy the inverted bitmap mask onto the overlay bitmap. 
		overlayDC.BitBlt( 0, 0, sizeCtrl.cx, sizeCtrl.cy, &maskDC, 0, 0, NOTSRCCOPY ); 
 
		// Copy the combined bitmap onto the overlay bitmap. 
		overlayDC.BitBlt( 0, 0, sizeCtrl.cx, sizeCtrl.cy, &destDC, 0, 0, SRCAND ); 
 
		// Copy the bitmap mask onto the composite bitmap. 
		compositeDC.BitBlt( 0, 0, sizeCtrl.cx, sizeCtrl.cy, &maskDC, 0, 0, SRCCOPY ); 
 
		// Cleanup bitmap mask. 
		maskDC.SelectObject( pOldMaskBmp ); 
		bmpMask.DeleteObject(); 
 
		// Select the palette from the destination device context. 
		pPalette = destDC.GetCurrentPalette(); 
 
		// Does the palette exist? 
		if ( pPalette ) 
		{ 
			// Select the palette into the composite device context. 
			pPalette = compositeDC.SelectPalette( pPalette, FALSE ); 
			compositeDC.RealizePalette(); 
		} 
 
		// AND the layer's bitmap with the composite bitmap. 
		compositeDC.SetStretchBltMode( COLORONCOLOR ); 
		compositeDC.StretchBlt( pLayerInfo->m_ptLocation.x, pLayerInfo->m_ptLocation.y, 
			sizeLayer.cx, sizeLayer.cy, &srcDC, 0, 0, sizeLayer.cx, sizeLayer.cy, SRCAND ); 
 
		// OR the overlay bitmap with the composite bitmap. 
		compositeDC.BitBlt( 0, 0, sizeCtrl.cx, sizeCtrl.cy, &overlayDC, 0, 0, SRCPAINT ); 
		 
		// Cleanup the overlay bitmap. 
		overlayDC.SelectObject( pOldOverlayBmp ); 
		bmpOverlay.DeleteObject(); 
 
		// Copy the composite bitmap onto the combined bitmap. 
		destDC.BitBlt( 0, 0, sizeCtrl.cx, sizeCtrl.cy, &compositeDC, 0, 0, SRCCOPY ); 
		 
		// Cleanup the composite bitmap. 
		compositeDC.SelectPalette( pPalette, FALSE ); 
		compositeDC.SelectObject( pOldCompositeBmp ); 
		bmpComposite.DeleteObject(); 
	} 
	else 
	{ 
		// Paint this layer's bitmap onto the combined bitmap at the specified location. 
		destDC.BitBlt( pLayerInfo->m_ptLocation.x, pLayerInfo->m_ptLocation.y, 
			sizeCtrl.cx, sizeCtrl.cy, &srcDC, 0, 0, SRCCOPY ); 
	} 
 
	// Put the old source bitmap back into the source device context. 
	srcDC.SelectObject( pOldSrcBmp ); 
 
	// Final cleanup. 
	destDC.SelectObject( pOldDestBmp ); 
	ReleaseDC( pDC ); 
 
	return true; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	ShowVisibleLayers 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	This function makes sure that the layers are sorted 
//					and that the visible layers are combined into one 
//					bitmap before drawing them onto the screen. 
//******************************************************************* 
bool CLayeredBitmapCtrl::ShowVisibleLayers() 
{ 
	SortLayers(); 
 
	if ( CombineLayers() ) 
	{ 
		// Paint the new combined bitmap onto the control. 
		Invalidate(); 
	} 
 
	return true; 
} 
 
//******************************************************************* 
//  FUNCTION:   -	CreateFocusLayer 
//  RETURNS:    -	A newly allocated layer object that contains a focus 
//					rectangle. 
//  PARAMETERS: -	pDC - pointer to the current device context. 
//					nX - left location of the focus layer. 
//					nY - top location of the focus layer. 
//					nWidth - width of the focus layer. 
//					nHeight - height of the focus layer. 
//					colFocus - color of the focus rectangle. 
//  COMMENTS:   -	Creates a dynamic focus layer that contains a rectangle. 
//					This function is used within the OnPaint to show 
//					a rectangle around the currently selected layer. 
//					(Thanks X.Q.Wang for the suggestion). 
//******************************************************************* 
CLayerInfo *CLayeredBitmapCtrl::CreateFocusLayer( CDC *pDC, int nX, int nY, int nWidth, int nHeight, COLORREF colFocus ) 
{ 
	CDC tmpDC; 
	COLORREF colTrans				= RGB( 255, 0, 255 ); 
	CPen *pOldPen					= NULL; 
	CBrush *pOldBrush				= NULL; 
	CBitmap *pOldBmp				= NULL; 
	CPen penRectangle; 
	CBrush brushTransparent; 
 
	// Create a layer object that will contain the focus rectangle. 
	CLayerInfo *pLayerInfo			= new CLayerInfo(); 
	pLayerInfo->m_bTransparent		= true; 
	pLayerInfo->m_ptLocation.x		= nX; 
	pLayerInfo->m_ptLocation.y		= nY; 
	pLayerInfo->m_colTransparent	= colTrans; 
 
	tmpDC.CreateCompatibleDC( pDC ); 
	pLayerInfo->m_bmp.CreateCompatibleBitmap( pDC, nWidth, nHeight ); 
 
	// Select the newly created bitmap into the device context. 
	pOldBmp = tmpDC.SelectObject( &pLayerInfo->m_bmp ); 
 
	// Create a brush with the transparent color. 
	brushTransparent.CreateSolidBrush( colTrans ); 
 
	// Select the brush into the device context. 
	pOldBrush = tmpDC.SelectObject( &brushTransparent ); 
 
	// Create the pen to be used for the focus rectangle. 
	penRectangle.CreatePen( PS_SOLID, 1, colFocus ); 
	pOldPen = tmpDC.SelectObject( &penRectangle ); 
	 
	// Draw a rectangle with the current brush and pen. 
	tmpDC.Rectangle( 0, 0, nWidth, nHeight ); 
 
	pLayerInfo->m_bmp.SetBitmapDimension( nWidth, nHeight ); 
 
	// Clean up the brush and pen resources. 
	tmpDC.SelectObject( pOldBrush ); 
	tmpDC.SelectObject( pOldPen ); 
 
	brushTransparent.DeleteObject(); 
	penRectangle.DeleteObject(); 
 
	// Select the current bitmap out of the device context. 
	tmpDC.SelectObject( pOldBmp ); 
 
	return pLayerInfo; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// Message Map 
BEGIN_MESSAGE_MAP(CLayeredBitmapCtrl, CStatic) 
	//{{AFX_MSG_MAP(CLayeredBitmapCtrl) 
	ON_WM_PAINT() 
	ON_WM_MOUSEMOVE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_SYSCOLORCHANGE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CLayeredBitmapCtrl message handlers 
 
//******************************************************************* 
//  FUNCTION:   -	OnPaint 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:	-	This function paints the bitmap containing all of 
//					the visible layers onto the static control. 
//******************************************************************* 
void CLayeredBitmapCtrl::OnPaint()  
{ 
	CPaintDC dc( this ); // device context for painting 
	 
    CDC         displayDC; 
    CRect       rectCtrl; 
    CBitmap     *pOldBmp		= NULL; 
	CBitmap		bmpTemp; 
	bool		bShowTopLayers	= false; 
	int			nIndex			= 0; 
	CLayerInfo	*pCurrentLayer	= NULL; 
	CLayerInfo	*pTrackedLayer	= NULL; 
	CLayerInfo	*pTmpLayer		= NULL; 
	CRect		rectIntersect; 
 
	// First make a copy of the combined bitmap. 
	CLayerInfo::CopyBitmap( m_bmpCombined, bmpTemp ); 
 
	// Get the client rect of the static control. 
    GetClientRect( &rectCtrl ); 
 
	// Create a compatible device context to display the combined bitmap. 
    displayDC.CreateCompatibleDC( &dc ); 
 
	// Cycle thru the layers to see if we are tracking. 
	for ( nIndex = 0; nIndex < m_vecLayerInfo.size(); nIndex++ ) 
	{ 
		pCurrentLayer	= reinterpret_cast(&m_vecLayerInfo[nIndex]); 
 
		// If we are tracking a layer, then all the visible layers above may need to be redrawn onto the bitmap, 
		// unless the m_bShowOnTopWhileTracking flag has been set. 
		// Note: The redrawing process is going to get slower if there are a lot of layers above the 
		// layer that is being tracked. 
		if ( bShowTopLayers ) 
		{ 
			if ( pCurrentLayer->m_bVisible ) 
			{ 
				rectIntersect.SetRectEmpty(); 
 
				if ( NULL != pTrackedLayer ) 
				{ 
					// Only redraw the current layer if the layer is within the tracked layer's rectangle. 
					if ( DoLayersIntersect( pTrackedLayer, pCurrentLayer, &rectIntersect ) ) 
					{ 
						// Create a temporary layer that will only contain the portion of the current layer 
						// that needs to be updated. 
						pTmpLayer							= new CLayerInfo( *pCurrentLayer ); 
 
						// Set the transparent pixel location to -1 because the bitmap section that we will be creating may not have the 
						// same coordinates.  Since the original layer object is copied into the temporary layer, the transparent 
						// color will be set appropriately. 
						pTmpLayer->m_ptTransparentPixel.x	= -1; 
						pTmpLayer->m_ptTransparentPixel.y	= -1; 
 
						// Set the location of the temporary layer. 
						pTmpLayer->m_ptLocation.x			= rectIntersect.left; 
						pTmpLayer->m_ptLocation.y			= rectIntersect.top; 
						int nTmpWidth						= rectIntersect.Width(); 
						int nTmpHeight						= rectIntersect.Height(); 
 
						// Get the sizes of the tracked layer and the current layer. 
						CSize sizeTracked					= pTrackedLayer->m_bmp.GetBitmapDimension(); 
						CSize sizeCurrent					= pCurrentLayer->m_bmp.GetBitmapDimension(); 
 
						// Tracked layer is on the right portion of the current layer.  
						if ( pTrackedLayer->m_ptLocation.x >= pCurrentLayer->m_ptLocation.x ) 
						{ 
							// Is the width of the tracked layer smaller than the width of the current layer? 
							if ( sizeTracked.cx < sizeCurrent.cx ) 
							{ 
								// Is the width of the current layer larger than the width of the intersecting rectangle? 
								if ( sizeCurrent.cx > nTmpWidth ) 
								{ 
									// We need to get the bitmap section from the left side of the current bitmap. 
									rectIntersect.left	= rectIntersect.left - pCurrentLayer->m_ptLocation.x; 
								} 
								else 
								{ 
									// We need to get the bitmap section from the right side of the current bitmap. 
									rectIntersect.left	= sizeCurrent.cx - nTmpWidth; 
								} 
							} 
							else 
							{ 
								// We need to get the bitmap section from the right side of the current bitmap. 
								rectIntersect.left		= sizeCurrent.cx - nTmpWidth; 
							} 
						} 
						else 
						{ 
							// If the tracked layer is on the left side of the current layer, then start the rectangle at zero (0). 
							rectIntersect.left			= 0; 
						} 
 
						// Calculate the right side of the rectangle. 
						rectIntersect.right				= rectIntersect.left + nTmpWidth; 
 
						// Tracked layer is on the bottom portion of the current layer. 
						if ( pTrackedLayer->m_ptLocation.y >= pCurrentLayer->m_ptLocation.y ) 
						{ 
							// Is the height of the tracked layer smaller than the height of the current layer? 
							if ( sizeTracked.cy < sizeCurrent.cy ) 
							{ 
								// Is the height of the current layer larger than the height of the intersecting rectangle? 
								if ( sizeCurrent.cy > nTmpHeight ) 
								{ 
									// We need to get the bitmap section from the top of the current bitmap. 
									rectIntersect.top	= rectIntersect.top - pCurrentLayer->m_ptLocation.y; 
								} 
								else 
								{ 
									// We need to get the bitmap section from the bottom of the current bitmap. 
									rectIntersect.top	= sizeCurrent.cy - nTmpHeight; 
								} 
							} 
							else 
							{ 
								// We need to get the bitmap section from the bottom of the current bitmap. 
								rectIntersect.top		= sizeCurrent.cy - nTmpHeight; 
							} 
						} 
						else 
						{ 
							// If the tracked layer is on the top of the current layer, then start the rectangle at zero (0). 
							rectIntersect.top			= 0; 
						} 
 
						// Calculate the bottom of the rectangle. 
						rectIntersect.bottom			= rectIntersect.top + nTmpHeight; 
 
						// Copy the bitmap section from the current layer's bitmap into the temporary layer's bitmap. 
						CLayerInfo::CopyBitmapSection( pCurrentLayer->m_bmp, pTmpLayer->m_bmp, rectIntersect, &dc ); 
 
						// Draw the current layer onto the bitmap. 
						DrawLayerOnBitmap( &bmpTemp, pTmpLayer ); 
 
						delete pTmpLayer; 
					} 
				} 
			} 
		} 
 
		// Are we moving the current layer with the mouse? 
		if ( true == pCurrentLayer->m_bTracking ) 
		{ 
			// Draw the current layer onto the bitmap. 
			DrawLayerOnBitmap( &bmpTemp, pCurrentLayer ); 
 
			// Store a pointer to the tracked layer so that we can determine if we need to draw each 
			// of the visible layers above this one. 
			pTrackedLayer = pCurrentLayer; 
 
			// Only redraw the layers above the tracked layer if requested to do so. 
			if ( false == pCurrentLayer->m_bShowOnTopWhileTracking ) 
			{ 
				// Now, set the flag so that all of the visible layer above this one will be redrawn. 
				bShowTopLayers = true; 
			} 
		} 
 
		// Show the focus rectangle if necessary. 
		if ( true == pCurrentLayer->m_bShowFocusRectangle ) 
		{ 
			// Create a temporary layer to display a rectangle around the layer being tracked. 
			CLayerInfo *pLayerInfo = NULL; 
			CSize sizeBitmap; 
 
			sizeBitmap	= pCurrentLayer->m_bmp.GetBitmapDimension(); 
 
			// Create the focus layer based on the size of the current layer object. 
			pLayerInfo	= CreateFocusLayer( &dc, pCurrentLayer->m_ptLocation.x, pCurrentLayer->m_ptLocation.y, 
				sizeBitmap.cx, sizeBitmap.cy, pCurrentLayer->m_colFocusRectangle ); 
 
			if ( NULL != pLayerInfo ) 
			{ 
				// Draw the temporary layer onto the bitmap. 
				DrawLayerOnBitmap( &bmpTemp, pLayerInfo ); 
 
				delete pLayerInfo; 
			} 
		} 
	} 
	 
    // Select the combined bitmap into the display device context. 
    pOldBmp = displayDC.SelectObject( &bmpTemp ); 
 
	// Copy the combined bitmap onto the static control. 
	dc.BitBlt( rectCtrl.left, rectCtrl.top, rectCtrl.Width(), rectCtrl.Height(),  
		&displayDC, 0, 0, SRCCOPY ); 
	 
	// Cleanup the display device context. 
    displayDC.SelectObject( pOldBmp ); 
 
	// Do not call CStatic::OnPaint() for painting messages 
} 
 
//******************************************************************* 
//  FUNCTION:   -	OnMouseMove 
//  RETURNS:    -	 
//  PARAMETERS: -	nFlags - Specifies if any of the mouse buttons are 
//						down and the status of the ctrl and shift keys. 
//					point - Specifies the location of the mouse's hot spot. 
//  COMMENTS:	-	This is just added functionality to display which 
//					layer that the mouse is currently in.  Also, 
//					if layer tracking is enabled, the layer can be 
//					moved around the control while the left mouse 
//					button is pressed. 
//******************************************************************* 
void CLayeredBitmapCtrl::OnMouseMove(UINT nFlags, CPoint point)  
{ 
	vector::iterator	currentLayer; 
	bool bShowTip				= false; 
	bool bSomethingChanged		= false; 
	int nOffsetX, nOffsetY; 
 
	if ( m_vecLayerInfo.empty() ) 
	{ 
		CStatic::OnMouseMove(nFlags, point); 
		return; 
	} 
 
	// Loop through the top layers first. 
	for ( currentLayer = m_vecLayerInfo.end() -1; currentLayer >= m_vecLayerInfo.begin(); --currentLayer ) 
	{ 
		// See if the left mouse button is down. 
		if ( nFlags & MK_LBUTTON ) 
		{ 
			if ( (true == currentLayer->m_bTracking) || (true == currentLayer->m_bShowFocusRectangle) ) 
			{ 
				// Don't show the tool tip if we're tracking. 
				m_bHideTrackingToolTip = true; 
 
				// If the mouse is moving right. 
				if ( point.x >= currentLayer->m_ptTrackingStart.x ) 
				{ 
					nOffsetX	= point.x - currentLayer->m_ptTrackingStart.x; 
				} 
				else 
				{ 
					// If the mouse is moving left, make the offset negative. 
					nOffsetX	= currentLayer->m_ptTrackingStart.x - point.x; 
					nOffsetX	*= -1; 
				} 
 
				// Adjust the layer's X location based on the offset. 
				currentLayer->m_ptLocation.x		+= nOffsetX; 
 
				// If the mouse is moving down. 
				if ( point.y >= currentLayer->m_ptTrackingStart.y ) 
				{ 
					nOffsetY	= point.y - currentLayer->m_ptTrackingStart.y; 
				} 
				else 
				{ 
					// If the mouse is moving up, make the offset negative. 
					nOffsetY	= currentLayer->m_ptTrackingStart.y - point.y; 
					nOffsetY	*= -1; 
				} 
 
				// Adjust the layer's Y location based on the offset. 
				currentLayer->m_ptLocation.y		+= nOffsetY; 
 
				// Adjust the tracking point based on the offset. 
				currentLayer->m_ptTrackingStart.x	+= nOffsetX; 
				currentLayer->m_ptTrackingStart.y	+= nOffsetY; 
 
				// Adjust the region based on the offset. 
				currentLayer->m_rgn.OffsetRgn( nOffsetX, nOffsetY ); 
				 
				bSomethingChanged					= true; 
			} 
		} 
	} 
 
	if ( bSomethingChanged ) 
	{ 
		// Paint the control without combining the lower layers again. 
		Invalidate(); 
	} 
 
	// See if we need to show tool tips. 
	if ( m_bShowToolTips && (false == m_bHideTrackingToolTip) ) 
	{ 
		// Show the tool tip for the top layer first. 
		for ( currentLayer = m_vecLayerInfo.end() -1; currentLayer >= m_vecLayerInfo.begin(); --currentLayer ) 
		{ 
			// Only look for visible layers. 
			if ( currentLayer->m_bVisible ) 
			{ 
				// Only display a tool tip if the layer contains a region. 
				if ( true == currentLayer->m_bUseRgn ) 
				{ 
					// If the mouse point is within the layer's region, display a tool tip. 
					if ( currentLayer->m_rgn.PtInRegion( point ) ) 
					{ 
						// If a layer description is present, then display the tool tip. 
						if ( !currentLayer->m_strLayerDesc.IsEmpty() ) 
						{ 
							m_strToolTip = currentLayer->m_strLayerDesc; 
							m_toolTip.UpdateTipText( (LPCSTR)m_strToolTip, this ); 
							m_toolTip.Update(); 
							bShowTip = true; 
						} 
 
						// Only show the tool tip for the first layer that we come across. 
						break; 
					} 
				} 
			} 
		} 
 
		// Remove the tool tip window if there is no tool tip to display. 
		if ( false == bShowTip ) 
		{ 
			m_strToolTip.Empty(); 
			m_toolTip.Pop(); 
		} 
	} 
 
	CStatic::OnMouseMove(nFlags, point); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	OnLButtonDown 
//  RETURNS:    -	 
//  PARAMETERS: -	nFlags - Specifies if any of the mouse buttons are 
//						down and the status of the ctrl and shift keys. 
//					point - Specifies the location of the mouse's hot spot. 
//  COMMENTS:   -	Starts the layer tracking process, if tracking is 
//					enabled. 
//******************************************************************* 
void CLayeredBitmapCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	vector::iterator	currentLayer; 
 
	if ( m_vecLayerInfo.empty() ) 
	{ 
		CStatic::OnLButtonDown(nFlags, point); 
		return; 
	} 
 
	// Loop through the top layers first. 
	for ( currentLayer = m_vecLayerInfo.end() -1; currentLayer >= m_vecLayerInfo.begin(); --currentLayer ) 
	{ 
		// Only look for visible layers. 
		if ( currentLayer->m_bVisible ) 
		{ 
			// Only track if the layer contains a region. 
			if ( true == currentLayer->m_bUseRgn ) 
			{ 
				// Is the mouse within the region? 
				if ( currentLayer->m_rgn.PtInRegion( point ) ) 
				{ 
					// Does this layer support tracking? 
					if ( currentLayer->m_bTrackingEnabled ) 
					{ 
						currentLayer->m_ptTrackingStart = point; 
 
						// Indicate that this layer is now being tracked. 
						currentLayer->m_bTracking		= true; 
 
						// Remove the bitmap from the display so that it can be redrawn 
						// at it's new location. 
						currentLayer->m_bVisible		= false; 
					} 
 
					if ( true == currentLayer->m_bFocusRectangleEnabled ) 
					{ 
						currentLayer->m_bShowFocusRectangle = true; 
					} 
 
					break; 
				} 
			} 
		} 
	} 
 
	// The layer that is currently being tracked will no longer be part of 
	// the combined bitmap, it will be drawn in the OnPaint function. 
	ShowVisibleLayers(); 
	 
	CStatic::OnLButtonDown(nFlags, point); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	OnLButtonUp 
//  RETURNS:    -	 
//  PARAMETERS: -	nFlags - Specifies if any of the mouse buttons are 
//						down and the status of the ctrl and shift keys. 
//					point - Specifies the location of the mouse's hot spot. 
//  COMMENTS:   -	Stops the layer tracking process, if tracking is 
//					enabled and re-displays the layer that was previously 
//					being tracked. 
//******************************************************************* 
void CLayeredBitmapCtrl::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
	vector::iterator	currentLayer; 
	bool bFoundLastSelected		= false; 
 
	if ( m_vecLayerInfo.empty() ) 
	{ 
		CStatic::OnLButtonUp(nFlags, point); 
		return; 
	} 
 
	// Loop through the top layers first. 
	for ( currentLayer = m_vecLayerInfo.end() -1; currentLayer >= m_vecLayerInfo.begin(); --currentLayer ) 
	{ 
		if ( currentLayer->m_bTracking ) 
		{ 
			// Show this layer again at it's current location. 
			currentLayer->m_bVisible		= true; 
 
			// We're no longer tracking this layer. 
			currentLayer->m_bTracking		= false; 
 
			// Allow the tool tips to be displayed again. 
			m_bHideTrackingToolTip			= false; 
		} 
 
		if ( currentLayer->m_bShowFocusRectangle ) 
		{ 
			// Don't display the focus rectangle since the left mouse button is no longer down. 
			currentLayer->m_bShowFocusRectangle = false; 
		} 
	} 
 
	// Combine and show all of the visible layers. 
	ShowVisibleLayers(); 
	 
	CStatic::OnLButtonUp(nFlags, point); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	PreTranslateMessage 
//  RETURNS:    -	0 if the message was not translated and needs to 
//						be dispatched. 
//					Otherwise, non-zero if it was translated. 
//  PARAMETERS: -	pMsg - The window's message to be translated. 
//  COMMENTS:	-	This is used to display the tool tip properly when 
//					a mouse event occurs. 
//******************************************************************* 
BOOL CLayeredBitmapCtrl::PreTranslateMessage(MSG* pMsg)  
{ 
	// Look for mouse messages. 
	if ( pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST ) 
	{ 
		if ( ::IsWindow( pMsg->hwnd ) ) 
		{ 
			// See if tool tips are allowed. 
			if ( m_bShowToolTips ) 
			{ 
				// Only display the tool tip if the string is not empty.  
				if ( !m_strToolTip.IsEmpty() ) 
				{ 
					m_toolTip.RelayEvent( pMsg ); 
				} 
			} 
		} 
	} 
	 
	return CStatic::PreTranslateMessage(pMsg); 
} 
 
//******************************************************************* 
//  FUNCTION:   -	OnSysColorChange 
//  RETURNS:    -	 
//  PARAMETERS: -	 
//  COMMENTS:   -	Redisplays the control if the system color changes 
//					and the control is set to use the system color. 
//******************************************************************* 
void CLayeredBitmapCtrl::OnSysColorChange()  
{ 
	CStatic::OnSysColorChange(); 
 
	// Make the control is using the system color. 
	if ( UsingSysColor() ) 
	{ 
		// Get the new system color just in case it has changed. 
		m_colCtrlBG = ::GetSysColor( (true == m_bIsParentDlg) ? COLOR_BTNFACE : COLOR_WINDOW ); 
 
		// Combine and show all of the visible layers to reflect the system color change. 
		ShowVisibleLayers(); 
	} 
 
	return; 
}