Skip to main content
Email Password   helpLost your password?

Here is an example of how to extend the CLayeredBitmapCtrl to be used within a CScrollView application:

Introduction

This article is about a CStatic derived class that supports multiple bitmap layers. The CLayeredBitmapCtrl class allows you to add/remove/show/hide bitmap layers on a static control. Each bitmap layer can have a user defined transparent color or retrieve the transparent color from a specified location in the bitmap. This allows the background bitmap to be visible through the transparent color of another bitmap layer. Tool tips are also used so that each layer can display its own description. Each layer can also have a non-transparent region that allows the tool tip to be displayed only when the mouse is over the non-transparent portion of the layer. 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, unless the layer is smaller and rectangular.

Background

I wrote this code because I needed a way of displaying a background image that contains multiple smaller images on it. I also needed a quick way of adding and removing images from the display. Being able to get more information about a particular image while the mouse was over it, was a must. That is why I used a technique to create a non-transparent region, so that only the visible portion of the image will trigger the tool tip description.

New Features (Added for Version 2.01)

Existing Features

Added for Version 2.0

From Initial Release

CLayerInfo Class

The CLayerInfo 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. The CLayeredBitmapCtrl class contains a vector of CLayerInfo objects. A new copy of the CLayerInfo object is added to the vector, which means that you can use a temporary CLayerInfo variable when creating layers.

Construction/Destruction

public:
    CLayerInfo();
    CLayerInfo( const CLayerInfo &src );  // Copy constructor


    // Destructor

    virtual ~CLayerInfo();

Implementation

public:
    // Copies the source layer object into this layer object.

    CLayerInfo &Copy( const CLayerInfo &src );

    // Assigns the contents of one layer object to another.

    CLayerInfo &operator=( const CLayerInfo &src );

    // Compares the layer index of the source layer object with the 

    // layer index of this layer object.  These comparison functions

    // are used by the vector for sorting purposes.

    bool operator==( const CLayerInfo &layerInfo ) const;
    bool operator<( const CLayerInfo &layerInfo ) const;
    bool operator>( const CLayerInfo &layerInfo ) const;

    // Here are some static bitmap utility functions

    // that can be used independently of the layers.


    // Copies the source bitmap into the destination bitmap.

    static bool CopyBitmap( const CBitmap &bmpSrc, CBitmap &bmpDest );

    // Copies a section from an existing source bitmap

    // into a new destination bitmap.

    static bool CopyBitmapSection( CBitmap &bmpSrc, 
           CBitmap &bmpDest, CRect &rectSection, CDC *pDC = NULL );

    // Allocates and initializes a BITMAPINFO structure.

    static BITMAPINFO *PrepareRGBBitmapInfo( int nWidth, int nHeight );

    // Gets the color from a specific location within a bitmap.

    static COLORREF GetColorFromBitmap( const CPoint &ptLocation, 
                                        CBitmap &bitmap );

Attributes

public:
    // Unique layer identifier, so that the layer

    // can be found within the vector.

    int         m_nLayerID;

    // Indicates which level this layer is at.

    // The vector is sorted by this index. (0 = bottom layer).

    int         m_nLayerIndex;

    // This is the description that

    // will be displayed in the tool tip.

    CString     m_strLayerDesc;

    // Indicates whether or not this

    // layer will be displayed or hidden.

    bool        m_bVisible;

    // Indicates that this layer contains a region

    // which is used to determine if

    // the mouse is within the layer.

    bool        m_bUseRgn;

    // Indicates that this layer can be moved with the mouse.

    bool        m_bTrackingEnabled;

    // Indicates that this layer is currently being tracked.

    bool        m_bTracking;

    // Indicates that this layer will be displayed above

    // all visible layers while being tracked.

    // This allows the tracked layer to be displayed

    // faster instead of having to redraw each section

    // of the above layers that intersect with the tracked layer.

    bool        m_bShowOnTopWhileTracking;

    // Indicates the point within the layer

    // that the left mouse button was first pressed.

    CPoint      m_ptTrackingStart;

    // Indicates that this layer contains transparent pixels.

    bool        m_bTransparent;

    // Indicates the transparent color.

    COLORREF    m_colTransparent;

    // Instead of setting the transparent

    // color manually, you can specify the location

    // within the bitmap to get the transparent color.

    CPoint      m_ptTransparentPixel;

    // Specifies where you want to put this layer

    // on the CLayeredBitmapCtrl window.

    CPoint      m_ptLocation;

    // Indicates whether or not this layer will display

    // a focus rectangle while the

    // left mouse button is pressed.

    bool        m_bFocusRectangleEnabled;

    // Indicates that the focus rectangle should be displayed.

    bool        m_bShowFocusRectangle;

    // Indicates the color of the focus rectangle.

    COLORREF    m_colFocusRectangle;

    // This is the bitmap for the current layer.

    CBitmap     m_bmp;

    // This is the region for the current layer.

    // (The region does not have to be created).

    CRgn        m_rgn;

CLayeredBitmapCtrl Class

The CLayeredBitmapCtrl 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. 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.

Construction/Destruction

public:
    // Default CStatic contructor.

    CLayeredBitmapCtrl();

    // Destructor - Frees all of the memory associated with the layers.

    virtual ~CLayeredBitmapCtrl();

Attributes

public:
    // This is the bitmap that is displayed on the screen within the control.

    CBitmap             m_bmpCombined;

protected:
    // This vector contains all of the layer

    // objects even if they are not displayed.

    vector<CLayerInfo>  m_vecLayerInfo;

    // Indicates if tool tips are to be shown

    // if the mouse is within a layer's region.

    bool                m_bShowToolTips;

    // Indicates that the tool tip control has been initialized.

    bool                m_bToolTipsInitialized;

    // Indicates that tool tips will be hidden

    // while moving a layer with the mouse.

    bool                m_bHideTrackingToolTip;

    // String that is displayed in the tool tip.

    CString             m_strToolTip;

    // Tool tip control that is displayed

    // if the mouse is within a layer's region.

    CToolTipCtrl        m_toolTip;
    
    // Indicates if the parent of this

    // control is a dialog or a view type window.

    // This way we can determine which system

    // color to use (COLOR_BTNFACE = CDialog,

    // COLOR_WINDOW = CView).

    bool                m_bIsParentDlg;

    // Indicates if the system color

    // is used for the background color of the control.

    bool                m_bUseSysColor;

    // Indicates the control's background color.

    COLORREF            m_colCtrlBG;

Public Methods

Using the code

To use this control in your application, add the LayeredBitmapCtrl.h and LayeredBitmapCtrl.cpp files to your project. Use the Resource Editor to add a Picture Control to your dialog. Edit the properties of the Picture Control and rename the control from IDC_STATIC to some other name like IDC_LAYERED_DISPLAY. Next, add the Notify style to the control. This allows the tool tip to work properly.

There are two ways to add a variable for the control.

  1. In order to see the CLayeredBitmapCtrl listed as an option in the ClassWizard, you must first delete the .clw file. Once you have deleted the file, open the ClassWizard. You will see a dialog box asking if you want to recreate the ClassWizard database from your source files. Choose Yes and make sure that the LayeredBitmapCtrl.h and LayeredBitmapCtrl.cpp are in the project directory. Now, choose your dialog and select Member Variables. Select the IDC_LAYERED_DISPLAY control (or the name that you gave it) and add a variable. Type the variable name and select Control as the Category. You should see the CLayeredBitmapCtrl listed under Variable type.
  2. Open the ClassWizard, choose your dialog, and select Member Variables. Select the IDC_LAYERED_DISPLAY control (or the name that you gave it) and add a variable. Type the variable name and select Control as the Category. Choose CStatic for the Variable type. Once you are finished with the ClassWizard, open your dialog's header file. Change the control type from CStatic to CLayeredBitmapCtrl for your variable.

Don't forget to add the following to your dialog's header file:

#include "LayeredBitmapCtrl.h"

Make sure that you have a unique layer ID for each layer. For the demo project, I created an enumerated list so that I knew each ID would be unique. I setup the layers within a function that I call at the end of the InitDialog function. However, the layers can be created at anytime. Also, within InitDialog, you can specify the control's background color. In the demo, I use the CLayeredBitmapCtrl::UseSysColor function so that the control's background color will reflect changes to the system color.

The CLayeredBitmapCtrl class uses another class called CLayerInfo. This class contains all of the information and data objects for each layer, including a CBitmap and CRgn.

How to setup layers

This is the method I used in the demo to setup the various layers. For the first layer, I don't specify a transparent color or create a region. The location of the bitmap is defaulted to the upper left-hand corner of the control. Since this layer is the same size as the control, there is no need to change its location.

    CLayerInfo *pLayerInfo = NULL;

    // Here are the background bitmaps for the Layer1 Selection.

    // Create a new layer.

    pLayerInfo                              = new CLayerInfo();
    pLayerInfo->m_nLayerID                  = VALLEY_OF_FIRE_LAYER;
    pLayerInfo->m_strLayerDesc              = _T("Valley of Fire");
    pLayerInfo->m_bmp.LoadBitmap( IDB_VALLEY_OF_FIRE_BITMAP );

    m_layeredDisplay.AddLayer( *pLayerInfo );
    delete pLayerInfo;

Here is an example of a transparent layer with a region:

    // Here is the transparent bitmap for the Layer2 Selection.

    // Create a new layer.

    pLayerInfo                              = new CLayerInfo();
    pLayerInfo->m_nLayerID                  = CHAMELEON_BOB_LAYER;
    pLayerInfo->m_strLayerDesc              = _T("Chameleon Bob");
    pLayerInfo->m_bTransparent              = true;
    pLayerInfo->m_ptTransparentPixel.x      = 1;
    pLayerInfo->m_ptTransparentPixel.y      = 1;
    pLayerInfo->m_ptLocation.x              = 200;
    pLayerInfo->m_ptLocation.y              = 210;
    pLayerInfo->m_bTrackingEnabled          = true;
    pLayerInfo->m_bFocusRectangleEnabled    = true;
    pLayerInfo->m_colFocusRectangle         = RGB( 0, 255, 0 );

    pLayerInfo->m_bmp.LoadBitmap( IDB_CHAMELEON_BOB_BITMAP );

    m_layeredDisplay.CreateNonTransparentRgn( pLayerInfo );
    pLayerInfo->m_rgn.OffsetRgn( pLayerInfo->m_ptLocation.x, 
                                  pLayerInfo->m_ptLocation.y );

    m_layeredDisplay.AddLayer( *pLayerInfo );
    delete pLayerInfo;

