Click here to Skip to main content
15,891,981 members
Articles / Desktop Programming / MFC

ClassLib, A C++ class library

Rate me:
Please Sign up or sign in to vote.
4.80/5 (32 votes)
25 May 2005CPOL8 min read 401.7K   11.5K   141  
C++ class library.
//
// infobar.cpp
//
// (C) Copyright 2000 Jan van den Baard.
//     All Rights Reserved.
//

#include "infobar.h"
#include "../../gdi/getdc.h"
#include "../../gdi/paintdc.h"
#include "../../gdi/bufferdc.h"
#include "../../gdi/selector.h"
#include "../../gdi/brush.h"
#include "../../gdi/selector.h"
#include "../../coords/rect.h"
#include "../../tools/module.h"

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

// Constructor. Setup the defaults.
ClsInfoBar::ClsInfoBar()
{
	// Setup default values.
	m_hIcon			= NULL;
	m_crTitleColor		= ::GetSysColor( COLOR_CAPTIONTEXT );
	m_crBackgroundColor	= ::GetSysColor( COLOR_INACTIVECAPTION );
	m_crBackgroundGradient	= ::GetSysColor(
						 #ifndef COLOR_GRADIENTINACTIVECAPTION
						 28
						 #else
						 COLOR_GRADIENTINACTIVECAPTION
						 #endif
						 );
	m_bUseGradient		= FALSE;
	m_bIsVertical		= FALSE;
	m_bIsClipped		= FALSE;
	m_bCompactAsPath	= FALSE;
	m_bIconRight		= TRUE;
	m_hToolTip		= NULL;

	// By default this control uses the system caption
	// font.
	NONCLIENTMETRICS	ncm = { sizeof( NONCLIENTMETRICS ), 0 };
	if ( ::SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof( ncm ), ( void * )&ncm, 0 ))
	{
		// Create the fonts.
		m_fNormal = CreateFontIndirect( &ncm.lfCaptionFont );
		ncm.lfCaptionFont.lfEscapement = ncm.lfCaptionFont.lfOrientation = 900;
		ncm.lfCaptionFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
		m_fVertical = CreateFontIndirect( &ncm.lfCaptionFont );
	}
}

// Destructor.
ClsInfoBar::~ClsInfoBar()
{
	// Free the icon and tooltip.
	if ( m_hIcon ) DestroyIcon( m_hIcon );
	if ( m_hToolTip ) DestroyWindow( m_hToolTip );
}

// Set the icon.
BOOL ClsInfoBar::SetIcon( LPCTSTR pszIconName, BOOL bRepaint /* = TRUE */ )
{
	// Load up the icon.
	HICON hIcon = ( HICON )::LoadImage( ClsGetResourceHandle(), pszIconName, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR );

	// Did the icon load OK?
	if ( pszIconName && hIcon == NULL )
		return FALSE;

	// OK?
	// Destroy the previous icon.
	if ( m_hIcon ) ::DestroyIcon( m_hIcon );

	// Setup the new handle.
	m_hIcon = hIcon;

	// Re-render.
	if ( bRepaint && GetSafeHWND()) Invalidate();

	return TRUE;
}

// Set the icon.
BOOL ClsInfoBar::SetSystemIcon( LPCTSTR pszIconName, BOOL bRepaint /* = TRUE */ )
{
	// Load up the icon.
	HICON hIcon = ( HICON )::LoadImage( NULL, pszIconName, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR );

	// OK?
	if ( hIcon )
	{
		// Destroy the previous icon.
		if ( m_hIcon ) ::DestroyIcon( m_hIcon );

		// Setup the new handle.
		m_hIcon = hIcon;

		// Re-render.
		if ( bRepaint && GetSafeHWND()) Invalidate();

		return TRUE;
	}
	return FALSE;
}

// Show or hide tooltips.
BOOL ClsInfoBar::TipClippedCaption( BOOL bClip /* = TRUE */ )
{
	_ASSERT_VALID( GetSafeHWND()); // Must be valid.

	// Must we show tool-tips?
	if ( bClip && m_hToolTip == NULL )
	{
		// Make sure we are notified!
		ModifyStyle( 0, SS_NOTIFY );

		// Create the tooltip.
		m_hToolTip = CreateWindowEx( WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, TTS_ALWAYSTIP,
					     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd,
					     ( HMENU )NULL, ClsGetInstanceHandle(), NULL );

		// OK?
		if ( m_hToolTip == NULL ) return FALSE;

		// Initalize the TOOLINFO structure.
		TOOLINFO ti;
		ti.cbSize	= sizeof( TOOLINFO );
		ti.uFlags	= TTF_IDISHWND | TTF_SUBCLASS;
		ti.hwnd		= m_hWnd;
		ti.hinst	= ClsGetInstanceHandle();
		ti.uId		= ( UINT )( UINT_PTR )m_hWnd;
		ti.lpszText	= ( LPTSTR )LPSTR_TEXTCALLBACK;

		// Add the tooltip.
		if ( ! ::SendMessage( m_hToolTip, TTM_ADDTOOL, 0, ( LPARAM )&ti ))
		{
			::DestroyWindow( m_hToolTip );
			m_hToolTip = NULL;
			return FALSE;
		}
	}
	else if ( bClip == FALSE )
	{
		// Do we have a tooltip window.
		if ( m_hToolTip )
		{
			// Destroy it.
			::DestroyWindow( m_hToolTip );
			m_hToolTip = NULL;
		}
	}
	return TRUE;
}

// Notification handler.
LRESULT ClsInfoBar::OnNotify( LPNMHDR pNMHDR )
{
	// Correct notification?
	if ( pNMHDR->code == TTN_GETDISPINFO  && m_bIsClipped )
	{
		m_Title = m_hWnd;
		(( LPNMTTDISPINFO )pNMHDR )->lpszText = m_Title;
		return TRUE;
	}
	return FALSE;
}

// Window procedure override. Need to intercept the WM_SETFONT message.
LRESULT ClsInfoBar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	switch ( uMsg )
	{
		// WP_PRINT
		case	WM_PRINTCLIENT:
			// Render what?
			if ( lParam & PRF_ERASEBKGND ) SendMessage( WM_ERASEBKGND, wParam );
			if ( lParam & PRF_CLIENT     ) SendMessage( WM_PAINT, wParam );
			return 0;
			
		// WM_SETTEXT?
		case	WM_SETTEXT:
		{
			// Let the base have a go at it.
			LRESULT rc = ClsWindow::WindowProc( uMsg, wParam, lParam );
			Invalidate();
			UpdateWindow();
			return rc;
		}

		// WM_SETFONT?
		case	WM_SETFONT:
		{
			// Get the font.
			ClsFont *pFont = ClsFont::FromHandle(( HFONT )wParam );

			// Get the font information.
			LOGFONT lf;
			pFont->GetLogFont( &lf );

			// Create the normal font.
			m_fNormal.CreateFontIndirect( &lf );

			// Create the vertical font.
			lf.lfEscapement = lf.lfOrientation = 900;
			lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
			m_fVertical = CreateFontIndirect( &lf );
			break;
		}

		// WM_GETFONT?
		case	WM_GETFONT:
		{
			// Return the correct handle.
			if ( m_bIsVertical ) return ( LRESULT )(( HFONT )m_fVertical );
			return ( LRESULT )(( HFONT )m_fNormal );
		}
	}

	// Pass to the base class.
	return ClsWindow::WindowProc( uMsg, wParam, lParam );
}

// Paint the control.
void ClsInfoBar::PaintControl( ClsDC *pDC )
{
	// Get the client rectangle.
	ClsRect	rcClient = GetClientRect();

	// Any room to render in?
	if ( ! rcClient.IsEmpty())
	{
		// Setup an off-screen buffer.
		ClsBufferDC	dc( *pDC, rcClient );

		// Snapshot the DC.
		int sDC = dc.SaveDC();

		// See if we can use a gradient
		// fill for the background.
		TRIVERTEX       trVert[ 2 ];
		GRADIENT_RECT   gRect;
		COLORREF	crColor = m_bIsVertical ? m_crBackgroundGradient : m_crBackgroundColor;

		// Setup the top (or left) side of the rectangle.
		trVert[ 0 ].x      = rcClient.Left();
		trVert[ 0 ].y      = rcClient.Top();
		trVert[ 0 ].Red    = ( COLOR16 )( GetRValue( crColor ) << 8 );
		trVert[ 0 ].Green  = ( COLOR16 )( GetGValue( crColor ) << 8 );
		trVert[ 0 ].Blue   = ( COLOR16 )( GetBValue( crColor ) << 8 );
		trVert[ 0 ].Alpha  = 0x0000;

		// Setup the bottom (or right) size of the rectangle.
		crColor		   = m_bIsVertical ? m_crBackgroundColor : m_crBackgroundGradient;
		trVert[ 1 ].x      = rcClient.Right();
		trVert[ 1 ].y      = rcClient.Bottom();
		trVert[ 1 ].Red    = ( COLOR16 )( GetRValue( crColor ) << 8 );
		trVert[ 1 ].Green  = ( COLOR16 )( GetGValue( crColor ) << 8 );
		trVert[ 1 ].Blue   = ( COLOR16 )( GetBValue( crColor ) << 8 );
		trVert[ 1 ].Alpha  = 0x0000;

		// Tell the function where the upper-left
		// and lower-right corners are located in the
		// TRIVERTEXT array.
		gRect.UpperLeft  = 0;
		gRect.LowerRight = 1;

		// Fill the area.
		if ( m_bUseGradient == FALSE || dc.GradientFill( trVert, 2, &gRect, 1, m_bIsVertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H ) == FALSE )
		{
			// Simple fill the rectangle with the
			// background color.
			ClsBrush brush( m_crBackgroundColor );
			dc.FillRect( rcClient, &brush );
		}

		// Do we have an icon?
		if ( m_hIcon )
		{
			ClsPoint	pt;

			// Center the icon.
			if ( m_bIsVertical )
			{
				// Center horizontally.
				pt.X() = ( rcClient.Width() / 2 ) - 8;

				// Bottom or top?
				if ( m_bIconRight )
				{
					pt.Y() = rcClient.Top();
					rcClient.Top() += 20;
					rcClient.Bottom() -= 4;
				}
				else
				{
					pt.Y() = rcClient.Bottom() - 18;
					rcClient.Bottom() -= 20;
				}
			}
			else
			{
				// Center vertically.
				pt.Y() = ( rcClient.Height() / 2 ) - 8;

				// Left or right?
				if ( m_bIconRight )
				{
					pt.X() = rcClient.Right() - 18;
					rcClient.Right() -= 20;
					rcClient.Left() += 4;
				}
				else
				{
					pt.X() = rcClient.Left() + 2;
					rcClient.Left() += 20;
				}
			}

			// Render it at the left side of the area.
			dc.DrawIconEx( pt, m_hIcon, ClsSize( 16, 16 ), 0, NULL, DI_NORMAL );
		}
		else
		{
			// Shove the text 4 pixels to the right or up.
			if ( m_bIsVertical ) rcClient.Bottom() -= 4;
			else		     rcClient.Left()   += 4;
		}

		// Any room left?
		if ( ! rcClient.IsEmpty())
		{
			// Get the control title.
			ClsString title = m_hWnd;
			if( title.GetStringLength())
			{
				// Setup the color and draw mode.
				dc.SetTextColor( m_crTitleColor );
				dc.SetBkMode( TRANSPARENT );

				// Select the font to use.
				ClsSelector sel( &dc, m_bIsVertical ? m_fVertical : m_fNormal );

				// Get the size of the title string and
				// at the same time see how many characters
				// we can render.
				int nNum, nCX = m_bIsVertical ? rcClient.Height() : rcClient.Width();
				ClsSize	size = dc.GetTextExtentExPoint( title, nCX, &nNum );

				// The unicode version (XP Home SP1a) seems to return 6 on a 3 character
				// string?? This kludge fixes that problem.
				nNum = min( nNum, title.GetStringLength());

				// Will all characters fit?
				if ( nNum < title.GetStringLength())
				{
					// Below I use my own code to add the ellipsis to the text
					// to output instead of letting the system do it for me
					// with DT_PATH_ELLIPSIS and DT_END_ELLIPSIS.
					//
					// The reason for this is that I had too much trouble getting
					// it to work with vertically printed text.

					// Do we need to compact the caption as a path name?
					if ( m_bCompactAsPath )
					{
						// Get the current contents of the caption.
						TCHAR	sz[ MAX_PATH ];
						GetWindowText( sz, MAX_PATH );

						// Compact it.
						PathCompactPath( dc, sz, m_bIsVertical ? rcClient.Height() : rcClient.Width());

						// Assign the title object to the result
						// and specify the length of the result.
						title = sz;
						nNum = title.GetStringLength();
					}
					else
					{
						// Get the size of an ellipsis. I do not use the DT_END_ELLIPSIS
						// flag with DrawText() since I want to know when the text is
						// clipped so that I can show the tooltip when appropiate.
						ClsSize szell = dc.GetTextExtent( _T( "..." ), 3 );

						// Compute how many character will fit in the area excluding
						// the area the ellipsis takes up.
						dc.GetTextExtentExPoint( title, max( 0, nCX - szell.CX()), &nNum );

						// We want atleast one character to remain.
						nNum = max( nNum, 1 );

						// Setup the title string to contain the actual string
						// we render.
						title.SetStringLength( nNum );
						title += _T( "..." );

						// Add the length of the ellipsis.
						nNum += 3;
					}

					// We are clipped.
					m_bIsClipped = TRUE;
				}
				else
					// We are not clipped.
					m_bIsClipped = FALSE;

				// Render the title.
				if ( ! m_bIsVertical ) dc.TextOut( rcClient.Left(), rcClient.Top() + (( rcClient.Height() / 2 ) - ( size.CY() / 2 )), title, nNum );
				else		       dc.TextOut( rcClient.Left() + (( rcClient.Width() / 2 ) - ( size.CY() / 2 )), rcClient.Bottom(), title, nNum );
			}
		}
		else
			m_bIsClipped = TRUE;

		// Restore the DC.
		dc.RestoreDC( sDC );
	}
}

// OnPaint() overide.
LRESULT ClsInfoBar::OnPaint( ClsDC *pDC )
{
	// Input DC?
	if ( pDC ) PaintControl( pDC );
	else
	{
		ClsPaintDC dc( this );
		PaintControl( &dc );
	}
	return 0;
}

// For the layout engine.
BOOL ClsInfoBar::OnGetMinSize( ClsSize& szMinSize )
{
	// Do we have an icon?
	if ( m_hIcon ) szMinSize.CX() = szMinSize.CY() = 18;
	else
	{
		// Get caption height.
		int nCap = ::GetSystemMetrics( SM_CYCAPTION );
		if ( m_bIsVertical ) szMinSize.CX() = nCap;
		else		     szMinSize.CY() = nCap;
	}

	// Measure text.
	ClsString str( GetSafeHWND());

	// Any text?
	if ( str.GetStringLength())
	{
		// Get device context and setup the used
		// font.
		ClsGetDC dc( this );
		ClsSelector sel( &dc, m_bIsVertical ? m_fVertical : m_fNormal );

		// Size the text.
		ClsSize sz = dc.GetTextExtent( str );

		// Are we vertical?
		if ( m_bIsVertical )
		{
			// Add spacing.
			szMinSize.CY() += 4;

			// Adjust the minimum width if the text height is larger
			// than the icon width.
			if ( sz.CY() > szMinSize.CX()) szMinSize.CX() = sz.CY();

			// Add text width to the control height.
			szMinSize.CY() += sz.CX();
		}
		else
		{
			// Add spacing.
			szMinSize.CX() += 4;

			// Adjust the minimum height if the text height is larger
			// than the icon height.
			if ( sz.CY() > szMinSize.CY()) szMinSize.CY() = sz.CY();

			// Add text width to the control width.
			szMinSize.CX() += sz.CX();
		}
	}
	return TRUE;
}

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)
Netherlands Netherlands
I have been programming for a hobby since 1985. I have started programming on the C= 64. After that I migrated to the C= Amiga which I traded in for a PC back in 1997 I believe. Back in 2000 I decided to lose a hobby and start developing software for a living.

Currently I am working mainly in developing software for building security and access control systems.

Comments and Discussions