Click here to Skip to main content
15,891,607 members
Articles / Desktop Programming / WTL

CDialogRegionT - Skinning a WTL Dialog

Rate me:
Please Sign up or sign in to vote.
4.83/5 (20 votes)
29 Mar 2007CPOL2 min read 62.4K   2.3K   68  
Simplest way to skin a WTL Dialog in 3 easy steps
/*
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * DialogRegion.h:
 *                Implementation of CDialogRegionT template class. This class
 *          helps to skin WTL dialog. You'll have to either add bitmap in the
 *          applications' resource OR provide path to bitmap file
 * 
 *  Written by Robin Debnath (d.robin@gmail.com)
 * ___________________________________________________________________________ 
 *
 *  This code may be used in compiled form in any way you desire. This
 *  file may be redistributed by any means PROVIDING it is 
 *  not sold for profit without the authors written consent, and 
 *  providing that this notice and the authors name is included. 
 *  
 *  This file is provided "as is" with no expressed or implied warranty.
 *  The author accepts no liability if it causes any damage to you or your
 *  computer whatsoever. It's free, so don't hassle me about it.
 * ___________________________________________________________________________ 
 *     
 *  __ USAGE _________________________________________________________________
 *   ________________________________________________________________________ 
 *  |WARNING: While working with static controls ensure that the application |
 *  |         does NOT request for common controls 6. In case the project is |
 *  |         manifested you'll have to remove it from your .rc file.        |
 *  |________________________________________________________________________|
 *
 *  In order to skin the Dialog follow the steps below after you include this
 *  header:
 *    ______________
 *      STEP #1: Inherit from this template making the dialog class as base 
 *      _______  for this template
 *
 *               class CMainDlg: public CDialogImpl<CMainDlg>, 
 *                               ...
 *                               ...
 *                               CDialogRegionT<CMainDlg>    // this is step1
 *               {
 *    ______________ 
 *      STEP #2: Add an entry in message map to chain the messages
 *      _______
 *               BEGIN_MSG_MAP(CMainDlg)
 *                   MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
 *                   ...
 *                   ...
 *                   CHAIN_MSG_MAP(CDialogRegionT<CMainDlg>) // this is step2
 *               END_MSG_MAP()
 *    ______________
 *      STEP #3: Set the skin file. You do this by adding the following line
 *      _______  in routine correscponding to WM_INITDIALOG message.
 *
 *               LRESULT CMainDlg::OnInitDialog(UINT uMsg, WPARAM wParam, 
 *                                              LPARAM lParam, BOOL& bHandled)
 *               {
 *                   SetBkBitmap(IDB_BITMAP, 
 *                                 RGB(255,255,0), false);   // this is step3
 *                   //
 *                   // Existing code
 *                   //
 *                   return TRUE;
 *               }
 *  __________________________________________________________________________
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 */


#pragma once

template <class T>
class CDialogRegionT
{
public:
	HRGN     m_hRgn;          // the bitmap region
	BITMAP   m_bmpInfo;       // contains bitmap info
	HDC      m_hdcBmp;        // bitmap device context
	CBitmap  m_Bitmap;        // the bitmap
	BOOL     m_bIsRgnSet;     // Indicates if the region is set
	BOOL     m_bDlgMove;      // Indicates if dialog can be moved by clicking
	                          //  and dragging on any part of dialog
	COLORREF m_crTransparent; // the color which is to be drawn as transparent
public:	

	BEGIN_MSG_MAP(CMainDlg)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkGnd)
		MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnCtlColorStatic)
		MESSAGE_HANDLER(WM_NCHITTEST, OnNCHitTest)
	END_MSG_MAP()

	CDialogRegionT()
	{
		m_bIsRgnSet		= FALSE;
		m_bDlgMove		= FALSE;
		m_hRgn			= NULL;
		m_crTransparent = RGB(255, 0, 255);
	}
	
	~CDialogRegionT()
	{
		if(m_hRgn)
			DeleteObject(m_hRgn);
		if(m_Bitmap)
			m_Bitmap.DeleteObject();
	}


	bool SetDialogRegion()
	{
		T* pT = static_cast<T*>(this);

		// Set the window region
		int iRet = pT->SetWindowRgn( m_hRgn, TRUE );

		if( iRet == 0 )
			return false;	// Ups something went wrong

		int iX  = (GetSystemMetrics(SM_CXSCREEN)) / 2 - (m_bmpInfo.bmWidth / 2);
		int iY  = (GetSystemMetrics(SM_CYSCREEN)) / 2 - (m_bmpInfo.bmHeight / 2);
		
		// Size the window to the size of bitmap
		iRet = pT->SetWindowPos( HWND_NOTOPMOST , iX, iY, m_bmpInfo.bmWidth, m_bmpInfo.bmHeight, NULL );

		m_bIsRgnSet = true;

		return true;
	}

	bool GenerateRegion()
	{
		m_hdcBmp = CreateCompatibleDC(NULL);

		// Get info about the bitmap 
		GetObject(m_Bitmap, sizeof(m_bmpInfo), &m_bmpInfo);
		HGDIOBJ hGdiObj = SelectObject(m_hdcBmp, m_Bitmap);
		m_hRgn = CreateRectRgn(0,0,0,0);

		int iX = 0;
		int iRet = 0;
		for (int iY = 0; iY < m_bmpInfo.bmHeight; iY++)
		{
			do
			{
				while ( iX < m_bmpInfo.bmWidth && GetPixel(m_hdcBmp, iX, iY) == m_crTransparent )
					iX++;
				int iLeftX = iX;
				while ( iX < m_bmpInfo.bmWidth && GetPixel(m_hdcBmp, iX, iY) != m_crTransparent )
					++iX;
				HRGN hRgnTemp = CreateRectRgn(iLeftX, iY, iX, iY+1);
				iRet = CombineRgn(m_hRgn, m_hRgn, hRgnTemp, RGN_OR);
				if(iRet == ERROR)
				{
					return false;
				}

				//delete the temp region for next pass
				DeleteObject(hRgnTemp);
			}while(iX < m_bmpInfo.bmWidth);
			iX = 0;
		}
		
		return true;
	}
	
	bool SetBKBitmap(unsigned int iResourceID, COLORREF crTransparent, bool bDlgMove = true)
	{
		m_crTransparent	= crTransparent;
		return SetBKBitmap(iResourceID, bDlgMove);
	}

	bool SetBKBitmap(unsigned int iResourceID, bool bDlgMove = true)
	{
		bool bRetVal = false;
		
		ATLASSERT(m_Bitmap == NULL);
		// Load the resource bitmap image
		m_Bitmap.LoadBitmap(iResourceID);

		bRetVal	= processBitmap();
		
		if( bRetVal )
			m_bDlgMove = bDlgMove;

		return bRetVal;
	}

	bool SetBKBitmap(LPCTSTR szBMPfileName, COLORREF crTransparent, bool bDlgMove = true)
	{
		m_crTransparent	= crTransparent;
		return SetBKBitmap(szBMPfileName, bDlgMove);
	}

	bool SetBKBitmap(LPCTSTR szBMPfileName, bool bDlgMove = true)
	{
		bool bRetVal = false;
	
		ATLASSERT(m_Bitmap == NULL);
		// Load the bitmap image
		m_Bitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBMPfileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
		
		bRetVal	= processBitmap();
		
		if( bRetVal )
			m_bDlgMove = bDlgMove;

		return bRetVal;
	}

	bool processBitmap()
	{
		T* pT = static_cast<T*>(this);

		long oldWinStyle = pT->GetWindowLong(GWL_STYLE);

		if(m_Bitmap == NULL)
			return false;		// Ups we dont have a bitmap image

		// Set the window style to WS_POPUPWINDOW and remove borders
		int iRetVal	= pT->SetWindowLong( GWL_STYLE,  oldWinStyle & WS_POPUPWINDOW & ~WS_BORDER );

		if(iRetVal == 0)
		{
			// Something went wrong
			m_Bitmap.DeleteObject();
			return false;
		}

		if( !GenerateRegion() )
		{
			// Something went wrong, set the old window style
			pT->SetWindowLong( GWL_STYLE, oldWinStyle );
			return false;
		}
		
		// set the region for dialog
		SetDialogRegion();

		return true;
	}

	LRESULT OnEraseBkGnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(m_bIsRgnSet)
		{
			HDC hDC = (HDC) wParam;
			BitBlt(hDC, 0, 0, m_bmpInfo.bmWidth, m_bmpInfo.bmHeight, m_hdcBmp, 0, 0, SRCCOPY);
		}
		bHandled = m_bIsRgnSet;
		return 0;
	}

	LRESULT OnCtlColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		// We handle this message only if we have set the region
		bHandled = m_bIsRgnSet;

		if(m_bIsRgnSet)
		{
			::SetBkMode((HDC)wParam, TRANSPARENT);
			return (LRESULT) GetStockObject (HOLLOW_BRUSH);
		}
		return 0;
	}

	LRESULT OnNCHitTest(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		// We handle this message only if we have set the region
		bHandled = m_bIsRgnSet;

		if(m_bDlgMove)	// check if we can move the dialog
		{
			return HTCAPTION;
		}
		else
		{
			return 0;
		}
	}
};

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

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

License

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


Written By
Software Developer (Senior)
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions