Click here to Skip to main content
15,896,912 members
Articles / Programming Languages / C++

Clock Screen Saver

Rate me:
Please Sign up or sign in to vote.
4.73/5 (42 votes)
27 Jun 2004CPOL4 min read 155.1K   4.5K   48  
A mouse trailing clock screen saver written in MFC
This project is a screen saver application that I originally started as a way to pick up C++/MFC. In the years since, I’ve added some features to it like Outlook Calendar and MAPI support for signaling when new mail arrives while the screen saver is active.
// CColourPickerXP & CColourPopupXP version 1.4
//
// Copyright � 2002-2003 Zorglab
//
//   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//   !! You are not allowed to use these classes in a commercial project !!
//   !!              without the permission of the author !              !!
//   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// Feel free to remove or otherwise mangle any part.
// Please report any bug, comment, suggestion, etc. to the following address :
//   mailto:zorglab@wanadoo.be
//
// These classes are based on work by Chris Maunder, Alexander Bischofberger,
// James White and Descartes Systems Sciences, Inc.
//   http://www.codeproject.com/miscctrl/colour_picker.asp
//   http://www.codeproject.com/miscctrl/colorbutton.asp
//   http://www.codeproject.com/wtl/wtlcolorbutton.asp
//
// Thanks to Keith Rule for his CMemDC class (see MemDC.h).
// Thanks to P�l Kristian T�nder for his CXPTheme class, which is based on
// the CVisualStyleXP class of David Yuheng Zhao (see XPTheme.cpp).
//
// Other people who have contributed to the improvement of the ColourPickerXP,
// by sending a bug report, by solving a bug, by submitting a suggestion, etc.
// are mentioned in the history-section (see below).
//
// Many thanks to them all.
//
//                             === HISTORY ===
//
//	version 1.4		- fixed : "A required resource was"-dialog due to not
//					  restoring the DC after drawing pop-up (thanks to
//					  Kris Wojtas, KRI Software)
//					- using old style selection rectangle in pop-up when
//					  flat menus are disabled
//					- pop-up will now raise when user hit F4-key or down-arrow
//					- modified : moving around in the pop-up with arrow keys
//					  when no colour is selected
//
//	version 1.3		- parent window stays active when popup is up on screen
//					  (thanks to Damir Valiulin)
//					- when using track-selection, the initial colour is shown
//					  for an invalid selection instead of black
//					- added bTranslateDefault parameter in GetColor
//
//	version 1.2		- fixed : in release configuration, with neither
//					  'Automatic' nor 'Custom' labels, the pop-up won't work
//					- diasbled combo-box is drawn correctly
//					- combo-box height depends on text size
//					- font support : use SetFont() and GetFont(), for combo-
//					  box style call SetStyle() after changing font
//
//	version 1.1		- fixed some compile errors in VC6
//					- no need anymore to change the defines in stdafx.h
//					  except for multi-monitor support
//
//	version 1.0		first release
//
//                  === ORIGINAL COPYRIGHT STATEMENTS ===
//
// ------------------- Descartes Systems Sciences, Inc. --------------------
//
// Copyright (c) 2000-2002 - Descartes Systems Sciences, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are 
// met:
// 
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer. 
// 2. Neither the name of Descartes Systems Sciences, Inc nor the names of 
//    its contributors may be used to endorse or promote products derived 
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---------------- Chris Maunder & Alexander Bischofberger ----------------
//
// Written by Chris Maunder (chrismaunder@codeguru.com)
// Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de)
// Copyright (c) 1998.
//
// Updated 30 May 1998 to allow any number of colours, and to
//                     make the appearance closer to Office 97. 
//                     Also added "Default" text area.         (CJM)
//
//         13 June 1998 Fixed change of focus bug (CJM)
//         30 June 1998 Fixed bug caused by focus bug fix (D'oh!!)
//                      Solution suggested by Paul Wilkerson.
//
// ColourPopup is a helper class for the colour picker control
// CColourPicker. Check out the header file or the accompanying 
// HTML doc file for details.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified 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.
//
// Expect bugs.
// 
// Please use and enjoy. Please let me know of any bugs/mods/improvements 
// that you have found/implemented and I will fix/incorporate them into this
// file. 
//
// -------------------------------------------------------------------------
//
//                   === END OF COPYRIGHT STATEMENTS ===
//

#include "stdafx.h"
#include "ColourPickerXP.h"

#include "MemDC.h"

#include "monitor.h"
#include "monitors.h"

//***********************************************************************
//**                         MFC Debug Symbols                         **
//***********************************************************************
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//***********************************************************************
//**               Defines and init for CColourPickerXP                **
//***********************************************************************

#define COMBOBOX_DISABLED_COLOUR_OUT RGB(201,199,186)
#define COMBOBOX_DISABLED_COLOUR_IN  RGB(245,244,234)

//***********************************************************************
//**               Defines and init for CColourPopupXP                 **
//***********************************************************************

#define DEFAULT_BOX_VALUE -3
#define CUSTOM_BOX_VALUE  -2
#define INVALID_COLOUR    -1

#define MAX_COLOURS      100

#ifndef SPI_GETFLATMENU
#define SPI_GETFLATMENU                     0x1022
#endif

#ifndef SPI_GETDROPSHADOW
#define SPI_GETDROPSHADOW                   0x1024
#endif

#ifndef CS_DROPSHADOW
#define CS_DROPSHADOW       0x00020000
#endif

#ifndef ODS_HOTLIGHT
#define ODS_HOTLIGHT        0x0040
#endif

#ifndef COLOR_MENUHILIGHT
#define COLOR_MENUHILIGHT       29
#endif


TCHAR CColourPopupXP::m_strInitNames[][256] = 
{
    { _T("Black")             },
    { _T("Brown")             },
    { _T("Dark Olive Green")  },
    { _T("Dark Green")        },
    { _T("Dark Teal")         },
    { _T("Dark blue")         },
    { _T("Indigo")            },
    { _T("Dark grey")         },

    { _T("Dark red")          },
    { _T("Orange")            },
    { _T("Dark yellow")       },
    { _T("Green")             },
    { _T("Teal")              },
    { _T("Blue")              },
    { _T("Blue-grey")         },
    { _T("Grey - 40")         },

    { _T("Red")               },
    { _T("Light orange")      },
    { _T("Lime")              }, 
    { _T("Sea green")         },
    { _T("Aqua")              },
    { _T("Light blue")        },
    { _T("Violet")            },
    { _T("Grey - 50")         },

    { _T("Pink")              },
    { _T("Gold")              },
    { _T("Yellow")            },    
    { _T("Bright green")      },
    { _T("Turquoise")         },
    { _T("Skyblue")           },
    { _T("Plum")              },
    { _T("Light grey")        },

    { _T("Rose")              },
    { _T("Tan")               },
    { _T("Light yellow")      },
    { _T("Pale green ")       },
    { _T("Pale turquoise")    },
    { _T("Pale blue")         },
    { _T("Lavender")          },
    { _T("White")             }
};

ColourTableEntry CColourPopupXP::m_crColours[] = 
{
    { RGB(0x00, 0x00, 0x00),    _T("Black")             },
    { RGB(0xA5, 0x2A, 0x00),    _T("Brown")             },
    { RGB(0x00, 0x40, 0x40),    _T("Dark Olive Green")  },
    { RGB(0x00, 0x55, 0x00),    _T("Dark Green")        },
    { RGB(0x00, 0x00, 0x5E),    _T("Dark Teal")         },
    { RGB(0x00, 0x00, 0x8B),    _T("Dark blue")         },
    { RGB(0x4B, 0x00, 0x82),    _T("Indigo")            },
    { RGB(0x28, 0x28, 0x28),    _T("Dark grey")         },

    { RGB(0x8B, 0x00, 0x00),    _T("Dark red")          },
    { RGB(0xFF, 0x68, 0x20),    _T("Orange")            },
    { RGB(0x8B, 0x8B, 0x00),    _T("Dark yellow")       },
    { RGB(0x00, 0x93, 0x00),    _T("Green")             },
    { RGB(0x38, 0x8E, 0x8E),    _T("Teal")              },
    { RGB(0x00, 0x00, 0xFF),    _T("Blue")              },
    { RGB(0x7B, 0x7B, 0xC0),    _T("Blue-grey")         },
    { RGB(0x66, 0x66, 0x66),    _T("Grey - 40")         },

    { RGB(0xFF, 0x00, 0x00),    _T("Red")               },
    { RGB(0xFF, 0xAD, 0x5B),    _T("Light orange")      },
    { RGB(0x32, 0xCD, 0x32),    _T("Lime")              }, 
    { RGB(0x3C, 0xB3, 0x71),    _T("Sea green")         },
    { RGB(0x7F, 0xFF, 0xD4),    _T("Aqua")              },
    { RGB(0x7D, 0x9E, 0xC0),    _T("Light blue")        },
    { RGB(0x80, 0x00, 0x80),    _T("Violet")            },
    { RGB(0x80, 0x80, 0x80),    _T("Grey - 50")         },

    { RGB(0xFF, 0xC0, 0xCB),    _T("Pink")              },
    { RGB(0xFF, 0xD7, 0x00),    _T("Gold")              },
    { RGB(0xFF, 0xFF, 0x00),    _T("Yellow")            },    
    { RGB(0x00, 0xFF, 0x00),    _T("Bright green")      },
    { RGB(0x40, 0xE0, 0xD0),    _T("Turquoise")         },
    { RGB(0xC0, 0xFF, 0xFF),    _T("Skyblue")           },
    { RGB(0x48, 0x00, 0x48),    _T("Plum")              },
    { RGB(0xC0, 0xC0, 0xC0),    _T("Light grey")        },

    { RGB(0xFF, 0xE4, 0xE1),    _T("Rose")              },
    { RGB(0xD2, 0xB4, 0x8C),    _T("Tan")               },
    { RGB(0xFF, 0xFF, 0xE0),    _T("Light yellow")      },
    { RGB(0x98, 0xFB, 0x98),    _T("Pale green ")       },
    { RGB(0xAF, 0xEE, 0xEE),    _T("Pale turquoise")    },
    { RGB(0x68, 0x83, 0x8B),    _T("Pale blue")         },
    { RGB(0xE6, 0xE6, 0xFA),    _T("Lavender")          },
    { RGB(0xFF, 0xFF, 0xFF),    _T("White")             }
};

