Click here to Skip to main content
15,886,045 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 399.6K   11.5K   141  
C++ class library.
//
// colorpicker.cpp.
//
// (C) Copyright 2000 Jan van den Baard.
//     All Rights Reserved.
//

#include "colorpicker.h"
#include "colorpopup.h"
#include "../common dialogs/colordialog.h"
#include "../../gdi/paintdc.h"
#include "../../gdi/bufferdc.h"
#include "../../gdi/getdc.h"
#include "../../gdi/brush.h"
#include "../../gdi/selector.h"
#include "../../tools/drawstate.h"
#include "../../tools/theming.h"
#include "../../tools/xpcolors.h"
#include "../../strings/string.h"

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

// Constructor. Set's up defaults.
ClsColorPicker::ClsColorPicker()
{
	// Setup defaults.
	m_crColor = RGB( 0, 0, 0 );
	m_crTempColor = CLR_NONE;
	m_bFullOpen = TRUE;
	m_bRenderArrow = FALSE;
	m_bXPPopup = FALSE;
	m_bXPControl = FALSE;
	m_bIsDropped = FALSE;
	m_strDefault = _T( "Default Color" );
	m_strCustom  = _T( "Custom Color..." );
	m_crDefaultColor = CLR_NONE;
}

// Destructor. Does nothing.
ClsColorPicker::~ClsColorPicker()
{;}

// Trigger the action.
void ClsColorPicker::Trigger()
{
	// Get the control bounds.
	ClsRect rc = GetWindowRect();

	// Update control visuals.
	UpdateWindow();

	// Create the popup. The popup will automatically destroy
	// itself.
	new ClsColorPopup( ClsPoint( rc.Left(), m_bXPControl ? rc.Bottom() - 1 : rc.Bottom()), m_crColor, this, 0, m_strDefault, m_strCustom, NULL, m_bFullOpen, m_bXPPopup );
}

// Capture popup window messages.
LRESULT ClsColorPicker::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	switch ( uMsg )
	{
		case	WM_NCACTIVATE:
			{
				// Pass this on if we have a parent.
				ClsWindow *pParent = GetParent();
				if ( pParent )
				{
					pParent->SendMessage( WM_NCACTIVATE, TRUE );
					return 0;
				}
			}
			break;

		// Render control.
		case	WM_PRINTCLIENT:
			if ( lParam & PRF_ERASEBKGND ) SendMessage( WM_ERASEBKGND, wParam );
			if ( lParam & PRF_CLIENT     ) PaintControl( ClsDC::FromHandle(( HDC )wParam ));
			return 0;

		case	CPN_SELCHANGE:
			// Set the temporary color so that the PaintControl()
			// method knows it only needs to refresh the
			// color rectangle.
			m_crTempColor = ( COLORREF )wParam;
			Invalidate();
			break;

		// Selection ended successfully?
		case	CPN_SELENDOK:
		{
			// Store selected color.
			m_crColor = ( COLORREF )wParam;

			// Re-render control.
			Invalidate();

			// Send a message to our parent.
			GetParent()->SendMessage( WM_COMMAND, MAKEWPARAM( GetWindowLong( GWL_ID ), COLPN_COLORCHANGED ), ( LPARAM )m_hWnd );
		}
		break;

		// Colorpopup opened?
		case	CPN_DROPDOWN:
			m_bIsDropped = TRUE;
			Invalidate();
			UpdateWindow();
			break;

		// Colorpopup closed?
		case	CPN_CLOSEUP:
			m_bIsDropped = FALSE;
			ClsWindow *pParent = GetParent();
			if ( pParent )
			{
				pParent->Invalidate();
				pParent->UpdateWindow();
			}
			else
			{
				Invalidate();
				UpdateWindow();
			}
			break;
	}

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

// Return the tip string.
extern ColorTableEntry crDefaultColors[];
BOOL ClsColorPicker::TipString( LPNMTTDISPINFO lpDispInfo )
{
	// Default color?
	if ( m_crColor == CLR_DEFAULT )
	{
		// Make it so...
		lpDispInfo->lpszText = m_strDefault;
		return TRUE;
	}

	// Try to find it in the default color table.
	for ( int i = 0; crDefaultColors[ i ].crColor != RGB_END; i++ )
	{
		// Is this the one?
		if ( crDefaultColors[ i ].crColor == m_crColor )
		{
			// Show it's name.
			lpDispInfo->lpszText = crDefaultColors[ i ].szName;
			return TRUE;
		}
	}

	// Format the tip.
	m_strTip.Format( _T( "%s (R=%ld, G=%ld, B=%ld)" ), ( LPCTSTR )m_strCustom, GetRValue( m_crColor ), GetGValue( m_crColor ), GetBValue( m_crColor ));

	// Any available?
	if ( m_strTip.GetStringLength())
	{
		// Set it up.
		lpDispInfo->lpszText = m_strTip;
		return TRUE;
	}
	return FALSE;
}

void ClsColorPicker::PaintControl( ClsDC *pDC )
{
	// Pre-set flags.
	DWORD dwFlags = 0;
	if ( ! IsWindowEnabled())			   dwFlags |= ClsDrawTools::CDSF_DISABLED;
	if ( IsDown() && ! ThemingAPI.IsThemingEnabled())  dwFlags |= ClsDrawTools::CDSF_DOWNPRESSED;
	if ( GetUIState() & UISF_HIDEACCEL )		   dwFlags |= ClsDrawTools::CDSF_HIDEACCEL;

	// Get frame sizes.
	int cx = GetSystemMetrics( SM_CXEDGE );
	int cy = GetSystemMetrics( SM_CYEDGE );
	int nWidth = 0;
	COLORREF crFg, crBg = ::GetSysColor( COLOR_BTNFACE );

        // Get the client rectangle.
	ClsRect	rc = GetClientRect();

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

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

		// Draw the button edge.
		if ( ! m_bXPControl ) RenderFrame( &dc, rc );
		else 
		{
			// Only when were hot, down or the popup
			// is open.
			if (( IsHot() || IsDown() || m_bIsDropped ) && IsWindowEnabled())
			{
				// Determine the fill and outline colors to use.
				if ( m_bIsDropped )
				{
					crFg = XPColors.GetXPColor( ClsXPColors::XPC_IMAGE_DISABLED );
					crBg = XPColors.GetXPColor( ClsXPColors::XPC_IMAGE_BACKGROUND );
				}
				else
				{
					crFg = XPColors.GetXPColor( ClsXPColors::XPC_OUTER_SELECTION );
					crBg = XPColors.GetXPColor( IsDown() ? ClsXPColors::XPC_INNER_CHECKED_SELECTED : ClsXPColors::XPC_INNER_SELECTION );
				}
			}
			else
			{
				// Default colors...
				crFg = ( IsDefault() && IsWindowEnabled()) ? XPColors.GetXPColor( ClsXPColors::XPC_OUTER_SELECTION ) : XPColors.GetXPColor( ClsXPColors::XPC_IMAGE_DISABLED );
			}

			// Render rectangle.
			dc.OutlinedRectangle( rc, crFg, crBg );

			// Render the shadow.
			if ( m_bIsDropped && m_crTempColor == CLR_NONE )
			{
				ClsWindow *pParent = GetParent();
				if ( pParent )
				{
					double factor;
					ClsColor col;
					GetWindowRect( rc );
					pParent->ScreenToClient( rc );
					if ( rc.IsEmpty() == FALSE )
					{
						// Get the parent DC.
						ClsGetDC wdc( pParent );
						if ( wdc.IsValid())
						{
							// Copy the parent rectangle and adjust the width
							// for the shadow.
							rc.Right() += 4;

							// Render the shadow at rhe right side of the rectangle.
							for ( int x = 0; x < 5; x++ )
							{
								for ( int y = 0; y <= rc.Height() - 6; y++ )
								{
									col = wdc.GetPixel( x + ( rc.Right() - 4 ), y + rc.Top() + 4 );
									if ( y  < 4 ) factor = y * 0.02;
									else factor = 0.1;
									factor = max( 0.01, min( 0.01 + (( 4 - x ) * factor ), 1 ));
									col.DarkenColor( factor, factor, factor );				
									wdc.SetPixelV( x + ( rc.Right() - 4 ), y + rc.Top() + 4 , col );
								}
							}
						}
					}
				}
			}
		}

		// Get client rectangle.
		GetClientRect( rc );

		// Do we need to render a drop-down arrow?
		if ( m_bRenderArrow )
		{
			// Space needed by the drop-down arrow.
			nWidth = ::GetSystemMetrics( SM_CXHSCROLL );

			// Copy client rectangle and adjust it to fit the
			// dropdwon arrow.
			ClsRect rdd = rc;
			rdd.Left() = rdd.Right() - ( nWidth + 4 );
			rdd.Deflate( 0, 4 );

			// Render the separator.
			dc.DrawEdge( rdd, m_bXPControl ? BDR_SUNKENOUTER : EDGE_ETCHED, BF_LEFT );

			// Offset position.
			rdd.Offset( 0, 2 );

			// Render the drop-down arrow.
			ClsDrawTools::RenderBitmap( dc, ClsGetApp()->GetClsImages(), ClsApp::CII_DROPDOWN, rdd, dwFlags & ~ClsDrawTools::CDSF_DOWNPRESSED );
			rc.Right() -= nWidth + 3;
		}

		// Get the caption.
		ClsString str( m_hWnd );

		// Get box size.
		int nBoxSize = max( 8, ( GetSystemMetrics( SM_CXEDGE ) * 2 ) + (( rc.Width() / 10 ) * 2 ));

		// Adjust to create the color rectangle.
		if ( str.GetStringLength() == 0 ) rc.Left() = cx + 2;
		else				  rc.Left() = rc.Right() - nBoxSize;
	
		rc.Right()  -= cx + 2;
		rc.Top()     = cy + 2;
		rc.Bottom() -= cy + 2;

		// Render the frame around the
		// color box.
		if ( ! m_bXPControl ) dc.DrawEdge( rc, IsDown() ? BDR_RAISEDINNER : BDR_SUNKENOUTER, BF_RECT );
		else dc.OutlinedRectangle( rc, XPColors.GetXPColor( ClsXPColors::XPC_IMAGE_DISABLED ), XPColors.GetXPColor( ClsXPColors::XPC_IMAGE_BACKGROUND ));

		// Adjust the rectangle to fit the
		// actual color box.
		rc.Left()   += 2;
		rc.Top()    += 2;
		rc.Right()  -= 2;
		rc.Bottom() -= 2;

		// Render the color box.
		COLORREF cr = ( m_crTempColor == CLR_NONE ) ? m_crColor : m_crTempColor;
		if ( cr == CLR_DEFAULT ) cr = m_crDefaultColor;
		if ( IsWindowEnabled())
		{
			// Do we have a color to render?
			ClsBrush brush;
			if ( cr != CLR_NONE )
			{
				// Fill with the selected color.
				brush.CreateSolidBrush( cr );
			}
			else
			{
				// Fill as transparent.
				brush.CreateHatchBrush( HS_DIAGCROSS, ::GetSysColor( COLOR_BTNTEXT ));
				dc.SetBkColor( crBg );
			}
			// Fill the colorbox.
			dc.FillRect( rc, &brush );
		}
		else
		{
			dc.SetTextColor( cr );
			dc.FillRect( rc, ClsGetApp()->GetPatternBrush());
		}

		// Get client rectangle.
		GetClientRect( rc );
		if ( m_bRenderArrow ) rc.Right() -= nWidth + 2 ;

		// Adjust rectangle.
		if ( str.GetStringLength() == 0 ) 
		{
			rc.Left()    = cx + 4;
			rc.Top()     = cy + 4;
			rc.Right()  -= cx + 4;
			rc.Bottom() -= cy + 4;
		} 
		else 
		{
			rc.Right()  -= nBoxSize + 3;
			rc.Left()    = cx + 2;
			rc.Top()     = cy + 2;
			rc.Bottom() -= cy + 2;
		}

		// Do we have the keyboard focus?
		if ( HasFocus() && ! ( GetUIState() & UISF_HIDEFOCUS ) && ! m_bIsDropped )
			dc.DrawFocusRect( rc );

		// Render caption.
		if ( str.GetStringLength())
		{
			// Setup font.
			ClsFont font;
			GetFont( font );
			ClsSelector sel( &dc, font );

			// Render transparent.
			dc.SetBkMode( TRANSPARENT );

			// Setup color.
			dc.SetTextColor( ::GetSysColor( COLOR_BTNTEXT ));

			// Render the caption.
			ClsDrawTools::RenderText( dc, str, rc, dwFlags );
		}

		// Clear temprary color.
		m_crTempColor = CLR_NONE;

		// Restore device context.
		dc.RestoreDC( sDC );
	}
}

LRESULT ClsColorPicker::OnPaint( ClsDC *pDC )
{
	// Device context passed?
	if ( pDC ) PaintControl( pDC );
	else
	{
		// Create DC.
		ClsPaintDC dc( this );
		PaintControl( &dc );
	}
	return 0;
}

// For the layout engine.
BOOL ClsColorPicker::OnGetMinSize( ClsSize& szMinSize )
{
	// First we have the frame sizes and the minimum.
	// size of the color box.
	szMinSize.CX() = ( ::GetSystemMetrics( SM_CXFRAME ) * 3 ) + 20;
	szMinSize.CY() = ( ::GetSystemMetrics( SM_CYFRAME ) * 3 );

	// Any caption?
	ClsString str( GetSafeHWND());
	if ( str.GetStringLength())
	{
		// Get the dimensions of the control
		// caption.
		ClsGetDC dc( this );
		ClsFont font;
		GetFont( font );
		ClsSelector sel( &dc, font );

		// Measure the text.
		ClsRect rc;
		dc.DrawText( str, rc, DT_CALCRECT );

		// Add size.
		szMinSize.Add( rc.Size());
	}
	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