Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

CKCSideBannerWnd: An MFC Banner Control that Can Add a Professional-looking Feel to Most Windows...

, 6 Nov 2003
A CWnd-derived control that can attach itself to any window, without the programmer making provisions for it
Prize winner in Competition "MFC/C++ Sep 2003"
kcsidebannerwnd_demo.zip
SideBanner
Release
SideBanner.exe
res
ico00001.ico
icon1.ico
texture.bmp
SideBanner.clw
SideBanner.dsp
SideBanner.dsw
/****************************************************************************
 *	class		:	CKCSideBannerWnd
 *	author		:	Peter Mares / kinkycode.com (gui@kinkycode.com)
 *	base class	:	CWnd (MFC)
 *	notes		:	A control to act as a banner to a window. More of a look'n'feel
 *					control.
 *					NOTE: Remember to link to MSIMG32.LIB to enable GradientFill()
 *
 *	Blurb		:	Its free, it feels good and its from South Africa :)
 ****************************************************************************
 *	Version History:
 *
 *	v0.1 (20-Oct-2003)
 *
 *	- First public release
 *
 *	v0.2 (24-Oct-2003)
 *
 *	- Added (Set)(Get)ColTxtTitle() and (Set)(Get)ColTxtCaption() functions
 *	- Revised all other updates since initial release
 *
 *	v0.3 (25-Oct-2003)
 *
 *	- Changed the SetIcon() function to support a delete flag
 *	- Added SetTexture() function
 *	- Fixed a resource leak
 *
 *	v0.31 (26-Oct-2003)
 *
 *	- Added UNICODE support to the control - thanks to Abraxas23
 *
 *	v0.32 (29-Oct-2003)
 *
 *	- Added support for gradient drawing without the dependancy on MSIMG32.LIB
 *    Used John A. Johnson's GradientFill() function, and used dynamic linking
 *	  of the MSIMG32.DLL (thanks to Irek Zielinski's code)
 *
 ****************************************************************************/

#include "stdafx.h"
#include "KCSideBannerWnd.h"

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

/////////////////////////////////////////////////////////////////////////////
// CKCSideBannerWnd

CKCSideBannerWnd::CKCSideBannerWnd()
: CWndUtil(KCSB_CLASSNAME)
, m_pOwner(NULL)
, m_nSize(50)
, m_uPosFlag(0)
, m_uFillFlag(KCSB_FILL_GRADIENT)
, m_colBkg(RGB(255,255,255))
, m_colBkg2(RGB(128,128,192))
, m_colTxtTitle(RGB(0,0,0))
, m_colTxtCaption(RGB(0,0,0))
, m_colEdge(RGB(0,0,0))
, m_strTitle(_T("This is the sample title"))
, m_strCaption(_T("This is the sample caption..."))
, m_szEdgeOffset(5,3)
, m_szCaptionOffset(4, 10)
, m_uIconPos(KCSB_ICON_RIGHT)
, m_hIcon(0)
, m_bIconDelete(false)
, m_hBkgBitmap(0)
, m_bBmpDelete(false)
, m_pGradFill(NULL)
, m_hGradMod(0)
{
	RegisterWndClass();

	CFont			font;

	font.CreatePointFont(110, _T("Tahoma Bold"));
	font.GetLogFont(&m_lfTitle);
	font.DeleteObject();
	font.CreatePointFont(85, _T("Tahoma"));
	font.GetLogFont(&m_lfCaption);
	font.DeleteObject();

	// try and load the MSIMG32.LIB
	if ( (m_hGradMod = LoadLibrary(_T("MSIMG32.DLL"))) )
		m_pGradFill = (PFNGRADFILL) GetProcAddress( m_hGradMod, "GradientFill" );
}

/////////////////////////////////////////////////////////////////////////////