int CColourPopupXP::m_nNumColours = sizeof(CColourPopupXP::m_crColours)/sizeof(ColourTableEntry);

CString CColourPickerXP::m_strRegSectionStatic(_T(""));

//***********************************************************************
//**                            DDX Method                             **
//***********************************************************************

void AFXAPI DDX_ColourPickerXP(CDataExchange *pDX, int nIDC, COLORREF& crColour)
{
    HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
    ASSERT (hWndCtrl != NULL);                
    
    CColourPickerXP* pColourButton = (CColourPickerXP*) CWnd::FromHandle(hWndCtrl);
    if (pDX->m_bSaveAndValidate)
    {
		crColour = pColourButton->Color;
    }
    else // initializing
    {
		pColourButton->Color = crColour;
    }
}

//***********************************************************************
//**                             Constants                             **
//***********************************************************************
const int g_ciArrowSizeX = 4 ;
const int g_ciArrowSizeY = 2 ;

//***********************************************************************
//**                            MFC Macros                            **
//***********************************************************************
IMPLEMENT_DYNCREATE(CColourPickerXP, CButton)

//***********************************************************************
// Method:	CColourPickerXP::CColourPickerXP(void)
// Notes:	Default Constructor.
//***********************************************************************
CColourPickerXP::CColourPickerXP(void):
	_Inherited(),
	m_Color(CLR_DEFAULT),
	m_DefaultColor(::GetSysColor(COLOR_APPWORKSPACE)),
	m_strDefaultText(_T("Automatic")),
	m_strCustomText(_T("More Colors...")),
	m_bPopupActive(FALSE),
	m_bTrackSelection(FALSE),
	m_bMouseOver(FALSE),
	m_strRegSection(_T("")),
	m_bComboBoxStyle(FALSE),
	m_strRGBText(_T("RGB")),
	m_bAlwaysRGB(FALSE)
{
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof (osvi);
	::GetVersionEx (&osvi);
	bool bIsXP = osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
		(osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 &&
		osvi.dwMinorVersion >= 1));

	m_bFlatMenus = FALSE;
 	if (bIsXP)
		::SystemParametersInfo (SPI_GETFLATMENU, 0, &m_bFlatMenus, FALSE);
}

//***********************************************************************
// Method:	CColourPickerXP::~CColourPickerXP(void)
// Notes:	Destructor.
//***********************************************************************
CColourPickerXP::~CColourPickerXP(void)
{
}

//***********************************************************************
// Methods:	CColourPickerXP::GetColor()
//			CColourPickerXP::GetColor(BOOL bTranslateDefault)
// Notes:	None.
//***********************************************************************
COLORREF CColourPickerXP::GetColor(void) const
{
	return m_Color;
}

COLORREF CColourPickerXP::GetColor(BOOL bTranslateDefault) const
{
	return ( bTranslateDefault && m_Color == CLR_DEFAULT ? m_DefaultColor : m_Color );
}


//***********************************************************************
// Method:	CColourPickerXP::SetColor()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetColor(COLORREF Color)
{
	m_Color = Color;

	if (::IsWindow(m_hWnd)) 
	{
        Invalidate(FALSE);
	}
}


//***********************************************************************
// Method:	CColourPickerXP::GetDefaultColor()
// Notes:	None.
//***********************************************************************
COLORREF CColourPickerXP::GetDefaultColor(void) const
{
	return m_DefaultColor;
}

//***********************************************************************
// Method:	CColourPickerXP::SetDefaultColor()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetDefaultColor(COLORREF Color)
{
	m_DefaultColor = Color;
}

//***********************************************************************
// Method:	CColourPickerXP::SetCustomText()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetCustomText(LPCTSTR tszText)
{
	m_strCustomText = tszText;
}

//***********************************************************************
// Method:	CColourPickerXP::SetDefaultText()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetDefaultText(LPCTSTR tszText)
{
	m_strDefaultText = tszText;
	if(m_bComboBoxStyle && m_Color==CLR_DEFAULT)
		Invalidate(FALSE);
}

//***********************************************************************
// Method:	CColourPickerXP::SetColoursName()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetColoursName(UINT nFirstID)
{
	if(nFirstID)
	{
		CString szTemp;
		for(int i=0; i<(sizeof(CColourPopupXP::m_crColours)/sizeof(ColourTableEntry)); i++)
		{
			if(!szTemp.LoadString(nFirstID + i))
				szTemp = CColourPopupXP::m_strInitNames[i];
			strcpy(CColourPopupXP::m_crColours[i].szName, szTemp);
		}
	}
	else
	{
		for(int i=0; i<(sizeof(CColourPopupXP::m_crColours)/sizeof(ColourTableEntry)); i++)
			strcpy(CColourPopupXP::m_crColours[i].szName, CColourPopupXP::m_strInitNames[i]);
	}
}

//***********************************************************************
// Method:	CColourPickerXP::SetRegSection()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetRegSection(LPCTSTR tszRegSection /*= _T("")*/)
{
	m_strRegSection = tszRegSection;
}

//***********************************************************************
// Method:	CColourPickerXP::SetRegSectionStatic()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetRegSectionStatic(LPCTSTR tszRegSection /*= _T("")*/)
{
	m_strRegSectionStatic = tszRegSection;
}

//***********************************************************************
// Method:	CColourPickerXP::SetTrackSelection()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetTrackSelection(BOOL bTrack)
{
	m_bTrackSelection = bTrack;
}

//***********************************************************************
// Method:	CColourPickerXP::GetTrackSelection()
// Notes:	None.
//***********************************************************************
BOOL CColourPickerXP::GetTrackSelection(void) const
{
	return m_bTrackSelection;
}

//***********************************************************************
// Method:	CColourPickerXP::SetStyle()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetStyle(BOOL bComboBoxStyle)
{
	m_bComboBoxStyle = bComboBoxStyle;
	if(bComboBoxStyle)
	{
		CRect rc;
		GetWindowRect(rc);

		CDC *pDC = this->GetDC();
		CFont *pOldFont = pDC->SelectObject(GetFont());

		TEXTMETRIC tm;
		pDC->GetTextMetrics(&tm);

		pDC->SelectObject(pOldFont);
		this->ReleaseDC(pDC);

		SetWindowPos(NULL, 0, 0, rc.Width(), tm.tmHeight + 8, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);
	}
	Invalidate(FALSE);
}

//***********************************************************************
// Method:	CColourPickerXP::GetStyle()
// Notes:	None.
//***********************************************************************
BOOL CColourPickerXP::GetStyle(void) const
{
	return m_bComboBoxStyle;
}

//***********************************************************************
// Method:	CColourPickerXP::SetRGBText()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetRGBText(LPCTSTR tszRGB /*= _T("RGB")*/)
{
	m_strRGBText = tszRGB;
	while(m_strRGBText.GetLength() < 3)
		m_strRGBText += _T(" ");
	if(m_bComboBoxStyle && m_Color!=CLR_DEFAULT)
		Invalidate(FALSE);
}

//***********************************************************************
// Method:	CColourPickerXP::SetAlwaysRGB()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::SetAlwaysRGB(BOOL bShow)
{
	m_bAlwaysRGB = bShow;
	if(m_bComboBoxStyle && m_Color!=CLR_DEFAULT)
		Invalidate(FALSE);
}

//***********************************************************************
// Method:	CColourPickerXP::GetAlwaysRGB()
// Notes:	None.
//***********************************************************************
BOOL CColourPickerXP::GetAlwaysRGB(void) const
{
	return m_bAlwaysRGB;
}

//***********************************************************************
//**                         CButton Overrides                         **
//***********************************************************************
void CColourPickerXP::PreSubclassWindow() 
{
    ModifyStyle(0, BS_OWNERDRAW);      

    _Inherited::PreSubclassWindow();
}

//***********************************************************************
//**                         Message Handlers                         **
//***********************************************************************
BEGIN_MESSAGE_MAP(CColourPickerXP, CButton)
    //{{AFX_MSG_MAP(CColourPickerXP)
    ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
    ON_WM_CREATE()
    ON_MESSAGE(CPN_SELENDOK,     OnSelEndOK)
    ON_MESSAGE(CPN_SELENDCANCEL, OnSelEndCancel)
    ON_MESSAGE(CPN_SELCHANGE,    OnSelChange)
	ON_WM_MOUSEMOVE()
	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()


//***********************************************************************
// Method:	CColourPickerXP::OnSelEndOK()
// Notes:	None.
//***********************************************************************
LONG CColourPickerXP::OnSelEndOK(UINT lParam, LONG /*wParam*/)
{
	m_bPopupActive = FALSE;

    COLORREF OldColor = m_Color;
	
	Color = (COLORREF)lParam;

    CWnd *pParent = GetParent();

    if (pParent) 
	{
        pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID());
        pParent->SendMessage(CPN_SELENDOK, lParam, (WPARAM) GetDlgCtrlID());
    }

    if (OldColor != m_Color)
        if (pParent) pParent->SendMessage(CPN_SELCHANGE, m_Color, (WPARAM) GetDlgCtrlID());

    return TRUE;
}


//***********************************************************************
// Method:	CColourPickerXP::OnSelEndCancel()
// Notes:	None.
//***********************************************************************
LONG CColourPickerXP::OnSelEndCancel(UINT lParam, LONG /*wParam*/)
{
	m_bPopupActive = FALSE;
	
	Color = (COLORREF)lParam;

    CWnd *pParent = GetParent();

    if (pParent) 
	{
        pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID());
        pParent->SendMessage(CPN_SELENDCANCEL, lParam, (WPARAM) GetDlgCtrlID());
    }

    return TRUE;
}


//***********************************************************************
// Method:	CColourPickerXP::OnSelChange()
// Notes:	None.
//***********************************************************************
LONG CColourPickerXP::OnSelChange(UINT lParam, LONG /*wParam*/)
{
    if (m_bTrackSelection) 
		Color = (COLORREF)lParam;

    CWnd *pParent = GetParent();

    if (pParent) pParent->SendMessage(CPN_SELCHANGE, lParam, (WPARAM) GetDlgCtrlID());

    return TRUE;
}

//***********************************************************************
// Method:	CColourPickerXP::OnCreate()
// Notes:	None.
//***********************************************************************
int CColourPickerXP::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CButton::OnCreate(lpCreateStruct) == -1)
        return -1;

    return 0;
}

//***********************************************************************
// Method:	CColourPickerXP::OnClicked()
// Notes:	None.
//***********************************************************************
BOOL CColourPickerXP::OnClicked()
{
	m_bPopupActive = TRUE;

    CRect rDraw;
    GetWindowRect(rDraw);

    new CColourPopupXP(CPoint(rDraw.left, rDraw.bottom),		// Point to display popup
                       m_Color,									// Selected colour
                       this,									// parent
                       m_strDefaultText,						// "Default" text area
                       m_strCustomText,							// Custom Text
					   (m_strRegSection.GetLength() ?
						m_strRegSection
						: m_strRegSectionStatic));				// Registry Section for Custom Colours

    CWnd *pParent = GetParent();

    if (pParent)
        pParent->SendMessage(CPN_DROPDOWN, (LPARAM)m_Color, (WPARAM) GetDlgCtrlID());

    return TRUE;
}

//***********************************************************************
// Method:	CColourPickerXP::OnNMThemeChanged()
// Notes:	For Windows XP theme support.
//***********************************************************************
void CColourPickerXP::OnNMThemeChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	// This feature requires Windows XP or greater.
	// The symbol _WIN32_WINNT must be >= 0x0501.
	// TODO: Add your control notification handler code here
#ifdef _THEME_H_
	m_xpButton.Open(GetSafeHwnd(), L"BUTTON");
	m_xpEdit.Open(GetSafeHwnd(), L"EDIT");
	m_xpCombo.Open(GetSafeHwnd(), L"COMBOBOX");
#endif
	Invalidate(FALSE);
	*pResult = 0;
}

//***********************************************************************
// Method:	CColourPickerXP::OnMouseMove()
// Notes:	Hover support.
//***********************************************************************
void CColourPickerXP::OnMouseMove(UINT nFlags, CPoint point)
{
	if (!m_bMouseOver)
	{
		m_bMouseOver = TRUE;
		TRACKMOUSEEVENT tme;
		tme.cbSize = sizeof(tme);
		tme.dwFlags = TME_LEAVE;
		tme.hwndTrack = m_hWnd;
		_TrackMouseEvent(&tme);
		if(m_bComboBoxStyle)
			DrawHotArrow(TRUE);
		else
			Invalidate(FALSE);
	}

	CButton::OnMouseMove(nFlags, point);
}

//***********************************************************************
// Method:	CColourPickerXP::OnMouseLeave()
// Notes:	Hover support.
//***********************************************************************
LRESULT CColourPickerXP::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
	if (m_bMouseOver)
	{
		m_bMouseOver = FALSE;
		if(m_bComboBoxStyle)
			DrawHotArrow(FALSE);
		else
			Invalidate(FALSE);
	}
	return 0;
}





//***********************************************************************
// Method:	CColourPickerXP::DrawHotArrow()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::DrawHotArrow(BOOL bHot)
{
#ifdef _THEME_H_
    if (m_xpCombo.IsAppThemed())
    {
		CClientDC dc(this);

		CRect rcArrow;
		GetClientRect(rcArrow);
		m_xpEdit.GetBackgroundContentRect(dc.GetSafeHdc(), EP_EDITTEXT, ETS_NORMAL, &rcArrow, &rcArrow);
		rcArrow.left = rcArrow.right-(rcArrow.Height()-2);

		m_xpCombo.DrawBackground(dc.GetSafeHdc(), CP_DROPDOWNBUTTON, (bHot ? CBXS_HOT : CBXS_NORMAL), &rcArrow, NULL);
    }
#endif
}

//***********************************************************************
// Method:	CColourPickerXP::DrawItem()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	ASSERT(lpDrawItemStruct);

	CDC*    pDC      = CDC::FromHandle(lpDrawItemStruct->hDC);
	CMemDC  dcMem(pDC);
	UINT    state    = lpDrawItemStruct->itemState;
    CRect   rDraw    = lpDrawItemStruct->rcItem;
	CRect	rArrow;
	bool	bFocus   = (state & ODS_FOCUS) && ((state & ODS_SELECTED)==0);

	SendMessage(WM_ERASEBKGND, (WPARAM)dcMem.GetSafeHdc());

	if (m_bPopupActive && !m_bComboBoxStyle)
		state |= ODS_SELECTED/*|ODS_FOCUS*/;

	if (state & ODS_FOCUS)
		state |= ODS_DEFAULT;

#ifdef _THEME_H_
	if(!m_xpButton)
		m_xpButton.Open(GetSafeHwnd(), L"BUTTON");
	if(!m_xpEdit)
		m_xpEdit.Open(GetSafeHwnd(), L"EDIT");
	if(!m_xpCombo)
		m_xpCombo.Open(GetSafeHwnd(), L"COMBOBOX");
#endif

	//******************************************************
	//**                  Draw Outer Edge
	//******************************************************
#ifdef _THEME_H_
	if (m_xpButton.IsAppThemed())
	{
		if ((state & ODS_DISABLED) != 0 && m_bComboBoxStyle)
		{
			dcMem.Draw3dRect(rDraw, COMBOBOX_DISABLED_COLOUR_OUT, COMBOBOX_DISABLED_COLOUR_OUT);
			rDraw.DeflateRect(1, 1);
		}
		else
		{
			int nFrameState = 0;
			if ((state & ODS_SELECTED) != 0 || m_bPopupActive)
				nFrameState |= (m_bComboBoxStyle ? ETS_SELECTED : PBS_PRESSED);
			if ((state & ODS_DISABLED) != 0)
				nFrameState |= (m_bComboBoxStyle ? ETS_DISABLED : PBS_DISABLED);
			if ((state & ODS_HOTLIGHT) != 0 || m_bMouseOver)
				nFrameState |= (m_bComboBoxStyle ? ETS_HOT : PBS_HOT);
			else if ((state & ODS_DEFAULT) != 0 && !m_bComboBoxStyle)
				nFrameState |= PBS_DEFAULTED;

			if(m_bComboBoxStyle)
			{
				m_xpEdit.DrawBackground(dcMem.GetSafeHdc(), EP_EDITTEXT, nFrameState, &rDraw, NULL);
				m_xpEdit.GetBackgroundContentRect(dcMem.GetSafeHdc(), EP_EDITTEXT, nFrameState, &rDraw, &rDraw);
			}
			else
			{
				m_xpButton.DrawBackground(dcMem.GetSafeHdc(), BP_PUSHBUTTON, nFrameState, &rDraw, NULL);
				m_xpButton.GetBackgroundContentRect(dcMem.GetSafeHdc(), BP_PUSHBUTTON, nFrameState, &rDraw, &rDraw);
				rDraw.InflateRect(0, 0, 1, 0);
			}
		}
	}
	else
#endif
	{
		if(m_bComboBoxStyle)
		{
			if ((state & ODS_DISABLED) == 0)
				dcMem.FillSolidRect(&rDraw, ::GetSysColor(COLOR_WINDOW));
			dcMem.DrawEdge(&rDraw, EDGE_SUNKEN, BF_RECT);

			rDraw.DeflateRect(::GetSystemMetrics(SM_CXEDGE),
							::GetSystemMetrics(SM_CYEDGE));
		}
		else
		{
			UINT uFrameState = DFCS_BUTTONPUSH|DFCS_ADJUSTRECT;

			if (state & ODS_SELECTED)
				uFrameState |= DFCS_PUSHED;

			if (state & ODS_DISABLED)
				uFrameState |= DFCS_INACTIVE;
			
			dcMem.DrawFrameControl(&rDraw,
								DFC_BUTTON,
								uFrameState);

			if (state & ODS_SELECTED)
				rDraw.OffsetRect(1,1);
		}
	}

	//******************************************************
	//**                     Draw Arrow (ComboBox style)
	//******************************************************
	if(m_bComboBoxStyle)
	{
#ifdef _THEME_H_
		if (m_xpCombo.IsAppThemed())
		{
			int nFrameState = 0;
			if ((state & ODS_SELECTED) != 0 /*|| m_bPopupActive*/)
				nFrameState |= CBXS_PRESSED;
			if ((state & ODS_DISABLED) != 0)
				nFrameState |= CBXS_DISABLED;
			if ((state & ODS_HOTLIGHT) != 0 || m_bMouseOver)
				nFrameState |= CBXS_HOT;

			rArrow.SetRect(rDraw.right-(rDraw.Height()-2), rDraw.top, rDraw.right, rDraw.bottom);

			m_xpCombo.DrawBackground(dcMem.GetSafeHdc(), CP_DROPDOWNBUTTON, nFrameState, &rArrow, NULL);

			rDraw.DeflateRect(0, 0, rArrow.Width(), 0);
		}
		else
#endif
		{
			rArrow.SetRect(rDraw.right-(rDraw.Height()), rDraw.top, rDraw.right, rDraw.bottom);

			dcMem.DrawFrameControl(&rArrow, DFC_SCROLL, DFCS_SCROLLDOWN  | 
								((state & ODS_SELECTED) ? DFCS_FLAT | DFCS_PUSHED : 0) |
								((state & ODS_DISABLED) ? DFCS_INACTIVE : 0));

			rDraw.DeflateRect(1, 1, rArrow.Width(), 1);
		}
	}

	//******************************************************
	//**                  Draw Inner Edge (Disabled Combo-box)
	//******************************************************
#ifdef _THEME_H_
	if (m_xpButton.IsAppThemed() && m_bComboBoxStyle)
	{
		if ((state & ODS_DISABLED) != 0)
		{
			dcMem.Draw3dRect(rDraw, COMBOBOX_DISABLED_COLOUR_IN, COMBOBOX_DISABLED_COLOUR_IN);
		}
		rDraw.DeflateRect(2, 2, 1, 2);
	}
#endif

	//******************************************************
	//**                     Draw Focus
	//******************************************************
	if (bFocus) 
    {
		CRect rFocus(rDraw.left,
					 rDraw.top,
					 rDraw.right - 1,
					 rDraw.bottom);

		if(m_bComboBoxStyle)
		{
			COLORREF clFocus = ::GetSysColor(COLOR_HIGHLIGHT);
			COLORREF clInvert = RGB(255-GetRValue(clFocus), 255-GetGValue(clFocus), 255-GetBValue(clFocus));

			rFocus.DeflateRect(1, 1);
			dcMem.FillSolidRect(rFocus, clFocus);
			rFocus.InflateRect(1, 1);

			dcMem.Draw3dRect(rFocus, clInvert, clInvert);
		}
  
        dcMem.DrawFocusRect(&rFocus);
    }

	rDraw.DeflateRect(::GetSystemMetrics(SM_CXEDGE),
					  ::GetSystemMetrics(SM_CYEDGE));
	rDraw.DeflateRect(0, 0, 1, 0);

	if(!m_bComboBoxStyle)
	{
		//******************************************************
		//**                     Draw Arrow (Button style)
		//******************************************************
		rArrow.left		= rDraw.right - g_ciArrowSizeX - ::GetSystemMetrics(SM_CXEDGE) /2;
		rArrow.right	= rArrow.left + g_ciArrowSizeX;
		rArrow.top		= (rDraw.bottom + rDraw.top)/2 - g_ciArrowSizeY / 2;
		rArrow.bottom	= (rDraw.bottom + rDraw.top)/2 + g_ciArrowSizeY / 2;

		DrawArrow(&dcMem,
				&rArrow,
				0,
				(state & ODS_DISABLED) 
				? ::GetSysColor(COLOR_GRAYTEXT) 
				: RGB(0,0,0));

		rDraw.right = rArrow.left - ::GetSystemMetrics(SM_CXEDGE)/2 - 2;

		//******************************************************
		//**                   Draw Separator (Button Style)
		//******************************************************
		dcMem.DrawEdge(&rDraw,
					EDGE_ETCHED,
					BF_RIGHT | (m_bFlatMenus ? BF_FLAT : 0));

		rDraw.right -= (::GetSystemMetrics(SM_CXEDGE) * 2) + 1 ;
	}
				  
	//******************************************************
	//**                     Draw Color
	//******************************************************
	if ((state & ODS_DISABLED) == 0)
	{
		CRect rcColor(rDraw);
		if(m_bComboBoxStyle)
			rcColor.right = rDraw.left+rDraw.Height();

		dcMem.FillSolidRect(&rcColor,
						   (m_Color == CLR_DEFAULT)
						   ? m_DefaultColor
						   : m_Color);

		::FrameRect(dcMem.m_hDC,
					&rcColor,
					::GetSysColorBrush(bFocus && m_bComboBoxStyle ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));

		if(m_bComboBoxStyle)
		{
			rDraw.DeflateRect(rcColor.Width()+2, -1, 0, -1);

			CString szTemp;
			if(m_Color == CLR_DEFAULT)
				szTemp = m_strDefaultText;
			else
			{
				szTemp.Format(_T("%s:%d %s:%d %s:%d"), m_strRGBText.Left(1), GetRValue(m_Color), m_strRGBText.Mid(1, 1), GetGValue(m_Color), m_strRGBText.Mid(2, 1), GetBValue(m_Color));
				for (int i = 0; i < CColourPopupXP::m_nNumColours; i++)
				{
					if (CColourPopupXP::GetColour(i) == m_Color)
					{
						if(m_bAlwaysRGB)
						{
							CString szRGB = szTemp;
							szTemp.Format(_T("%s (%s)"), CColourPopupXP::GetColourName(i), szRGB);
						}
						else
							szTemp = CColourPopupXP::GetColourName(i);
						break;
					}
				}
			}

			CFont *pOldFont = dcMem.SelectObject(GetFont());

			dcMem.SetBkMode(TRANSPARENT);
			
			if (bFocus) 
				dcMem.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));

			dcMem.DrawText(szTemp, rDraw, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);

			dcMem.SelectObject(pOldFont);
		}
	}
}


//***********************************************************************
//**                          Static Methods                          **
//***********************************************************************

//***********************************************************************
// Method:	CColourPickerXP::DrawArrow()
// Notes:	None.
//***********************************************************************
void CColourPickerXP::DrawArrow(CDC* pDC, 
							 RECT* pRect, 
							 int iDirection,
							 COLORREF clrArrow /*= RGB(0,0,0)*/)
{
	POINT ptsArrow[3];

	switch (iDirection)
	{
		case 0 : // Down
		{
			ptsArrow[0].x = pRect->left;
			ptsArrow[0].y = pRect->top;
			ptsArrow[1].x = pRect->right;
			ptsArrow[1].y = pRect->top;
			ptsArrow[2].x = (pRect->left + pRect->right)/2;
			ptsArrow[2].y = pRect->bottom;
			break;
		}

		case 1 : // Up
		{
			ptsArrow[0].x = pRect->left;
			ptsArrow[0].y = pRect->bottom;
			ptsArrow[1].x = pRect->right;
			ptsArrow[1].y = pRect->bottom;
			ptsArrow[2].x = (pRect->left + pRect->right)/2;
			ptsArrow[2].y = pRect->top;
			break;
		}

		case 2 : // Left
		{
			ptsArrow[0].x = pRect->right;
			ptsArrow[0].y = pRect->top;
			ptsArrow[1].x = pRect->right;
			ptsArrow[1].y = pRect->bottom;
			ptsArrow[2].x = pRect->left;
			ptsArrow[2].y = (pRect->top + pRect->bottom)/2;
			break;
		}

		case 3 : // Right
		{
			ptsArrow[0].x = pRect->left;
			ptsArrow[0].y = pRect->top;
			ptsArrow[1].x = pRect->left;
			ptsArrow[1].y = pRect->bottom;
			ptsArrow[2].x = pRect->right;
			ptsArrow[2].y = (pRect->top + pRect->bottom)/2;
			break;
		}
	}
	
	CBrush brsArrow(clrArrow);
	CPen penArrow(PS_SOLID, 1 , clrArrow);

	CBrush* pOldBrush = pDC->SelectObject(&brsArrow);
	CPen*   pOldPen   = pDC->SelectObject(&penArrow);
	
	pDC->SetPolyFillMode(WINDING);
	pDC->Polygon(ptsArrow, 3);

	pDC->SelectObject(pOldBrush);
	pDC->SelectObject(pOldPen);
}

BOOL CColourPickerXP::PreTranslateMessage(MSG* pMsg)
{
	if(pMsg->message == WM_KEYDOWN)
	{
		switch(pMsg->wParam)
		{
		case VK_DOWN:
		case VK_F4:
			OnClicked();		// Activate pop-up when F4-key or down-arrow is hit
			return TRUE;
		case VK_UP:
			return TRUE;		// Disable up-arrow
		}
	}

	return _Inherited::PreTranslateMessage(pMsg);
}

/////////////////////////////////////////////////////////////////////////////
// ColourPopupXP : implementation                                          //
/////////////////////////////////////////////////////////////////////////////

//
// Sizing definitions
//

static const CSize s_sizeTextHiBorder (3, 3);
static const CSize s_sizeTextMargin (2, 2);
static const CSize s_sizeBoxHiBorder (2, 2);
static const CSize s_sizeBoxMargin (0, 0);
static const CSize s_sizeBoxCore (14, 14);

/////////////////////////////////////////////////////////////////////////////
// CColourPopupXP

CColourPopupXP::CColourPopupXP()
{
    Initialise();
}

CColourPopupXP::CColourPopupXP(CPoint p, COLORREF crColour, CWnd* pParentWnd,
                           LPCTSTR szDefaultText /* = NULL */,
                           LPCTSTR szCustomText  /* = NULL */,
						   LPCTSTR szRegSection  /* = NULL */)
{
    Initialise();

    m_crColour       = m_crInitialColour = crColour;
    m_pParent        = pParentWnd;
    m_strDefaultText = (szDefaultText)? szDefaultText : _T("");
    m_strCustomText  = (szCustomText)?  szCustomText  : _T("");

	m_strRegSection  = (szRegSection)?  szRegSection  : _T("");

    CColourPopupXP::Create(p, crColour, pParentWnd, szDefaultText, szCustomText);
}

void CColourPopupXP::Initialise()
{
	ASSERT(m_nNumColours <= MAX_COLOURS);
	if (m_nNumColours > MAX_COLOURS)
		m_nNumColours = MAX_COLOURS;

	m_nNumColumns       = 0;
    m_nNumRows          = 0;
    m_nBoxSize          = 18;
    m_nMargin           = ::GetSystemMetrics(SM_CXEDGE);
    m_nCurrentSel       = INVALID_COLOUR;
    m_nChosenColourSel  = INVALID_COLOUR;
    m_pParent           = NULL;
    m_crColour          = m_crInitialColour = RGB(0,0,0);

    m_bChildWindowVisible = FALSE;

	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof (osvi);
	::GetVersionEx (&osvi);
	m_bIsXP = osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
		(osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 &&
		osvi.dwMinorVersion >= 1));

	m_bFlatmenus = FALSE;
 	if (m_bIsXP)
		::SystemParametersInfo (SPI_GETFLATMENU, 0, &m_bFlatmenus, FALSE);

	//
	// Get all the colors I need
	//

	int nAlpha = 48;
	m_clrBackground = ::GetSysColor (COLOR_MENU);
	m_clrHiLightBorder = ::GetSysColor (COLOR_HIGHLIGHT);
	m_clrHiLight = m_clrHiLightBorder;
	if (m_bIsXP)
		m_clrHiLight = ::GetSysColor (COLOR_MENUHILIGHT);
	m_clrHiLightText = ::GetSysColor (COLOR_HIGHLIGHTTEXT);
	m_clrText = ::GetSysColor (COLOR_MENUTEXT);
	m_clrLoLight = RGB (
		(GetRValue (m_clrBackground) * (255 - nAlpha) + 
			GetRValue (m_clrHiLightBorder) * nAlpha) >> 8,
		(GetGValue (m_clrBackground) * (255 - nAlpha) + 
			GetGValue (m_clrHiLightBorder) * nAlpha) >> 8,
		(GetBValue (m_clrBackground) * (255 - nAlpha) + 
			GetBValue (m_clrHiLightBorder) * nAlpha) >> 8);

    // Idiot check: Make sure the colour square is at least 5 x 5;
    if (m_nBoxSize - 2*m_nMargin - 2 < 5) m_nBoxSize = 5 + 2*m_nMargin + 2;

    // Create the font
    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(NONCLIENTMETRICS);
    VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
    m_Font.CreateFontIndirect(&(ncm.lfMessageFont));

    // Create the palette
    struct {
        LOGPALETTE    LogPalette;
        PALETTEENTRY  PalEntry[MAX_COLOURS];
    } pal;

    LOGPALETTE* pLogPalette = (LOGPALETTE*) &pal;
    pLogPalette->palVersion    = 0x300;
    pLogPalette->palNumEntries = (WORD) m_nNumColours; 

    for (int i = 0; i < m_nNumColours; i++)
    {
        pLogPalette->palPalEntry[i].peRed   = GetRValue(m_crColours[i].crColour);
        pLogPalette->palPalEntry[i].peGreen = GetGValue(m_crColours[i].crColour);
        pLogPalette->palPalEntry[i].peBlue  = GetBValue(m_crColours[i].crColour);
        pLogPalette->palPalEntry[i].peFlags = 0;
    }

    m_Palette.CreatePalette(pLogPalette);
}

CColourPopupXP::~CColourPopupXP()
{
    m_Font.DeleteObject();
    m_Palette.DeleteObject();
}

BOOL CColourPopupXP::Create(CPoint p, COLORREF crColour, CWnd* pParentWnd,
                          LPCTSTR szDefaultText /* = NULL */,
                          LPCTSTR szCustomText  /* = NULL */)
{
    ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd()));
  
    m_pParent  = pParentWnd;
    m_crColour = m_crInitialColour = crColour;

    // Get the class name and create the window
	UINT nClassStyle = CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW;
	if(m_bIsXP)
	{
		BOOL bDropShadow;
		::SystemParametersInfo(SPI_GETDROPSHADOW, 0, &bDropShadow, FALSE);
		if (bDropShadow)
			nClassStyle |= CS_DROPSHADOW;
	}

    CString szClassName = AfxRegisterWndClass(nClassStyle,
                                              0,
                                              (HBRUSH) (COLOR_MENU+1), 
                                              0);

	// Finding the window's topmost parent
	CWnd* pTopParent = m_pParent->GetParentOwner();
    
	if ( pTopParent != NULL )
		pTopParent->SetRedraw( FALSE );

	BOOL bCreate = CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP, 
                        p.x, p.y, 100, 100, // size updated soon
                        pParentWnd->GetSafeHwnd(), 0, NULL);
    
	if ( pTopParent != NULL )
	{
		pTopParent->SendMessage( WM_NCACTIVATE, TRUE );
		pTopParent->SetRedraw( TRUE );
	}
    
	if ( !bCreate )
		return FALSE;

    // Store the Custom text
    if (szCustomText != NULL) 
        m_strCustomText = szCustomText;

    // Store the Default Area text
    if (szDefaultText != NULL) 
        m_strDefaultText = szDefaultText;
        
    // Set the window size
    SetWindowSize();

    // Create the tooltips
    CreateToolTips();

    // Find which cell (if any) corresponds to the initial colour
    FindCellFromColour(crColour);

    // Capture all mouse events for the life of this window
    SetCapture();

    return TRUE;
}

BEGIN_MESSAGE_MAP(CColourPopupXP, CWnd)
    //{{AFX_MSG_MAP(CColourPopupXP)
    ON_WM_NCDESTROY()
    ON_WM_LBUTTONUP()
    ON_WM_PAINT()
    ON_WM_MOUSEMOVE()
    ON_WM_KEYDOWN()
    ON_WM_QUERYNEWPALETTE()
    ON_WM_PALETTECHANGED()
	ON_WM_KILLFOCUS()
	ON_WM_ACTIVATEAPP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CColourPopupXP message handlers

// For tooltips
BOOL CColourPopupXP::PreTranslateMessage(MSG* pMsg) 
{
    m_ToolTip.RelayEvent(pMsg);

    // Fix (Adrian Roman): Sometimes if the picker loses focus it is never destroyed
    if (GetCapture()->GetSafeHwnd() != m_hWnd)
        SetCapture(); 

    return CWnd::PreTranslateMessage(pMsg);
}

// If an arrow key is pressed, then move the selection
void CColourPopupXP::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
    int row = GetRow(m_nCurrentSel),
        col = GetColumn(m_nCurrentSel);

    if (nChar == VK_DOWN) 
    {
        if (row == DEFAULT_BOX_VALUE) 
            row = col = 0; 
        else if (row == CUSTOM_BOX_VALUE || row == INVALID_COLOUR)
        {
            if (m_strDefaultText.GetLength())
                row = col = DEFAULT_BOX_VALUE;
            else
                row = col = 0;
        }
        else
        {
            row++;
            if (GetIndex(row,col) < 0)
            {
                if (m_strCustomText.GetLength())
                    row = col = CUSTOM_BOX_VALUE;
                else if (m_strDefaultText.GetLength())
                    row = col = DEFAULT_BOX_VALUE;
                else
                    row = col = 0;
            }
        }
        ChangeSelection(GetIndex(row, col));
    }

    if (nChar == VK_UP) 
    {
        if (row == DEFAULT_BOX_VALUE || row == INVALID_COLOUR)
        {
            if (m_strCustomText.GetLength())
                row = col = CUSTOM_BOX_VALUE;
            else
           { 
                row = GetRow(m_nNumColours-1); 
                col = GetColumn(m_nNumColours-1); 
            }
        }
        else if (row == CUSTOM_BOX_VALUE)
        { 
            row = GetRow(m_nNumColours-1); 
            col = GetColumn(m_nNumColours-1); 
        }
        else if (row > 0) row--;
        else /* row == 0 */
        {
            if (m_strDefaultText.GetLength())
                row = col = DEFAULT_BOX_VALUE;
            else if (m_strCustomText.GetLength())
                row = col = CUSTOM_BOX_VALUE;
            else
            { 
                row = GetRow(m_nNumColours-1); 
                col = GetColumn(m_nNumColours-1); 
            }
        }
        ChangeSelection(GetIndex(row, col));
    }

    if (nChar == VK_RIGHT) 
    {
        if (row == DEFAULT_BOX_VALUE) 
            row = col = 0; 
        else if (row == CUSTOM_BOX_VALUE || row == INVALID_COLOUR)
        {
            if (m_strDefaultText.GetLength())
                row = col = DEFAULT_BOX_VALUE;
            else
                row = col = 0;
        }
        else if (col < m_nNumColumns-1) 
            col++;
        else 
        { 
            col = 0; row++;
        }

        if (GetIndex(row,col) == INVALID_COLOUR)
        {
            if (m_strCustomText.GetLength())
                row = col = CUSTOM_BOX_VALUE;
            else if (m_strDefaultText.GetLength())
                row = col = DEFAULT_BOX_VALUE;
            else
                row = col = 0;
        }

        ChangeSelection(GetIndex(row, col));
    }

    if (nChar == VK_LEFT) 
    {
        if (row == DEFAULT_BOX_VALUE || row == INVALID_COLOUR)
        {
            if (m_strCustomText.GetLength())
                row = col = CUSTOM_BOX_VALUE;
            else
           { 
                row = GetRow(m_nNumColours-1); 
                col = GetColumn(m_nNumColours-1); 
            }
        }
        else if (row == CUSTOM_BOX_VALUE)
        { 
            row = GetRow(m_nNumColours-1); 
            col = GetColumn(m_nNumColours-1); 
        }
        else if (col > 0) col--;
        else /* col == 0 */
        {
            if (row > 0) { row--; col = m_nNumColumns-1; }
            else 
            {
                if (m_strDefaultText.GetLength())
                    row = col = DEFAULT_BOX_VALUE;
                else if (m_strCustomText.GetLength())
                    row = col = CUSTOM_BOX_VALUE;
                else
                { 
                    row = GetRow(m_nNumColours-1); 
                    col = GetColumn(m_nNumColours-1); 
                }
            }
        }
        ChangeSelection(GetIndex(row, col));
    }

    if (nChar == VK_ESCAPE) 
    {
        m_crColour = m_crInitialColour;
        EndSelection(CPN_SELENDCANCEL);
        return;
    }

    if (nChar == VK_RETURN || nChar == VK_SPACE)
    {
        EndSelection(CPN_SELENDOK);
        return;
    }

    CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

// auto-deletion
void CColourPopupXP::OnNcDestroy() 
{
    CWnd::OnNcDestroy();
    delete this;
}

void CColourPopupXP::OnPaint() 
{
    CPaintDC dc(this); // device context for painting

	// Draw the Default Area text
    if (m_strDefaultText.GetLength())
        DrawCell(&dc, DEFAULT_BOX_VALUE);
 
    // Draw colour cells
    for (int i = 0; i < m_nNumColours; i++)
        DrawCell(&dc, i);
    
    // Draw custom text
    if (m_strCustomText.GetLength())
        DrawCell(&dc, CUSTOM_BOX_VALUE);

    // Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
    // but for some reason isn't
    CRect rect;
    GetClientRect(rect);
	DrawBorder(&dc, rect, EDGE_RAISED, BF_RECT);
}

void CColourPopupXP::OnMouseMove(UINT nFlags, CPoint point) 
{
    int nNewSelection = INVALID_COLOUR;

    // Translate points to be relative raised window edge
    point.x -= m_nMargin;
    point.y -= m_nMargin;

    // First check we aren't in text box
    if (m_strCustomText.GetLength() && m_CustomTextRect.PtInRect(point))
        nNewSelection = CUSTOM_BOX_VALUE;
    else if (m_strDefaultText.GetLength() && m_DefaultTextRect.PtInRect(point))
        nNewSelection = DEFAULT_BOX_VALUE;
	else if (!m_BoxesRect.PtInRect(point))
		nNewSelection = INVALID_COLOUR;
    else
    {
        // Take into account text box
        if (m_strDefaultText.GetLength()) 
            point.y -= m_DefaultTextRect.Height();  

        // Get the row and column
        nNewSelection = GetIndex(point.y / m_nBoxSize, point.x / m_nBoxSize);

        // In range? If not, default and exit
        if (nNewSelection < 0 || nNewSelection >= m_nNumColours)
        {
            //CWnd::OnMouseMove(nFlags, point);
            //return;
			nNewSelection = INVALID_COLOUR;
        }
    }

    // OK - we have the row and column of the current selection (may be CUSTOM_BOX_VALUE)
    // Has the row/col selection changed? If yes, then redraw old and new cells.
    if (nNewSelection != m_nCurrentSel)
        ChangeSelection(nNewSelection);

    CWnd::OnMouseMove(nFlags, point);
}

// End selection on LButtonUp
void CColourPopupXP::OnLButtonUp(UINT nFlags, CPoint point) 
{    
    CWnd::OnLButtonUp(nFlags, point);

    DWORD pos = GetMessagePos();
    point = CPoint(LOWORD(pos), HIWORD(pos));

    if (m_WindowRect.PtInRect(point))
        EndSelection(CPN_SELENDOK);
    else
        EndSelection(CPN_SELENDCANCEL);
}

/////////////////////////////////////////////////////////////////////////////
// CColourPopupXP implementation

int CColourPopupXP::GetIndex(int row, int col) const
{ 
    if ((row == CUSTOM_BOX_VALUE || col == CUSTOM_BOX_VALUE) && m_strCustomText.GetLength())
        return CUSTOM_BOX_VALUE;
    else if ((row == DEFAULT_BOX_VALUE || col == DEFAULT_BOX_VALUE) && m_strDefaultText.GetLength())
        return DEFAULT_BOX_VALUE;
    else if (row < 0 || col < 0 || row >= m_nNumRows || col >= m_nNumColumns)
        return INVALID_COLOUR;
    else
    {
        if (row*m_nNumColumns + col >= m_nNumColours)
            return INVALID_COLOUR;
        else
            return row*m_nNumColumns + col;
    }
}

int CColourPopupXP::GetRow(int nIndex) const               
{ 
    if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength())
        return CUSTOM_BOX_VALUE;
    else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength())
        return DEFAULT_BOX_VALUE;
    else if (nIndex < 0 || nIndex >= m_nNumColours)
        return INVALID_COLOUR;
    else
        return nIndex / m_nNumColumns; 
}

int CColourPopupXP::GetColumn(int nIndex) const            
{ 
    if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength())
        return CUSTOM_BOX_VALUE;
    else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength())
        return DEFAULT_BOX_VALUE;
    else if (nIndex < 0 || nIndex >= m_nNumColours)
        return INVALID_COLOUR;
    else
        return nIndex % m_nNumColumns; 
}

void CColourPopupXP::FindCellFromColour(COLORREF crColour)
{
    if (crColour == CLR_DEFAULT && m_strDefaultText.GetLength())
    {
        m_nChosenColourSel = DEFAULT_BOX_VALUE;
        return;
    }

    for (int i = 0; i < m_nNumColours; i++)
    {
        if (GetColour(i) == crColour)
        {
            m_nChosenColourSel = i;
            return;
        }
    }

    if (m_strCustomText.GetLength())
        m_nChosenColourSel = CUSTOM_BOX_VALUE;
    else
        m_nChosenColourSel = INVALID_COLOUR;
}

