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; }