Here is an example of a transparent bitmap. I use magenta RGB(255,0,255) for the transparent color, because it's not very likely that I'll have that color in my background image.

For example

Chameleon Bob

If you want to have a layer displayed, add the following code before you call the CLayeredBitmapCtrl::AddLayer function:

    pLayerInfo->m_bVisible    = true;

Or, you can specify the visibility after the layer has been added, by calling the CLayeredBitmapCtrl::SetLayerVisibility function.

    m_layeredDisplay.SetLayerVisibility( CHAMELEON_BOB_LAYER, true );

Once you have setup the layers, call the CLayeredBitmapCtrl::ShowVisibleLayers function to display the combined bitmap layers on the control.

    m_layeredDisplay.ShowVisibleLayers();

Points of Interest

I had looked at various examples of transparent bitmaps and read a section from the Windows 2000 Graphics API Black Book, by Damon Chandler, Michael Fotsch, and eventually, I came up with a solution to my problem. It took a lot of tweaking to get it right, due to the various sizes of the bitmaps. To allow for the focus rectangle and the ability to move layers, I came up with the idea of being able to draw a layer on any bitmap instead of just the combined bitmap. Here is the code used to combine the visible layers onto one bitmap, as well as the code for drawing a layer on to any bitmap:

//*******************************************************************

//  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<CLayerInfo *>(&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;
}

Here is the OnPaint function. In this function, a copy of the combined bitmap is made so that we can draw the focus rectangle if necessary. Also, depending on the m_bShowOnTopWhileTracking flag, the top layers will be redrawn above the tracked layer. If the flag is set, then the code determines if the rectangle surrounding the tracked layer intersects with the current layer. If the two rectangles intersect, then only the portion of the current layer that intersects with the tracked layer is redrawn. It is still a slow process, but a nice effect. That is why I added the flag, so that the tracked layer can be displayed on top of all of the other layers without having to redraw them. Note, that the tracked layer's index is not modified. So once the mouse button is released, the tracked layer will be drawn under the visible top layers again.

//*******************************************************************

//  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<CLayerInfo *>(&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

}

Acknowledgements

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralTransparent object Pin
vickgehenk
16:38 9 Nov '09  
GeneralMake it run on WINCE Pin
bobby xiang
6:57 26 Jun '09  
GeneralRe: Make it run on WINCE Pin
bobby xiang
6:38 2 Jul '09  
QuestionC# VS 2005 Pin
Randall Medcalf
5:02 18 Apr '08  
GeneralCompile on VC++ 8 but not run properly Pin
Amrut Kothiya
21:03 23 May '07  
GeneralRe: Compile on VC++ 8 but not run properly Pin
bobo01
11:00 22 May '08  
QuestionMake it run on Windows 98 Pin
vincennes
12:46 27 Feb '07  
AnswerRe: Make it run on Windows 98 Pin
vincennes
3:33 11 Mar '07  
GeneralGreat job , but i need your help Pin
The Yariv
22:00 22 Oct '06  
AnswerRe: Great job , but i need your help Pin
Metaldude
20:49 24 Oct '06  
Generallossing colur info Pin
raviatcodeproject
13:05 4 Apr '06  
GeneralRe: lossing colur info Pin
Metaldude
5:35 5 Apr '06  
GeneralRe: lossing colur info Pin
lohw
22:15 3 Sep '09  
General2 Bugs found if compiled with Visual Studio 2005 Pin
khdtrader
3:12 16 Feb '06  
GeneralRe: 2 Bugs found if compiled with Visual Studio 2005 Pin
Metaldude
7:06 22 Feb '06  
GeneralEnhanced ToolTipCtrl Pin
varandas79
4:36 20 Oct '05  
GeneralGreat job Pin
Stlan
22:10 30 Jan '05  
GeneralRe: Great job Pin
Metaldude
5:24 31 Jan '05  
GeneralI've added a new scrollview demo to the downloads section Pin
Metaldude
5:18 27 Jan '05  
GeneralUsing LayeredBitmapCtrl in ScrollView Pin
rsundar123
22:55 20 Jan '05  
GeneralRe: Using LayeredBitmapCtrl in ScrollView Pin
Metaldude
19:10 25 Jan '05  
GeneralZip files have been updated... Pin
Metaldude
9:16 13 Dec '04  
Generaltransparent background Pin
Michel Wassink
21:31 5 Dec '04  
GeneralRe: transparent background Pin
Metaldude
10:16 6 Dec '04  
GeneralRe: transparent background Pin
Michel Wassink
22:50 6 Dec '04  


Last Updated 27 Jan 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009