// Gets the dimensions of the colour cell given by (row,col)
BOOL CColourPopupXP::GetCellRect(int nIndex, const LPRECT& rect)
{
    if (nIndex == CUSTOM_BOX_VALUE)
    {
        ::SetRect(rect, 
                  m_CustomTextRect.left,  m_CustomTextRect.top,
                  m_CustomTextRect.right, m_CustomTextRect.bottom);
        return TRUE;
    }
    else if (nIndex == DEFAULT_BOX_VALUE)
    {
        ::SetRect(rect, 
                  m_DefaultTextRect.left,  m_DefaultTextRect.top,
                  m_DefaultTextRect.right, m_DefaultTextRect.bottom);
        return TRUE;
    }

    if (nIndex < 0 || nIndex >= m_nNumColours)
        return FALSE;

    rect->left = GetColumn(nIndex) * m_nBoxSize + m_nMargin;
    rect->top  = GetRow(nIndex) * m_nBoxSize + m_nMargin;

    // Move everything down if we are displaying a default text area
    if (m_strDefaultText.GetLength()) 
        rect->top += (m_nMargin + m_DefaultTextRect.Height());

    rect->right = rect->left + m_nBoxSize;
    rect->bottom = rect->top + m_nBoxSize;

    return TRUE;
}

// Works out an appropriate size and position of this window
void CColourPopupXP::SetWindowSize()
{
    CSize TextSize = CSize(0,0);

    // If we are showing a custom or default text area, get the font and text size.
    if (m_strCustomText.GetLength() || m_strDefaultText.GetLength())
    {
        CClientDC dc(this);
        CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font);

        // Get the size of the custom text (if there IS custom text)
        if (m_strCustomText.GetLength())
            TextSize = dc.GetTextExtent(m_strCustomText);

        // Get the size of the default text (if there IS default text)
        if (m_strDefaultText.GetLength())
        {
            CSize DefaultSize = dc.GetTextExtent(m_strDefaultText);
            if (DefaultSize.cx > TextSize.cx) TextSize.cx = DefaultSize.cx;
            if (DefaultSize.cy > TextSize.cy) TextSize.cy = DefaultSize.cy;
        }

        dc.SelectObject(pOldFont);
        TextSize += CSize(2*m_nMargin,2*m_nMargin);

        // Add even more space to draw the horizontal line
        TextSize.cy += 2*m_nMargin + 2;
    }

    // Get the number of columns and rows
    //m_nNumColumns = (int) sqrt((double)m_nNumColours);    // for a square window (yuk)
    m_nNumColumns = 8;
    m_nNumRows = m_nNumColours / m_nNumColumns;
    if (m_nNumColours % m_nNumColumns) m_nNumRows++;

    // Get the current window position, and set the new size
    CRect rect;
    GetWindowRect(rect);

    m_WindowRect.SetRect(rect.left, rect.top, 
                         rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin,
                         rect.top  + m_nNumRows*m_nBoxSize + 2*m_nMargin);

    // if custom text, then expand window if necessary, and set text width as
    // window width
    if (m_strDefaultText.GetLength()) 
    {
        if (TextSize.cx > m_WindowRect.Width())
            m_WindowRect.right = m_WindowRect.left + TextSize.cx;
        TextSize.cx = m_WindowRect.Width()-2*m_nMargin;

        // Work out the text area
        m_DefaultTextRect.SetRect(m_nMargin, m_nMargin, 
                                  m_nMargin+TextSize.cx, 2*m_nMargin+TextSize.cy);
        m_WindowRect.bottom += m_DefaultTextRect.Height() + 2*m_nMargin;
    }
	else
		m_DefaultTextRect.SetRectEmpty();

    // if custom text, then expand window if necessary, and set text width as
    // window width
    if (m_strCustomText.GetLength()) 
    {
        if (TextSize.cx > m_WindowRect.Width())
            m_WindowRect.right = m_WindowRect.left + TextSize.cx;
        TextSize.cx = m_WindowRect.Width()-2*m_nMargin;

        // Work out the text area
        m_CustomTextRect.SetRect(m_nMargin, m_WindowRect.Height(), 
                                 m_nMargin+TextSize.cx, 
                                 m_WindowRect.Height()+m_nMargin+TextSize.cy);
        m_WindowRect.bottom += m_CustomTextRect.Height() + m_nMargin;
	}
	else
		m_CustomTextRect.SetRectEmpty();

	//
	// Compute the min width
	//

	int nBoxTotalWidth = m_nNumColumns * m_nBoxSize;
	int nMinWidth = nBoxTotalWidth;
	if (nMinWidth < TextSize.cx)
		nMinWidth = TextSize.cx;

	//
	// Initialize the color box rectangle
	//

	m_BoxesRect = CRect(
		CPoint ((nMinWidth - nBoxTotalWidth) / 2, m_DefaultTextRect.bottom), 
		CSize (nBoxTotalWidth, m_nNumRows * m_nBoxSize)
		);

	//
	// Get the screen size (with multi-monitor support)
	//
	CMonitor monitor = CMonitors::GetNearestMonitor( this );
	ASSERT( CMonitors::IsMonitor( monitor ) );

	CRect monitorRect;
	monitor.GetWorkAreaRect( &monitorRect );

	// Need to check it'll fit on screen: Too far right?
    if (m_WindowRect.right > monitorRect.right)
        m_WindowRect.OffsetRect( -m_WindowRect.Width(), 0 );

    // Too far left?
    if (m_WindowRect.left < monitorRect.left)
        m_WindowRect.OffsetRect( monitorRect.left - m_WindowRect.left, 0 );

    // Bottom falling out of screen?
    if (m_WindowRect.bottom > monitorRect.bottom)
    {
        CRect ParentRect;
        m_pParent->GetWindowRect(ParentRect);
        m_WindowRect.OffsetRect( 0, -(ParentRect.Height() + m_WindowRect.Height()) );
    }

    // Set the window size and position
    MoveWindow(m_WindowRect, TRUE);
}

void CColourPopupXP::CreateToolTips()
{
    // Create the tool tip
    if (!m_ToolTip.Create(this)) return;

    // Add a tool for each cell
    for (int i = 0; i < m_nNumColours; i++)
    {
        CRect rect;
        if (!GetCellRect(i, rect)) continue;
            m_ToolTip.AddTool(this, GetColourName(i), rect, 1);
    }
}

void CColourPopupXP::ChangeSelection(int nIndex)
{
    CClientDC dc(this);        // device context for drawing

    if (nIndex > m_nNumColours)
        nIndex = CUSTOM_BOX_VALUE; 

    if ((m_nCurrentSel >= 0 && m_nCurrentSel < m_nNumColours) ||
        m_nCurrentSel == CUSTOM_BOX_VALUE || m_nCurrentSel == DEFAULT_BOX_VALUE)
    {
        // Set Current selection as invalid and redraw old selection (this way
        // the old selection will be drawn unselected)
        int OldSel = m_nCurrentSel;
        m_nCurrentSel = INVALID_COLOUR;
        DrawCell(&dc, OldSel);
    }

    // Set the current selection as row/col and draw (it will be drawn selected)
    m_nCurrentSel = nIndex;
    DrawCell(&dc, m_nCurrentSel);

    // Store the current colour
    if (m_nCurrentSel == CUSTOM_BOX_VALUE)
        m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crInitialColour, 0);
    else if (m_nCurrentSel == DEFAULT_BOX_VALUE)
    {
        m_crColour = CLR_DEFAULT;
        m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) CLR_DEFAULT, 0);
    }
	else if (m_nCurrentSel == INVALID_COLOUR)
	{
		m_crColour = INVALID_COLOUR;
        m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crInitialColour, 0);
	}
    else
    {
        m_crColour = GetColour(m_nCurrentSel);
        m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crColour, 0);
    }
}

void CColourPopupXP::EndSelection(int nMessage)
{
    ReleaseCapture();

    // If custom text selected, perform a custom colour selection
    if (nMessage != CPN_SELENDCANCEL && m_nCurrentSel == CUSTOM_BOX_VALUE)
    {
        m_bChildWindowVisible = TRUE;

        CColorDialog dlg(m_crInitialColour, CC_FULLOPEN | CC_ANYCOLOR, this);

		COLORREF clCustomColors[16];

		CString szTemp;
		DWORD dwValue;
		DWORD dwType;
		DWORD dwCount = sizeof(DWORD);
		HKEY hSecKey = NULL;
		if(m_strRegSection.GetLength())
			hSecKey = AfxGetApp()->GetSectionKey(m_strRegSection);
		for(int i=0; i<16; i++) {
			if (hSecKey == NULL) {
				clCustomColors[i] = RGB(255,255,255);
				continue;
			}
			szTemp.Format(_T("CUSTOM_COLOR_%d"), i);
			if (RegQueryValueEx(hSecKey, (LPCTSTR) szTemp, NULL, &dwType,
				(LPBYTE)&dwValue, &dwCount) == ERROR_SUCCESS)
			{
				ASSERT(dwType == REG_DWORD);
				ASSERT(dwCount == sizeof(dwValue));
				clCustomColors[i] = dwValue;
				continue;
			}
			clCustomColors[i] = RGB(255,255,255);
		}

		dlg.m_cc.lpCustColors = clCustomColors;

        if (dlg.DoModal() == IDOK)
            m_crColour = dlg.GetColor();
        else
            nMessage = CPN_SELENDCANCEL;


		if(hSecKey!=NULL)
		{
			for(int i=0; i<16; i++)
			{
				szTemp.Format(_T("CUSTOM_COLOR_%d"), i);
				RegSetValueEx(hSecKey, (LPCTSTR) szTemp, NULL, REG_DWORD, (LPBYTE)&clCustomColors[i], sizeof(clCustomColors[i]));
			}
			RegCloseKey(hSecKey);
		}

        m_bChildWindowVisible = FALSE;
    } 

    if (nMessage == CPN_SELENDCANCEL)
        m_crColour = m_crInitialColour;

    m_pParent->SendMessage(nMessage, (WPARAM) m_crColour, 0);
    
    // Kill focus bug fixed by Martin Wawrusch
    if (!m_bChildWindowVisible)
        DestroyWindow();
}

void CColourPopupXP::DrawCell(CDC* pDC, int nIndex)
{
	//
	// Get the drawing rect
	//

	CRect rect;
	if (!GetCellRect(nIndex, &rect)) 
		return;

	//
	// Get the text pointer and colors
	//

	CString szText;
	COLORREF clrBox;
	CSize sizeMargin;
	CSize sizeHiBorder;
	UINT nBorder = 0;
	switch(nIndex)
	{
	case CUSTOM_BOX_VALUE:
		szText = m_strCustomText;
		sizeMargin = s_sizeTextMargin;
		sizeHiBorder = s_sizeTextHiBorder;
		nBorder = BF_TOP;
		break;

	case DEFAULT_BOX_VALUE:
		szText = m_strDefaultText;
		sizeMargin = s_sizeTextMargin;
		sizeHiBorder = s_sizeTextHiBorder;
		nBorder = BF_BOTTOM;
		break;

	default:
		szText = _T("");
		clrBox = GetColour(nIndex);
		sizeMargin = s_sizeBoxMargin;
		sizeHiBorder = s_sizeBoxHiBorder;
	}

	//
	// Based on the selectons, get our colors
	//

	COLORREF clrHiLight;
	COLORREF clrText;
	bool bSelected;
	COLORREF clr3dTopLeft, clr3dBottomRight;
	if (m_nCurrentSel == nIndex)
	{
		bSelected = true;
		clrHiLight = m_clrHiLight;
		clrText = (m_bFlatmenus ? m_clrHiLightText : m_clrText);
		clr3dTopLeft = ::GetSysColor(COLOR_3DHIGHLIGHT);
		clr3dBottomRight = ::GetSysColor(COLOR_3DSHADOW);
	}
	else if (m_nChosenColourSel == nIndex)
	{
		bSelected = true;
		clrHiLight = m_clrLoLight;
		clrText = m_clrText;
		clr3dTopLeft = ::GetSysColor(COLOR_3DSHADOW);
		clr3dBottomRight = ::GetSysColor(COLOR_3DHIGHLIGHT);
	}
	else
	{
		bSelected = false;
		clrHiLight = m_clrLoLight;
		clrText = m_clrText;
	}

	//
	// Select and realize the palette
	//

	CPalette* pOldPalette = NULL;
	if (szText == _T(""))
	{
		if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
		{
			pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
			pDC->RealizePalette();
		}
	}

	//
	// If we are currently selected
	//

	if (bSelected)
	{

		//
		// If we have a background margin, then draw that
		//

		if (sizeMargin.cx > 0 || sizeMargin.cy > 0)
		{
			pDC->FillSolidRect(&rect, m_clrBackground);
			rect.DeflateRect(sizeMargin.cx, sizeMargin.cy);
		}

		//
		// Draw the selection rectagle
		//

		if(m_bFlatmenus)
		{
			CPen pen(PS_SOLID, 1,m_clrHiLightBorder);
			CPen *pOldPen = pDC->SelectObject(&pen);

			CBrush brush(clrHiLight);
			CBrush *pOldBrush = pDC->SelectObject(&brush);

			pDC->Rectangle(&rect);

			rect.DeflateRect(sizeHiBorder.cx - 1, sizeHiBorder.cy - 1);

			// restore DC
			pDC->SelectObject(pOldPen);
			pDC->SelectObject(pOldBrush);
		}
		else
		{
			pDC->FillSolidRect(&rect, m_clrBackground);
			pDC->Draw3dRect(&rect, clr3dTopLeft, clr3dBottomRight);
			rect.DeflateRect(sizeHiBorder.cx, sizeHiBorder.cy);
		}
	}

	//
	// Otherwise, we are not selected
	//

	else
	{
		// Draw the background

		pDC->FillSolidRect(&rect, m_clrBackground);
		rect.DeflateRect(sizeMargin.cx + sizeHiBorder.cx, sizeMargin.cy + sizeHiBorder.cy);
	}

	//
	// Draw custom text
	//

	if (szText != _T(""))
	{
        CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font);
		pDC->SetTextColor(clrText);
        pDC->SetBkMode(TRANSPARENT);
        pDC->DrawText(szText, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        pDC->SelectObject(pOldFont);
    }        

	//
	// Otherwise, draw color
	//

	else
	{

		//
		// Draw color
		//
		CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
		CPen* pOldPen = pDC->SelectObject(&pen);

		CBrush brush(PALETTERGB(GetRValue(GetColour(nIndex)), 
								GetGValue(GetColour(nIndex)), 
								GetBValue(GetColour(nIndex)) ));
		CBrush* pOldBrush = pDC->SelectObject(&brush);

		// Draw the cell colour
		rect.DeflateRect(1, 1);
		pDC->Rectangle(&rect);

		// Restore DC
		pDC->SelectObject(pOldPen);
		pDC->SelectObject(pOldBrush);
	}

	//
	// Draw border
	//

	if(nBorder)
	{
		CRect r;
		GetCellRect(nIndex, &r);
		r.InflateRect(-2, 1);
		DrawBorder(pDC, r, EDGE_ETCHED, nBorder);
	}

    // cleanup
    if (pOldPalette && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
        pDC->SelectPalette(pOldPalette, FALSE);
}

void CColourPopupXP::DrawBorder(CDC* pDC, CRect rect, UINT nEdge, UINT nBorder)
{
	if(m_bFlatmenus)
	{
		CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_GRAYTEXT));
		CPen *pOldPen = pDC->SelectObject(&pen);

		rect.DeflateRect(0, 0, 1, 1);

		if(nBorder & BF_TOP)
		{
			pDC->MoveTo(rect.left, rect.top);
			pDC->LineTo(rect.right+1, rect.top);
		}

		if(nBorder & BF_BOTTOM)
		{
			pDC->MoveTo(rect.left, rect.bottom);
			pDC->LineTo(rect.right+1, rect.bottom);
		}

		if(nBorder & BF_LEFT)
		{
			pDC->MoveTo(rect.left, rect.top);
			pDC->LineTo(rect.left, rect.bottom+1);
		}

		if(nBorder & BF_RIGHT)
		{
			pDC->MoveTo(rect.right, rect.top);
			pDC->LineTo(rect.right, rect.bottom+1);
		}

		pDC->SelectObject(pOldPen);
	}
	else
		pDC->DrawEdge(rect, nEdge, nBorder);
}

BOOL CColourPopupXP::OnQueryNewPalette() 
{
    Invalidate(FALSE);    
    return CWnd::OnQueryNewPalette();
}

void CColourPopupXP::OnPaletteChanged(CWnd* pFocusWnd) 
{
    CWnd::OnPaletteChanged(pFocusWnd);

    if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
        Invalidate(FALSE);
}

void CColourPopupXP::OnKillFocus(CWnd* pNewWnd) 
{
	CWnd::OnKillFocus(pNewWnd);

    ReleaseCapture();
    //DestroyWindow(); - causes crash when Custom colour dialog appears.
}

// KillFocus problem fix suggested by Paul Wilkerson.
#if _MFC_VER >= 0x0700
void CColourPopupXP::OnActivateApp(BOOL bActive, DWORD dwTask) 
{
	CWnd::OnActivateApp(bActive, dwTask);
#else
void CColourPopupXP::OnActivateApp(BOOL bActive, HTASK hTask) 
{
	CWnd::OnActivateApp(bActive, hTask);
#endif

	// If Deactivating App, cancel this selection
	if (!bActive)
		 EndSelection(CPN_SELENDCANCEL);
}

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
Team Leader Starkey Laboratories
United States United States
The first computer program I ever wrote was in BASIC on a TRS-80 Model I and it looked something like:
10 PRINT "Don is cool"
20 GOTO 10

It only went downhill from there.

Hey look, I've got a blog

Comments and Discussions