CKCSideBannerWnd::~CKCSideBannerWnd()
{
	if ( m_hBkgBitmap && m_bBmpDelete )
		::DeleteObject(m_hBkgBitmap);
	if ( m_hIcon && m_bIconDelete )
		::DeleteObject(m_hIcon);
	if ( m_hGradMod )
		::FreeLibrary(m_hGradMod);
}

/////////////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CKCSideBannerWnd, CWnd)
	//{{AFX_MSG_MAP(CKCSideBannerWnd)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

BOOL CKCSideBannerWnd::Attach(CWnd* pWnd, unsigned int uFlags, unsigned int uiID)
{
	ASSERT(pWnd);
	if ( !pWnd )
		return FALSE;
	ASSERT(pWnd->m_hWnd);
	if ( !pWnd->m_hWnd )
		return FALSE;

	CRect				rect;

	m_pOwner = pWnd;
	m_pOwner->GetWindowRect(&rect);
	m_pOwner->ClientToScreen(&rect);

	m_uPosFlag = uFlags;

	// Banner LEFT
	if ( uFlags & KCSB_ATTACH_LEFT )
	{
		rect.left -= m_nSize;
		if ( rect.left < 0 )
			rect.OffsetRect( -rect.left, 0 );
	}
	// Banner RIGHT
	else if ( uFlags & KCSB_ATTACH_RIGHT )
	{
		rect.right += m_nSize;
	}
	// Banner TOP
	else if ( uFlags & KCSB_ATTACH_TOP )
	{
		rect.top -= m_nSize;
		if ( rect.top < 0 )
			rect.OffsetRect( 0, -rect.top );
	}
	// Banner BOTTOM
	else if ( uFlags & KCSB_ATTACH_BOTTOM )
	{
		rect.bottom += m_nSize;
	}
	// update the size of the owner
	m_pOwner->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);

	// update the positions of the child controls
	UpdateLayout(m_nSize);

	// attach the banner respective to its positional flag
	m_pOwner->GetClientRect(&rect);
	if ( uFlags & KCSB_ATTACH_LEFT )
		rect.right = rect.left + m_nSize;
	else if ( uFlags & KCSB_ATTACH_RIGHT )
		rect.left = rect.right - m_nSize;
	else if ( uFlags & KCSB_ATTACH_TOP )
		rect.bottom = rect.top + m_nSize;
	else if ( uFlags & KCSB_ATTACH_BOTTOM )
		rect.top = rect.bottom - m_nSize;

	// et voila... create the banner..
	Create(WS_CHILD | WS_VISIBLE, rect, m_pOwner, uiID);

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::SetSize(int nSize)
{
	if ( m_hWnd )
	{
		CRect			rect;

		//
		// offset the controls accordingly
		if ( m_uPosFlag & KCSB_ATTACH_LEFT || m_uPosFlag & KCSB_ATTACH_TOP )
		{
			UpdateLayout( nSize - m_nSize );
		}

		//
		// size the containing window
		m_pOwner->GetWindowRect(&rect);

		if ( m_uPosFlag & KCSB_ATTACH_LEFT )
		{
			rect.left -= (nSize-m_nSize);
			if ( rect.left < 0 )
				rect.OffsetRect( -rect.left, 0 );
			m_pOwner->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
		}
		else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
		{
			rect.left -= (nSize - m_nSize);
			m_pOwner->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
		}
		else if ( m_uPosFlag & KCSB_ATTACH_TOP )
		{
			rect.top -= (nSize - m_nSize);
			if ( rect.top < 0 )
				rect.OffsetRect( 0, -rect.top );
			m_pOwner->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
		}
		else if ( m_uPosFlag & KCSB_ATTACH_BOTTOM )
		{
			rect.top -= (nSize - m_nSize );
			m_pOwner->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
		}
	
		// size the banner
		GetClientRect(&rect);
		if ( m_uPosFlag & KCSB_ATTACH_LEFT )
			rect.right = rect.left + nSize;
		else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
			rect.right = rect.left + nSize;
		else if ( m_uPosFlag & KCSB_ATTACH_TOP )
			rect.bottom = rect.top + nSize;
		else if ( m_uPosFlag & KCSB_ATTACH_BOTTOM )
			rect.bottom = rect.top + nSize;
		MoveWindow(&rect);

		m_pOwner->Invalidate();

	}

	m_nSize = nSize;
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::UpdateSize()
{
	if ( !m_hWnd )
		return;

	CRect				rect;

	m_pOwner->GetClientRect(&rect);
	if ( m_uPosFlag & KCSB_ATTACH_LEFT )
		rect.right = rect.left + m_nSize;
	else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
		rect.left = rect.right - m_nSize;
	else if ( m_uPosFlag & KCSB_ATTACH_TOP )
		rect.bottom = rect.top + m_nSize;
	else if ( m_uPosFlag & KCSB_ATTACH_BOTTOM )
		rect.top = rect.bottom - m_nSize;

	MoveWindow(&rect, TRUE);
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::SetPosFlag(unsigned int uFlags)
{
	if ( (uFlags & 0xF) == (m_uPosFlag & 0xF) )
		return;

	CRect				rect;
	int					nSize = m_nSize;

	SetSize(0);
	m_uPosFlag = uFlags;
	SetSize(nSize);

	m_pOwner->GetClientRect(&rect);

	if ( uFlags & KCSB_ATTACH_LEFT )
		rect.right = rect.left + nSize;
	else if ( uFlags & KCSB_ATTACH_RIGHT )
		rect.left = rect.right - nSize;
	else if ( uFlags & KCSB_ATTACH_TOP )
		rect.bottom = rect.top + nSize;
	else if ( uFlags & KCSB_ATTACH_BOTTOM )
		rect.top = rect.bottom - nSize;

	MoveWindow(&rect);
	
	m_pOwner->Invalidate();
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::UpdateLayout(int nOffset)
{
	stEnum				data;

	data.pBannerWnd = this;
	data.pParentWnd = m_pOwner;
	data.nOffset = nOffset;
	data.uFlags = m_uPosFlag;

	::EnumChildWindows( m_pOwner->m_hWnd, ChildEnumProc, (LPARAM)&data );
}

/////////////////////////////////////////////////////////////////////////////

BOOL CALLBACK CKCSideBannerWnd::ChildEnumProc(HWND hWndChild, LPARAM lParam)
{
	stEnum*			pData = (stEnum*) lParam;
	HWND			hWndParent = 0;
	CRect			rect;
	POINT			topLeft, bottomRight;

	// check if the hwnd is valid, and check that its not the HWND to the banner
	if ( hWndChild && hWndChild != pData->pBannerWnd->m_hWnd )
	{
		// now we check if the parent is actually the parent of the banner..
		// this check was put it to deal with composite controls like a combobox..
		// NOTE: For some reason, a combobox's edit control appears to be a child
		// of the parent, until you query for its parent HWND.
		hWndParent = ::GetParent(hWndChild);
		if ( hWndParent == pData->pParentWnd->m_hWnd )
		{
			// we have a valid child window which we can now reposition
			::GetWindowRect(hWndChild, &rect);
			topLeft.x = rect.left;
			topLeft.y = rect.top;
			bottomRight.x = rect.right;
			bottomRight.y = rect.bottom;
			::ScreenToClient( pData->pParentWnd->m_hWnd, &topLeft );
			::ScreenToClient( pData->pParentWnd->m_hWnd, &bottomRight );
			if ( pData->uFlags & KCSB_ATTACH_LEFT )
			{
				topLeft.x += pData->nOffset;
				bottomRight.x += pData->nOffset;
			}
			else if ( pData->uFlags & KCSB_ATTACH_TOP )
			{
				topLeft.y += pData->nOffset;
				bottomRight.y += pData->nOffset;
			}
			::MoveWindow( hWndChild, topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, TRUE );
		}
	}

	// return TRUE to continue enumerating...
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CKCSideBannerWnd message handlers
/////////////////////////////////////////////////////////////////////////////

BOOL CKCSideBannerWnd::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	BOOL		bResult = CWnd::Create(KCSB_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID, pContext);

	return bResult;
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::OnPaint() 
{
	CPaintDC			dc(this); // device context for painting
	CDC					memDC;
	CBitmap				memBMP, *pOldBmp = NULL;
	CRect				rect;

	GetClientRect(&rect);

	// create mem DC
	memDC.CreateCompatibleDC(&dc);
	memBMP.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
	pOldBmp = memDC.SelectObject(&memBMP);

	// draw the banner
	DrawBackground(&memDC, rect);
	DrawTextFields(&memDC, rect);

	// render the image
	dc.BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);

	// deselect object
	memDC.SelectObject(pOldBmp);

	// delete objects
	memBMP.DeleteObject();
	memDC.DeleteDC();
}

/////////////////////////////////////////////////////////////////////////////

BOOL CKCSideBannerWnd::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::DrawBackground(CDC* pDC, CRect rect)
{
	CBrush				nBrush, *pOldBrush = NULL;
	CPen				nPen, *pOldPen = NULL;

	// Flat fill...
	if ( m_uFillFlag & KCSB_FILL_FLAT || ( (m_colBkg == m_colBkg2) && (m_uFillFlag & KCSB_FILL_GRADIENT) ))
	{
		pDC->FillSolidRect(&rect, m_colBkg);
		DrawEdge(pDC, rect);
	}
	// Gradient fill
	else if ( m_uFillFlag & KCSB_FILL_GRADIENT )
	{
		TRIVERTEX			vert[2];
		GRADIENT_RECT		gRect;
		ULONG				uGFlag;

		if ( m_pGradFill )		// can we use the MSIMG32.DLL function?
		{
			if ( (m_uPosFlag & KCSB_ATTACH_LEFT) || (m_uPosFlag & KCSB_ATTACH_RIGHT) )
			{
				// set the gradient fill according to position
				if ( m_uPosFlag & KCSB_ATTACH_LEFT )
				{
					vert[0].x = 0;
					vert[0].y = rect.top;
					vert[0].Red = GetRValue(m_colBkg2)<<8;
					vert[0].Green = GetGValue(m_colBkg2)<<8;
					vert[0].Blue = GetBValue(m_colBkg2)<<8;
					vert[0].Alpha = 0;

					vert[1].x = rect.right;
					vert[1].y = rect.bottom;
					vert[1].Red = GetRValue(m_colBkg)<<8;
					vert[1].Green = GetGValue(m_colBkg)<<8;
					vert[1].Blue = GetBValue(m_colBkg)<<8;
					vert[1].Alpha = 0;
				}
				else
				{
					vert[0].x = rect.right;
					vert[0].y = rect.top;
					vert[0].Red = GetRValue(m_colBkg)<<8;
					vert[0].Green = GetGValue(m_colBkg)<<8;
					vert[0].Blue = GetBValue(m_colBkg)<<8;
					vert[0].Alpha = 0;

					vert[1].x = 0;
					vert[1].y = rect.bottom;
					vert[1].Red = GetRValue(m_colBkg2)<<8;
					vert[1].Green = GetGValue(m_colBkg2)<<8;
					vert[1].Blue = GetBValue(m_colBkg2)<<8;
					vert[1].Alpha = 0;
				}
				uGFlag = GRADIENT_FILL_RECT_V;
			}
			else
			{
				vert[0].x = 0;
				vert[0].y = rect.top;
				vert[0].Red = GetRValue(m_colBkg)<<8;
				vert[0].Green = GetGValue(m_colBkg)<<8;
				vert[0].Blue = GetBValue(m_colBkg)<<8;
				vert[0].Alpha = 0;

				vert[1].x = rect.right;
				vert[1].y = rect.bottom;
				vert[1].Red = GetRValue(m_colBkg2)<<8;
				vert[1].Green = GetGValue(m_colBkg2)<<8;
				vert[1].Blue = GetBValue(m_colBkg2)<<8;
				vert[1].Alpha = 0;
				uGFlag = GRADIENT_FILL_RECT_H;
			}

			gRect.UpperLeft = 0;
			gRect.LowerRight = 1;

			// do the fill :)
			m_pGradFill( pDC->m_hDC, vert, 2, &gRect, 1, uGFlag );
		}
		else
		{
			// added 2003-Oct-29
			bool bFlip = false, bHorz = false;

			if ( (m_uPosFlag & KCSB_ATTACH_TOP) || (m_uPosFlag & KCSB_ATTACH_BOTTOM) )
			{
				bFlip = true;
				bHorz = true;
			}
			else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
			{
				bFlip = true;
			}
 
			GradientFill(pDC, m_colBkg, m_colBkg2, rect, bHorz, bFlip);
		}

		DrawEdge(pDC, rect);
	}
	// Gradient fill
	else if ( m_uFillFlag & KCSB_FILL_TEXTURE )
	{
		CBitmap			bmp;
		
		bmp.Attach(m_hBkgBitmap);

		nBrush.CreatePatternBrush(&bmp);
		pOldBrush = pDC->SelectObject(&nBrush);
		pDC->SelectStockObject(NULL_PEN);
		rect.InflateRect(1,1,1,1);
		pDC->Rectangle( &rect );
		rect.DeflateRect(1,1,1,1);
		DrawEdge(pDC, rect);

		bmp.Detach();
	}
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::DrawEdge(CDC* pDC, CRect rect)
{
	CPen				nPen, *pOldPen = NULL;

	nPen.CreatePen( PS_SOLID, 0, m_colEdge );
	pOldPen = pDC->SelectObject(&nPen);

	if ( m_uPosFlag & KCSB_ATTACH_LEFT )
	{
		pDC->MoveTo(rect.right-1, rect.top);
		pDC->LineTo(rect.right-1, rect.bottom);
	}
	else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
	{
		pDC->MoveTo(rect.left, rect.top);
		pDC->LineTo(rect.left, rect.bottom);
	}
	else if ( m_uPosFlag & KCSB_ATTACH_TOP )
	{
		pDC->MoveTo(rect.left, rect.bottom-1);
		pDC->LineTo(rect.right, rect.bottom-1);
	}
	else if ( m_uPosFlag & KCSB_ATTACH_BOTTOM )
	{
		pDC->MoveTo(rect.left, rect.top);
		pDC->LineTo(rect.right, rect.top);
	}

	pDC->SelectObject(pOldPen);
	nPen.DeleteObject();
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::DrawTextFields(CDC* pDC, CRect rect)
{
	CPoint				pt, pt2;

	if ( m_hIcon )
		DrawBannerIcon(pDC, rect);

	// configure the font
	if ( m_uPosFlag & KCSB_ATTACH_LEFT )
	{
		m_lfTitle.lfEscapement = m_lfTitle.lfOrientation = 
		m_lfCaption.lfEscapement = m_lfCaption.lfOrientation = 900;
		pt.x = rect.left + m_szEdgeOffset.cx;
		pt.y = rect.bottom - m_szEdgeOffset.cy;
		pt2.x = pt.x - m_lfTitle.lfHeight + m_szCaptionOffset.cx;
		pt2.y = pt.y - m_szCaptionOffset.cy;
	}
	else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
	{
		m_lfTitle.lfEscapement = m_lfTitle.lfOrientation = 
		m_lfCaption.lfEscapement = m_lfCaption.lfOrientation = -900;
		pt.x = rect.right - m_szEdgeOffset.cx;
		pt.y = rect.top + m_szEdgeOffset.cy;
		pt2.x = pt.x + m_lfTitle.lfHeight - m_szCaptionOffset.cx;
		pt2.y = pt.y + m_szCaptionOffset.cy;
	}
	else if ( ( m_uPosFlag & KCSB_ATTACH_TOP ) || ( m_uPosFlag & KCSB_ATTACH_BOTTOM ) )
	{
		m_lfTitle.lfEscapement = m_lfTitle.lfOrientation = 
		m_lfCaption.lfEscapement = m_lfCaption.lfOrientation = 0;
		pt.x = rect.left + m_szEdgeOffset.cx;
		pt.y = rect.top + m_szEdgeOffset.cy;
		pt2.x = pt.x + m_szCaptionOffset.cx;
		pt2.y = pt.y - m_lfTitle.lfHeight + m_szCaptionOffset.cy;
	}

	int					nOldBkMode = pDC->SetBkMode(TRANSPARENT);
	CFont				nFont, *pOldFont = NULL;
	COLORREF			oldTxtCol = pDC->SetTextColor(m_colTxtTitle);

	//
	// draw the title
	nFont.CreateFontIndirect(&m_lfTitle);
	pOldFont = pDC->SelectObject(&nFont);
	pDC->TextOut(pt.x, pt.y, m_strTitle);
	pDC->SelectObject(pOldFont);
	nFont.DeleteObject();

	//
	// draw the caption
	pDC->SetTextColor(m_colTxtCaption);
	nFont.CreateFontIndirect(&m_lfCaption);
	pOldFont = pDC->SelectObject(&nFont);

	int				arrWidths[256];
	pDC->GetCharWidth(0, 255, arrWidths);

	int			nCount = m_strCaption.GetLength(), i, nHeight = 0;
	CPoint		ptDraw = pt2;
	TCHAR		ch;

	for ( i = 0; i < nCount; i++ )
	{
		ch = m_strCaption.GetAt(i);
		if ( ch == '\r' )
			continue;
		if ( ch == '\n' )
		{
			if ( m_uPosFlag & KCSB_ATTACH_LEFT )
			{
				ptDraw = pt2;
				ptDraw.x -= m_lfCaption.lfHeight * (++nHeight);
			}
			else if ( (m_uPosFlag & KCSB_ATTACH_TOP) || (m_uPosFlag & KCSB_ATTACH_BOTTOM) )
			{
				ptDraw = pt2;
				ptDraw.y -= m_lfCaption.lfHeight * (++nHeight);
			}
			else if ( (m_uPosFlag & KCSB_ATTACH_RIGHT) )
			{
				ptDraw = pt2;
				ptDraw.x += m_lfCaption.lfHeight * (++nHeight);
			}
			continue;
		}
		pDC->TextOut( ptDraw.x, ptDraw.y, CString((char)ch) );
		if ( m_uPosFlag & KCSB_ATTACH_LEFT )
		{
			ptDraw.y -= arrWidths[ch];
			if ( (i < nCount-1) && 
				 ptDraw.y - arrWidths[m_strCaption.GetAt(i+1)] < rect.top )
			{
				ptDraw = pt2;
				ptDraw.x -= m_lfCaption.lfHeight * (++nHeight);
			}
		}
		else if ( (m_uPosFlag & KCSB_ATTACH_TOP) || (m_uPosFlag & KCSB_ATTACH_BOTTOM) )
		{
			ptDraw.x += arrWidths[ch];
			if ( (i < nCount-1) &&
				 ptDraw.x + arrWidths[m_strCaption.GetAt(i+1)] > rect.right )
			{
				ptDraw = pt2;
				ptDraw.y -= m_lfCaption.lfHeight * (++nHeight);
			}
		}
		else if ( (m_uPosFlag & KCSB_ATTACH_RIGHT) )
		{
			ptDraw.y += arrWidths[ch];
			if ( (i < nCount-1) && 
				 ptDraw.y + arrWidths[m_strCaption.GetAt(i+1)] > rect.bottom )
			{
				ptDraw = pt2;
				ptDraw.x += m_lfCaption.lfHeight * (++nHeight);
			}		
		}

	}
	pDC->SelectObject(pOldFont);
	nFont.DeleteObject();

	pDC->SetBkMode(nOldBkMode);
	pDC->SetTextColor(oldTxtCol);
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::DrawBannerIcon(CDC* pDC, CRect& rect)
{
	if ( !m_hIcon )
		return;

	CPoint			pt;

	// Banner on LEFT
	if ( m_uPosFlag & KCSB_ATTACH_LEFT )
	{
		// ICON to LEFT
		if ( m_uIconPos & KCSB_ICON_LEFT )
		{
			rect.bottom -= (m_szEdgeOffset.cy + m_bmpInfo.bmHeight);
			pt.y = rect.bottom;
		}
		// ICON to RIGHT
		else if ( m_uIconPos & KCSB_ICON_RIGHT )
		{
			rect.top += (m_szEdgeOffset.cy);
			pt = rect.TopLeft();
		}

		// VTOP
		if ( m_uIconPos & KCSB_ICON_TOP )
			pt.x = rect.left;
		// VCENTER
		else if ( m_uIconPos & KCSB_ICON_VCENTER )
			pt.x = rect.CenterPoint().x - (m_bmpInfo.bmWidth/2);
		// VBOTTOM
		else if ( m_uIconPos & KCSB_ICON_BOTTOM )
			pt.x = rect.right - m_bmpInfo.bmWidth - 1;

	}
	// Banner on RIGHT
	else if ( m_uPosFlag & KCSB_ATTACH_RIGHT )
	{
		// ICON to LEFT
		if ( m_uIconPos & KCSB_ICON_LEFT )
		{
			rect.top += ( m_szEdgeOffset.cy );
			pt.y = rect.top;
			rect.top += m_bmpInfo.bmHeight;
		}
		// ICON to RIGHT
		else if ( m_uIconPos & KCSB_ICON_RIGHT )
		{
			rect.bottom -= (m_szEdgeOffset.cy + m_bmpInfo.bmHeight);
			pt.x = rect.left;
			pt.y = rect.bottom;
		}

		// VTOP
		if ( m_uIconPos & KCSB_ICON_TOP )
			pt.x = rect.right - m_bmpInfo.bmWidth;
		// VCENTER
		else if ( m_uIconPos & KCSB_ICON_VCENTER )
			pt.x = rect.CenterPoint().x - (m_bmpInfo.bmWidth/2);
		// VBOTTOM
		else if ( m_uIconPos & KCSB_ICON_BOTTOM )
			pt.x = rect.left + 1;
	}
	// Banner on TOP OR BOTTOM
	else if ( (m_uPosFlag & KCSB_ATTACH_TOP) ||
			  (m_uPosFlag & KCSB_ATTACH_BOTTOM) )
	{
		// ICON to LEFT
		if ( m_uIconPos & KCSB_ICON_LEFT )
		{
			rect.left += m_szEdgeOffset.cx;
			pt = rect.TopLeft();
			rect.left += m_bmpInfo.bmWidth;
		}
		// ICON to RIGHT
		else if ( m_uIconPos & KCSB_ICON_RIGHT )
		{
			rect.right -= ( m_szEdgeOffset.cx + m_bmpInfo.bmWidth);
			pt.x = rect.right;
			pt.y = rect.top;
		}

		// VTOP
		if ( m_uIconPos & KCSB_ICON_TOP )
			pt.y = rect.top+1;
		// VCENTER
		else if ( m_uIconPos & KCSB_ICON_VCENTER )
			pt.y = rect.CenterPoint().y - (m_bmpInfo.bmHeight/2);
		// VBOTTOM
		else if ( m_uIconPos & KCSB_ICON_BOTTOM )
			pt.y = rect.bottom - m_bmpInfo.bmHeight-1;
	}
	pDC->DrawIcon( pt.x, pt.y, m_hIcon );
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::SetCaptionFont(CFont* pFont)
{
	if ( !pFont )
		return;

	pFont->GetLogFont(&m_lfCaption);
	Invalidate();
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::GetCaptionFont(LOGFONT* pFont)
{
	if ( !pFont )
		return;

	memcpy(pFont, &m_lfCaption, sizeof(LOGFONT));
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::SetTitleFont(CFont* pFont)
{
	if ( !pFont )
		return;

	pFont->GetLogFont(&m_lfTitle);
	Invalidate();
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::GetTitleFont(LOGFONT* pFont)
{
	if ( !pFont )
		return;

	memcpy(pFont, &m_lfTitle, sizeof(LOGFONT));
}

/////////////////////////////////////////////////////////////////////////////

bool CKCSideBannerWnd::SetIcon(HICON hIcon, UINT uiIconPos, bool bSelfDelete)
{
	bool			bResult = true;

	if ( m_bIconDelete && m_hIcon )
		::DeleteObject(m_hIcon);

	m_bIconDelete = bSelfDelete;
	m_uIconPos = uiIconPos;
	m_hIcon = hIcon;

	if ( m_hIcon )
	{
		// calculate the size of the icon
		ICONINFO			ii;

		if ( !GetIconInfo( (HICON)m_hIcon, &ii ) )
			bResult = false;
		if ( !GetObject( ii.hbmColor, sizeof(BITMAP), &m_bmpInfo ) )
			bResult = false;
		else
		{
			DeleteObject(ii.hbmColor);
			DeleteObject(ii.hbmMask);
		}
	}

	if ( IsWindow(m_hWnd) && m_hIcon )
		Invalidate();

	return bResult;
}

/////////////////////////////////////////////////////////////////////////////

void CKCSideBannerWnd::SetTexture(HBITMAP hBitmap, bool bSelfDelete)
{
	if ( m_hBkgBitmap && m_bBmpDelete )
		::DeleteObject(m_hBkgBitmap);
	m_bBmpDelete = bSelfDelete;
	m_hBkgBitmap = hBitmap;
}

/////////////////////////////////////////////////////////////////////////////

// added 2003-Oct-29
void CKCSideBannerWnd::GradientFill(CDC* pDC, COLORREF col1, COLORREF col2, CRect rect, bool bHor, bool bFlip)
{	
	if (rect == CRect(0,0,0,0))  // no rectangle?	
	{		
		// get the clip area of the device context!		
		pDC->GetClipBox(rect);	
	} 	
	
	if (bFlip)	
	{		
		// exhange the 2 colors		
		COLORREF clr = col1;		
		col1 = col2;		
		col2 = clr;	
	} 	
	
	if (pDC->GetDeviceCaps(BITSPIXEL) > 8)	// gradient only for true color displays	
	{		
		// draw the gradient		
		int nLenght = (bHor ? rect.Width() : rect.Height()) - 1;		
		for (int i=0; i<=nLenght; i++)		
		{			
			CRect rcl	= rect; 			
			if (bHor)			
			{				
				rcl.left	+=  i;				
				rcl.right	+= (i + 1);			
			}			
			else			
			{				
				rcl.top		+=  i;				
				rcl.bottom	+= (i + 1);			
			} 			
			
			double dfL = (double)i / (double)nLenght; 			
			pDC->FillSolidRect(rcl, RGB(dfL * GetRValue(col1) + (1.0 - dfL) * GetRValue(col2),
							   dfL * GetGValue(col1) + (1.0 - dfL) * GetGValue(col2),				
							   dfL * GetBValue(col1) + (1.0 - dfL) * GetBValue(col2) ));		
		}	
	}	
	else	
	{		
		// a solid rectangle		
		pDC->FillSolidRect(rect, col1);	
	}
}

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)

About the Author

Peter Mares
Architect
Ireland Ireland
Peter Mares has no comment on himself. I'll let the objective humanoids do the damage Wink | ;)
He is currently developing a hobby MMO to prove that he can do it Wink | ;)

My Blog

All good things were meant to be improved
Follow on   Twitter

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 7 Nov 2003
Article Copyright 2003 by Peter Mares
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid