//-----------------------------------------------------------------------------
//
// @doc
//
// @module ColorButton.cpp - Color button and popup |
//
// This module contains the definition of color button and popup
//
// Copyright (c) 2000-2002 - Descartes Systems Sciences, Inc.
//
// Based on work by Chris Maunder, Alexander Bischofberger and James White.
//
// http://www.codetools.com/miscctrl/colorbutton.asp
// http://www.codetools.com/miscctrl/colour_picker.asp
//
// 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.
//
// --- ORIGINAL COPYRIGHT STATEMENT ---
//
// 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
//
// $History: ColorButton.cpp $
//
// ***************** Version 4 *****************
// User: Tim Smith Date: 1/21/02 Time: 2:53p
// Updated in $/Omni_V2/exe_cnf
// Ported code to VC7 compiler
//
// ***************** Version 3 *****************
// User: Tim Smith Date: 9/10/01 Time: 9:05a
// Updated in $/Omni_V2/exe_cnf
//
// ***************** Version 2 *****************
// User: Tim Smith Date: 8/28/01 Time: 4:25p
// Updated in $/Omni_V2/exe_cnf
// Updated copyright dates.
//
// ***************** Version 1 *****************
// User: Tim Smith Date: 8/28/01 Time: 3:19p
// Created in $/Omni_V2/exe_cnf
//
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "ColorButton.h"
//
// Debug NEW
//
#if defined (_DEBUG)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//
// Sizing constants
//
const int g_ciArrowSizeX = 4;
const int g_ciArrowSizeY = 2;
//
// Color table
//
CColorButton::ColorTableEntry CColorButton::gm_sColors [] =
{
{ 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(0x7F, 0x7F, 0x7F), _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") }
};
//
// Other definitions
//
#define DEFAULT_BOX_VALUE -3
#define CUSTOM_BOX_VALUE -2
#define INVALID_COLOR -1
#define MAX_COLORS 100
//
// 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);
//
// Ok, here is how all the sizing works. All picker elements use the
// exact same rules. They all have 3 elements, their core size, the size
// of the highlight border, an the size of the margin.
//
// For text, the core size is just the extent of the text to be drawn.
// For the color boxes, it is the s_sizeBoxCore value. (For pointless
// jollies, the box size was modified so it doesn't have to be square. We
// are talking about changing 3-4 lines of code. No biggie.)
//
// Also, just a point of note. Each area has a well defined rectagle.
// (m_rectDefaultText, m_rectCustomText, and m_rectBoxes)
// Even if there isn't any default or custom text, the rectagles are still
// well defined, but they have no height. Their UpperLeft () is at the
// proper position and their Width () is valid. In the case of the boxes,
// m_rectBoxes is the rectagle that contains all the boxes. These changes
// made drawing and hit test 100000 times easier.
//
//-----------------------------------------------------------------------------
//
// @mfunc <c CColorButton> constructor.
//
// @rdesc None.
//
//-----------------------------------------------------------------------------
CColorButton::CColorButton () : m_wndPicker (this, 1)
{
m_clrCurrent = CLR_DEFAULT;
m_clrDefault = ::GetSysColor (COLOR_APPWORKSPACE);
m_pszDefaultText = _tcsdup (_T ("Automatic"));
m_pszCustomText = _tcsdup (_T ("More Colors..."));
m_fPopupActive = FALSE;
m_fTrackSelection = FALSE;
m_fMouseOver = FALSE;
}
//-----------------------------------------------------------------------------
//
// @mfunc <c CColorButton> destructor.
//
// @rdesc None.
//
//-----------------------------------------------------------------------------
CColorButton::~CColorButton ()
{
if (m_pszDefaultText)
free (m_pszDefaultText);
if (m_pszCustomText)
free (m_pszCustomText);
}
//-----------------------------------------------------------------------------
//
// @mfunc Subclass the control
//
// @parm HWND | hWnd | Handle of the window to be subclassed
//
// @rdesc Return value
//
// @flag TRUE | Window was subclassed
// @flag FALSE | Window was not subclassed
//
//-----------------------------------------------------------------------------
BOOL CColorButton::SubclassWindow (HWND hWnd)
{
CWindowImpl <CColorButton>::SubclassWindow (hWnd);
ModifyStyle (0, BS_OWNERDRAW);
#if !defined (COLORBUTTON_NOTHEMES)
OpenThemeData (L"Button");
#endif
return TRUE;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle key press
//
// @parm WORD | wNotifyCode | Command notification code
//
// @parm WORD | wID | ID of the control
//
// @parm HWND | hWndCtl | Handle of the control
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnClicked (WORD wNotifyCode,
WORD wID, HWND hWndCtl, BOOL &bHandled)
{
//
// Mark button as active and invalidate button to force a redraw
//
m_fPopupActive = TRUE;
InvalidateRect (NULL);
//
// Get the parent window
//
HWND hWndParent = GetParent ();
//
// Send the drop down notification to the parent
//
SendNotification (CPN_DROPDOWN, m_clrCurrent, TRUE);
//
// Save the current color for future reference
//
COLORREF clrOldColor = m_clrCurrent;
//
// Display the popup
//
BOOL fOked = Picker ();
//
// Cancel the popup
//
m_fPopupActive = FALSE;
//
// If the popup was canceled without a selection
//
if (!fOked)
{
//
// If we are tracking, restore the old selection
//
if (m_fTrackSelection)
{
if (clrOldColor != m_clrCurrent)
{
m_clrCurrent = clrOldColor;
SendNotification (CPN_SELCHANGE, m_clrCurrent, TRUE);
}
}
SendNotification (CPN_CLOSEUP, m_clrCurrent, TRUE);
SendNotification (CPN_SELENDCANCEL, m_clrCurrent, TRUE);
}
else
{
if (clrOldColor != m_clrCurrent)
{
SendNotification (CPN_SELCHANGE, m_clrCurrent, TRUE);
}
SendNotification (CPN_CLOSEUP, m_clrCurrent, TRUE);
SendNotification (CPN_SELENDOK, m_clrCurrent, TRUE);
}
//
// Invalidate button to force repaint
//
InvalidateRect (NULL);
return TRUE;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle mouse move
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnMouseMove (UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL &bHandled)
{
if (!m_fMouseOver)
{
m_fMouseOver = TRUE;
TRACKMOUSEEVENT tme;
tme .cbSize = sizeof (tme);
tme .dwFlags = TME_LEAVE;
tme .hwndTrack = m_hWnd;
_TrackMouseEvent (&tme);
InvalidateRect (NULL);
}
bHandled = FALSE;
return FALSE;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle mouse leave
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnMouseLeave (UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL &bHandled)
{
if (m_fMouseOver)
{
m_fMouseOver = FALSE;
InvalidateRect (NULL);
}
bHandled = FALSE;
return FALSE;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle a draw item request
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnDrawItem (UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL &bHandled)
{
LPDRAWITEMSTRUCT lpItem = (LPDRAWITEMSTRUCT) lParam;
CDC dc (lpItem ->hDC);
//
// Get data about the request
//
UINT uState = lpItem ->itemState;
CRect rcDraw = lpItem ->rcItem;
//
// If we have a theme
//
m_fPopupActive = false;
#if !defined (COLORBUTTON_NOTHEMES)
if (m_hTheme != NULL)
{
//
// Draw the outer edge
//
UINT uFrameState = 0;
if ((uState & ODS_SELECTED) != 0 || m_fPopupActive)
uFrameState |= PBS_PRESSED;
if ((uState & ODS_DISABLED) != 0)
uFrameState |= PBS_DISABLED;
if ((uState & ODS_HOTLIGHT) != 0 || m_fMouseOver)
uFrameState |= PBS_HOT;
else if ((uState & ODS_DEFAULT) != 0)
uFrameState |= PBS_DEFAULTED;
DrawThemeBackground (dc, BP_PUSHBUTTON,
uFrameState, &rcDraw, NULL);
GetThemeBackgroundContentRect (dc, BP_PUSHBUTTON,
uFrameState, &rcDraw, &rcDraw);
}
//
// Otherwise, we are old school
//
else
#endif
{
//
// Draw the outer edge
//
UINT uFrameState = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT;
if ((uState & ODS_SELECTED) != 0 || m_fPopupActive)
uFrameState |= DFCS_PUSHED;
if ((uState & ODS_DISABLED) != 0)
uFrameState |= DFCS_INACTIVE;
dc .DrawFrameControl (&rcDraw, DFC_BUTTON, uFrameState);
//
// Adjust the position if we are selected (gives a 3d look)
//
if ((uState & ODS_SELECTED) != 0 || m_fPopupActive)
rcDraw .OffsetRect (1, 1);
}
//
// Draw focus
//
if ((uState & ODS_FOCUS) != 0 || m_fPopupActive)
{
CRect rcFocus (rcDraw.left, rcDraw.top,
rcDraw.right - 1, rcDraw.bottom);
dc .DrawFocusRect(&rcFocus);
}
rcDraw .InflateRect (
- ::GetSystemMetrics(SM_CXEDGE),
- ::GetSystemMetrics(SM_CYEDGE));
//
// Draw the arrow
//
{
CRect rcArrow;
rcArrow .left = rcDraw. right - g_ciArrowSizeX - ::GetSystemMetrics (SM_CXEDGE) / 2;
rcArrow .top = (rcDraw.bottom + rcDraw.top)/2 - g_ciArrowSizeY / 2;
rcArrow .right = rcArrow.left + g_ciArrowSizeX;
rcArrow .bottom = (rcDraw .bottom + rcDraw .top) / 2 + g_ciArrowSizeY / 2;
DrawArrow (dc, rcArrow, 0,
(uState & ODS_DISABLED) ? ::GetSysColor (COLOR_GRAYTEXT) : RGB (0,0,0));
rcDraw.right = rcArrow.left - ::GetSystemMetrics (SM_CXEDGE) / 2;
}
//
// Draw separator
//
dc .DrawEdge (&rcDraw, EDGE_ETCHED, BF_RIGHT);
rcDraw.right -= (::GetSystemMetrics (SM_CXEDGE) * 2) + 1 ;
//
// Draw color
//
if ((uState & ODS_DISABLED) == 0)
{
dc .SetBkColor ((m_clrCurrent == CLR_DEFAULT) ? m_clrDefault : m_clrCurrent);
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rcDraw, NULL, 0, NULL);
dc .FrameRect (&rcDraw, (HBRUSH)::GetStockObject (BLACK_BRUSH));
}
return 1;
}
//-----------------------------------------------------------------------------
//
// @mfunc Draw the arrow of the button
//
// @parm CDC & | dc | Destination DC
//
// @parm const RECT & | rect | Rectangle of the control
//
// @parm int | iDirection | Direction
//
// @parm COLORREF | clrArrow | Color to draw the arrow.
//
// @rdesc None
//
//-----------------------------------------------------------------------------
void CColorButton::DrawArrow (CDC &dc, const RECT &rect,
int iDirection, COLORREF clrArrow)
{
POINT ptsArrow[3];
switch (iDirection)
{
case 0 : // Down
{
ptsArrow [0] .x = rect .left;
ptsArrow [0] .y = rect .top;
ptsArrow [1] .x = rect .right;
ptsArrow [1] .y = rect .top;
ptsArrow [2] .x = (rect .left + rect .right) / 2;
ptsArrow [2] .y = rect .bottom;
break;
}
case 1 : // Up
{
ptsArrow [0] .x = rect .left;
ptsArrow [0] .y = rect .bottom;
ptsArrow [1] .x = rect .right;
ptsArrow [1] .y = rect .bottom;
ptsArrow [2] .x = (rect .left + rect .right) / 2;
ptsArrow [2] .y = rect .top;
break;
}
case 2 : // Left
{
ptsArrow [0] .x = rect .right;
ptsArrow [0] .y = rect .top;
ptsArrow [1] .x = rect .right;
ptsArrow [1] .y = rect .bottom;
ptsArrow [2] .x = rect .left;
ptsArrow [2] .y = (rect .top + rect .bottom) / 2;
break;
}
case 3 : // Right
{
ptsArrow [0] .x = rect .left;
ptsArrow [0] .y = rect .top;
ptsArrow [1] .x = rect .left;
ptsArrow [1] .y = rect .bottom;
ptsArrow [2] .x = rect .right;
ptsArrow [2] .y = (rect .top + rect .bottom) / 2;
break;
}
}
CBrush brArrow;
brArrow .CreateSolidBrush (clrArrow);
CPen penArrow;
penArrow .CreatePen (PS_SOLID, 0, clrArrow);
HBRUSH hbrOld = dc .SelectBrush (brArrow);
HPEN hpenOld = dc .SelectPen (penArrow);
dc .SetPolyFillMode (WINDING);
dc .Polygon (ptsArrow, 3);
dc .SelectBrush (hbrOld);
dc .SelectPen (hpenOld);
return;
}
//-----------------------------------------------------------------------------
//
// @mfunc Display the picker popup
//
// @rdesc Return value
//
// @parm TRUE | A new color was selected
// @parm FALSE | The user canceled the picket
//
//-----------------------------------------------------------------------------
BOOL CColorButton::Picker ()
{
BOOL fOked = FALSE;
//
// See what version we are using
//
OSVERSIONINFO osvi;
osvi .dwOSVersionInfoSize = sizeof (osvi);
::GetVersionEx (&osvi);
bool fIsXP = osvi .dwPlatformId == VER_PLATFORM_WIN32_NT &&
(osvi .dwMajorVersion > 5 || (osvi .dwMajorVersion == 5 &&
osvi .dwMinorVersion >= 1));
//
// Get the flat flag
//
m_fPickerFlat = FALSE;
#if (_WIN32_WINNT >= 0x0501)
if (fIsXP)
::SystemParametersInfo (SPI_GETFLATMENU, 0, &m_fPickerFlat, FALSE);
#endif
//
// Get all the colors I need
//
int nAlpha = 48;
m_clrBackground = ::GetSysColor (COLOR_MENU);
m_clrHiLightBorder = ::GetSysColor (COLOR_HIGHLIGHT);
m_clrHiLight = m_clrHiLightBorder;
#if (WINVER >= 0x0501)
if (fIsXP)
m_clrHiLight = ::GetSysColor (COLOR_MENUHILIGHT);
#endif
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);
//
// Get the margins
//
m_rectMargins .left = ::GetSystemMetrics (SM_CXEDGE);
m_rectMargins .top = ::GetSystemMetrics (SM_CYEDGE);
m_rectMargins .right = ::GetSystemMetrics (SM_CXEDGE);
m_rectMargins .bottom = ::GetSystemMetrics (SM_CYEDGE);
//
// Initialize some sizing parameters
//
m_nNumColors = sizeof (gm_sColors) / sizeof (ColorTableEntry);
_ASSERTE (m_nNumColors <= MAX_COLORS);
if (m_nNumColors > MAX_COLORS)
m_nNumColors = MAX_COLORS;
//
// Initialize our state
//
m_nCurrentSel = INVALID_COLOR;
m_nChosenColorSel = INVALID_COLOR;
m_clrPicker = m_clrCurrent;
//
// Create the font
//
NONCLIENTMETRICS ncm;
ncm .cbSize = sizeof (NONCLIENTMETRICS);
SystemParametersInfo (SPI_GETNONCLIENTMETRICS,
sizeof (NONCLIENTMETRICS), &ncm, 0);
m_font .CreateFontIndirect (&ncm .lfMessageFont);
//
// Create the palette
//
struct
{
LOGPALETTE LogPalette;
PALETTEENTRY PalEntry [MAX_COLORS];
} pal;
LOGPALETTE *pLogPalette = (LOGPALETTE *) &pal;
pLogPalette ->palVersion = 0x300;
pLogPalette ->palNumEntries = (WORD) m_nNumColors;
for (int i = 0; i < m_nNumColors; i++)
{
pLogPalette ->palPalEntry [i] .peRed = GetRValue (gm_sColors [i] .clrColor);
pLogPalette ->palPalEntry [i] .peGreen = GetGValue (gm_sColors [i] .clrColor);
pLogPalette ->palPalEntry [i] .peBlue = GetBValue (gm_sColors [i] .clrColor);
pLogPalette ->palPalEntry [i] .peFlags = 0;
}
m_palette .CreatePalette (pLogPalette);
//
// Register the window class used for the picker
//
WNDCLASSEX wc;
wc .cbSize = sizeof (WNDCLASSEX);
wc .style = CS_CLASSDC | CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
wc .lpfnWndProc = CContainedWindow::StartWindowProc;
wc .cbClsExtra = 0;
wc .cbWndExtra = 0;
wc .hInstance = _Module .GetModuleInstance ();
wc .hIcon = NULL;
wc .hCursor = LoadCursor (NULL, IDC_ARROW);
wc .hbrBackground = (HBRUSH) (COLOR_MENU + 1);
wc .lpszMenuName = NULL;
wc .lpszClassName = _T ("ColorPicker");
wc .hIconSm = NULL;
#if (_WIN32_WINNT >= 0x0501)
if (fIsXP)
{
BOOL fDropShadow;
::SystemParametersInfo (SPI_GETDROPSHADOW, 0, &fDropShadow, FALSE);
if (fDropShadow)
wc .style |= CS_DROPSHADOW;
}
#endif
ATOM atom = ::RegisterClassEx (&wc);
//
// Create the window
//
CRect rcButton;
GetWindowRect (&rcButton);
_Module .AddCreateWndData (&m_wndPicker .m_thunk .cd, &m_wndPicker);
m_wndPicker .m_hWnd = ::CreateWindowEx (0, (LPCTSTR) MAKELONG (atom, 0),
_T (""), WS_POPUP, rcButton .left, rcButton .bottom, 100, 100,
GetParent (), NULL, _Module .GetModuleInstance(), NULL);
//
// If we created the window
//
if (m_wndPicker .m_hWnd != NULL)
{
//
// Set the window size
//
SetPickerWindowSize ();
//
// Create the tooltips
//
CToolTipCtrl sToolTip;
CreatePickerToolTips (sToolTip);
//
// Find which cell (if any) corresponds to the initial color
//
FindPickerCellFromColor (m_clrCurrent);
//
// Make visible
//
m_wndPicker .ShowWindow (SW_SHOWNA);
//
// Purge the message queue of paints
//
MSG msg;
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
{
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
return FALSE;
DispatchMessage(&msg);
}
//
// Set capture to the window which received this message
//
m_wndPicker .SetCapture ();
_ASSERTE (m_wndPicker .m_hWnd == ::GetCapture ());
//
// Get messages until capture lost or cancelled/accepted
//
while (m_wndPicker .m_hWnd == ::GetCapture ())
{
MSG msg;
if (!::GetMessage(&msg, NULL, 0, 0))
{
::PostQuitMessage (msg .wParam);
break;
}
sToolTip .RelayEvent (&msg);
switch (msg.message)
{
case WM_LBUTTONUP:
{
BOOL bHandled = TRUE;
OnPickerLButtonUp (msg .message,
msg .wParam, msg .lParam, bHandled);
}
break;
case WM_MOUSEMOVE:
{
BOOL bHandled = TRUE;
OnPickerMouseMove (msg .message,
msg .wParam, msg .lParam, bHandled);
}
break;
case WM_KEYUP:
break;
case WM_KEYDOWN:
{
BOOL bHandled = TRUE;
OnPickerKeyDown (msg .message,
msg .wParam, msg .lParam, bHandled);
}
break;
case WM_RBUTTONDOWN:
::ReleaseCapture ();
m_fOked = FALSE;
break;
// just dispatch rest of the messages
default:
DispatchMessage (&msg);
break;
}
}
::ReleaseCapture ();
fOked = m_fOked;
//
// Destroy the window
//
sToolTip .DestroyWindow ();
m_wndPicker .DestroyWindow ();
//
// If needed, show custom
//
if (fOked)
{
if (fOked && m_nCurrentSel == CUSTOM_BOX_VALUE)
{
CColorDialog dlg (m_clrCurrent,
CC_FULLOPEN | CC_ANYCOLOR, m_hWnd);
if (dlg .DoModal() == IDOK)
m_clrCurrent = dlg.GetColor();
else
fOked = FALSE;
}
else
m_clrCurrent = m_clrPicker;
}
//
// Clean up GDI objects
//
m_font .DeleteObject ();
m_palette .DeleteObject ();
}
//
// Unregister our class
//
::UnregisterClass ((LPCTSTR) MAKELONG (atom, 0),
_Module .GetModuleInstance());
return fOked;
}
//-----------------------------------------------------------------------------
//
// @mfunc Set the window size of the picker control
//
// @rdesc None.
//
//-----------------------------------------------------------------------------
void CColorButton::SetPickerWindowSize ()
{
SIZE szText = { 0, 0 };
//
// If we are showing a custom or default text area, get the font and text size.
//
if (HasCustomText () || HasDefaultText ())
{
CClientDC dc (m_wndPicker);
HFONT hfontOld = dc .SelectFont (m_font);
//
// Get the size of the custom text (if there IS custom text)
//
if (HasCustomText ())
{
dc .GetTextExtent (m_pszCustomText,
_tcslen (m_pszCustomText), &szText);
}
//
// Get the size of the default text (if there IS default text)
//
if (HasDefaultText ())
{
SIZE szDefault;
dc .GetTextExtent (m_pszDefaultText,
_tcslen (m_pszDefaultText), &szDefault);
if (szDefault .cx > szText .cx)
szText .cx = szDefault .cx;
if (szDefault .cy > szText .cy)
szText .cy = szDefault .cy;
}
dc .SelectFont (hfontOld);
//
// Commpute the final size
//
szText .cx += 2 * (s_sizeTextMargin .cx + s_sizeTextHiBorder .cx);
szText .cy += 2 * (s_sizeTextMargin .cy + s_sizeTextHiBorder .cy);
}
//
// Initiailize our box size
//
_ASSERTE (s_sizeBoxHiBorder .cx == s_sizeBoxHiBorder .cy);
_ASSERTE (s_sizeBoxMargin .cx == s_sizeBoxMargin .cy);
m_sizeBox .cx = s_sizeBoxCore .cx + (s_sizeBoxHiBorder .cx + s_sizeBoxMargin .cx) * 2;
m_sizeBox .cy = s_sizeBoxCore .cy + (s_sizeBoxHiBorder .cy + s_sizeBoxMargin .cy) * 2;
//
// Get the number of columns and rows
//
m_nNumColumns = 8;
m_nNumRows = m_nNumColors / m_nNumColumns;
if ((m_nNumColors % m_nNumColumns) != 0)
m_nNumRows++;
//
// Compute the min width
//
int nBoxTotalWidth = m_nNumColumns * m_sizeBox .cx;
int nMinWidth = nBoxTotalWidth;
if (nMinWidth < szText .cx)
nMinWidth = szText .cx;
//
// Create the rectangle for the default text
//
m_rectDefaultText = CRect (
CPoint (0, 0),
CSize (nMinWidth, HasDefaultText () ? szText .cy : 0)
);
//
// Initialize the color box rectangle
//
m_rectBoxes = CRect (
CPoint ((nMinWidth - nBoxTotalWidth) / 2, m_rectDefaultText .bottom),
CSize (nBoxTotalWidth, m_nNumRows * m_sizeBox .cy)
);
//
// Create the rectangle for the custom text
//
m_rectCustomText = CRect (
CPoint (0, m_rectBoxes .bottom),
CSize (nMinWidth, HasCustomText () ? szText .cy : 0)
);
//
// Get the current window position, and set the new size
//
CRect rectWindow (
m_rectDefaultText .TopLeft (),
m_rectCustomText .BottomRight ());
CRect rect;
m_wndPicker .GetWindowRect (&rect);
rectWindow .OffsetRect (rect .TopLeft ());
//
// Adjust the rects for the border
//
rectWindow .right += m_rectMargins .left + m_rectMargins .right;
rectWindow .bottom += m_rectMargins .top + m_rectMargins .bottom;
::OffsetRect (&m_rectDefaultText, m_rectMargins .left, m_rectMargins .top);
::OffsetRect (&m_rectBoxes, m_rectMargins .left, m_rectMargins .top);
::OffsetRect (&m_rectCustomText, m_rectMargins .left, m_rectMargins .top);
//
// Get the screen rectangle
//
CRect rectScreen (CPoint (0, 0), CSize (
::GetSystemMetrics (SM_CXSCREEN),
::GetSystemMetrics (SM_CYSCREEN)));
#if (WINVER >= 0x0500)
HMODULE hUser32 = ::GetModuleHandleA ("USER32.DLL");
if (hUser32 != NULL)
{
typedef HMONITOR (WINAPI *FN_MonitorFromWindow) (HWND hWnd, DWORD dwFlags);
typedef BOOL (WINAPI *FN_GetMonitorInfo) (HMONITOR hMonitor, LPMONITORINFO lpmi);
FN_MonitorFromWindow pfnMonitorFromWindow = (FN_MonitorFromWindow)
::GetProcAddress (hUser32, "MonitorFromWindow");
FN_GetMonitorInfo pfnGetMonitorInfo = (FN_GetMonitorInfo)
::GetProcAddress (hUser32, "GetMonitorInfoA");
if (pfnMonitorFromWindow != NULL && pfnGetMonitorInfo != NULL)
{
MONITORINFO mi;
HMONITOR hMonitor = pfnMonitorFromWindow (m_hWnd,
MONITOR_DEFAULTTONEAREST);
mi .cbSize = sizeof (mi);
pfnGetMonitorInfo (hMonitor, &mi);
rectScreen = mi .rcWork;
}
}
#endif
//
// Need to check it'll fit on screen: Too far right?
//
if (rectWindow .right > rectScreen .right)
::OffsetRect (&rectWindow, rectScreen .right - rectWindow .right, 0);
//
// Too far left?
//
if (rectWindow .left < rectScreen .left)
::OffsetRect (&rectWindow, rectScreen .left - rectWindow .left, 0);
//
// Bottom falling out of screen? If so, the move
// the whole popup above the parents window
//
if (rectWindow .bottom > rectScreen .bottom)
{
CRect rcParent;
GetWindowRect (&rcParent);
::OffsetRect (&rectWindow, 0,
- ((rcParent .bottom - rcParent .top) +
(rectWindow .bottom - rectWindow .top)));
}
//
// Set the window size and position
//
m_wndPicker .MoveWindow (&rectWindow, TRUE);
}
//-----------------------------------------------------------------------------
//
// @mfunc Create the tooltips for the picker
//
// @parm CToolTipCtrl & | sToolTip | Tool tip control
//
// @rdesc None.
//
//-----------------------------------------------------------------------------
void CColorButton::CreatePickerToolTips (CToolTipCtrl &sToolTip)
{
//
// Create the tool tip
//
if (!sToolTip .Create (m_wndPicker .m_hWnd))
return;
//
// Add a tool for each cell
//
for (int i = 0; i < m_nNumColors; i++)
{
CRect rect;
if (!GetPickerCellRect (i, &rect))
continue;
sToolTip .AddTool (m_wndPicker .m_hWnd,
gm_sColors [i] .pszName, &rect, 1);
}
}
//-----------------------------------------------------------------------------
//
// @mfunc Gets the dimensions of the colour cell given by (row,col)
//
// @parm int | nIndex | Index of the cell
//
// @parm RECT * | pRect | Rectangle of the cell
//
// @rdesc Return value.
//
// @flag TRUE | If the index is valid
// @flag FALSE | If the index is not valid
//
//-----------------------------------------------------------------------------
BOOL CColorButton::GetPickerCellRect (int nIndex, RECT *pRect) const
{
//
// If the custom box
//
if (nIndex == CUSTOM_BOX_VALUE)
{
*pRect = m_rectCustomText;
return TRUE;
}
//
// If the default box
//
else if (nIndex == DEFAULT_BOX_VALUE)
{
*pRect = m_rectDefaultText;
return TRUE;
}
//
// Validate the range
//
if (nIndex < 0 || nIndex >= m_nNumColors)
return FALSE;
//
// Compute the value of the boxes
//
pRect ->left = (nIndex % m_nNumColumns) * m_sizeBox .cx + m_rectBoxes .left;
pRect ->top = (nIndex / m_nNumColumns) * m_sizeBox .cy + m_rectBoxes .top;
pRect ->right = pRect ->left + m_sizeBox .cx;
pRect ->bottom = pRect ->top + m_sizeBox .cy;
return TRUE;
}
//-----------------------------------------------------------------------------
//
// @mfunc Set the chosen color from the given color
//
// @parm COLORREF | clr | Color
//
// @rdesc None
//
//-----------------------------------------------------------------------------
void CColorButton::FindPickerCellFromColor (COLORREF clr)
{
if (clr == CLR_DEFAULT && HasDefaultText ())
{
m_nChosenColorSel = DEFAULT_BOX_VALUE;
return;
}
for (int i = 0; i < m_nNumColors; i++)
{
if (gm_sColors [i] .clrColor == clr)
{
m_nChosenColorSel = i;
return;
}
}
if (HasCustomText ())
m_nChosenColorSel = CUSTOM_BOX_VALUE;
else
m_nChosenColorSel = INVALID_COLOR;
}
//-----------------------------------------------------------------------------
//
// @mfunc Change the current selection
//
// @parm int | nIndex | New selection
//
// @rdesc None
//
//-----------------------------------------------------------------------------
void CColorButton::ChangePickerSelection (int nIndex)
{
CClientDC dc (m_wndPicker);
//
// Clamp the index
//
if (nIndex > m_nNumColors)
nIndex = CUSTOM_BOX_VALUE;
//
// If the current selection is valid, redraw old selection with out
// it being selected
//
if ((m_nCurrentSel >= 0 && m_nCurrentSel < m_nNumColors) ||
m_nCurrentSel == CUSTOM_BOX_VALUE || m_nCurrentSel == DEFAULT_BOX_VALUE)
{
int nOldSel = m_nCurrentSel;
m_nCurrentSel = INVALID_COLOR;
DrawPickerCell (dc, nOldSel);
}
//
// Set the current selection as row/col and draw (it will be drawn selected)
//
m_nCurrentSel = nIndex;
DrawPickerCell (dc, m_nCurrentSel);
//
// Store the current colour
//
BOOL fValid = TRUE;
COLORREF clr;
if (m_nCurrentSel == CUSTOM_BOX_VALUE)
clr = m_clrDefault;
else if (m_nCurrentSel == DEFAULT_BOX_VALUE)
clr = m_clrPicker = CLR_DEFAULT;
else if (m_nCurrentSel == INVALID_COLOR)
{
clr = RGB (0, 0, 0);
fValid = FALSE;
}
else
clr = m_clrPicker = gm_sColors [m_nCurrentSel] .clrColor;
//
// Send the message
//
if (m_fTrackSelection)
{
if (fValid)
m_clrCurrent = clr;
InvalidateRect (NULL);
SendNotification (CPN_SELCHANGE, m_clrCurrent, fValid);
}
}
//-----------------------------------------------------------------------------
//
// @mfunc End the selection
//
// @parm BOOL | fOked | If TRUE, the user has selected a new color.
//
// @rdesc None.
//
//-----------------------------------------------------------------------------
void CColorButton::EndPickerSelection (BOOL fOked)
{
::ReleaseCapture ();
m_fOked = fOked;
}
//-----------------------------------------------------------------------------
//
// @mfunc Draw the given cell
//
// @parm CDC & | dc | Destination cell
//
// @parm int | nIndex | Index of the cell
//
// @rdesc None.
//
//-----------------------------------------------------------------------------
void CColorButton::DrawPickerCell (CDC &dc, int nIndex)
{
//
// Get the drawing rect
//
CRect rect;
if (!GetPickerCellRect (nIndex, &rect))
return;
//
// Get the text pointer and colors
//
LPCTSTR pszText;
COLORREF clrBox;
SIZE sizeMargin;
SIZE sizeHiBorder;
if (nIndex == CUSTOM_BOX_VALUE)
{
pszText = m_pszCustomText;
sizeMargin = s_sizeTextMargin;
sizeHiBorder = s_sizeTextHiBorder;
}
else if (nIndex == DEFAULT_BOX_VALUE)
{
pszText = m_pszDefaultText;
sizeMargin = s_sizeTextMargin;
sizeHiBorder = s_sizeTextHiBorder;
}
else
{
pszText = NULL;
clrBox = gm_sColors [nIndex] .clrColor;
sizeMargin = s_sizeBoxMargin;
sizeHiBorder = s_sizeBoxHiBorder;
}
//
// Based on the selectons, get our colors
//
COLORREF clrHiLight;
COLORREF clrText;
bool fSelected;
if (m_nCurrentSel == nIndex)
{
fSelected = true;
clrHiLight = m_clrHiLight;
clrText = m_clrHiLightText;
}
else if (m_nChosenColorSel == nIndex)
{
fSelected = true;
clrHiLight = m_clrLoLight;
clrText = m_clrText;
}
else
{
fSelected = false;
clrHiLight = m_clrLoLight;
clrText = m_clrText;
}
//
// Select and realize the palette
//
HPALETTE hpalOld = NULL;
if (pszText == NULL)
{
if (m_palette .m_hPalette != NULL &&
(dc .GetDeviceCaps (RASTERCAPS) & RC_PALETTE) != 0)
{
hpalOld = dc .SelectPalette (m_palette, FALSE);
dc .RealizePalette ();
}
}
//
// If we are currently selected
//
if (fSelected)
{
//
// If we have a background margin, then draw that
//
if (sizeMargin .cx > 0 || sizeMargin .cy > 0)
{
dc .SetBkColor (m_clrBackground);
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect .InflateRect (- sizeMargin .cx, - sizeMargin .cy);
}
//
// Draw the selection rectagle
//
dc .SetBkColor (m_clrHiLightBorder);
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect .InflateRect (-1, -1);
//
// Draw the inner coloring
//
dc .SetBkColor (clrHiLight);
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect .InflateRect (- (sizeHiBorder .cx - 1), - (sizeHiBorder .cy - 1));
}
//
// Otherwise, we are not selected
//
else
{
//
// Draw the background
//
dc .SetBkColor (m_clrBackground);
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect .InflateRect (
- (sizeMargin .cx + sizeHiBorder .cx),
- (sizeMargin .cy + sizeHiBorder .cy));
}
//
// Draw custom text
//
if (pszText)
{
HFONT hfontOld = dc .SelectFont (m_font);
dc .SetTextColor (clrText);
dc .SetBkMode (TRANSPARENT);
dc .DrawText (pszText, _tcslen (pszText),
&rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dc .SelectFont (hfontOld);
}
//
// Otherwise, draw color
//
else
{
//
// Draw color (ok, this code is bit sleeeeeezy. But the
// area's that are being drawn are SO small, that nobody
// will notice.)
//
dc .SetBkColor (::GetSysColor (COLOR_3DSHADOW));
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect .InflateRect (-1, -1);
dc .SetBkColor (gm_sColors [nIndex] .clrColor);
dc .ExtTextOut (0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
}
//
// Restore the pallete
//
if (hpalOld && (dc .GetDeviceCaps (RASTERCAPS) & RC_PALETTE) != 0)
dc .SelectPalette (hpalOld, FALSE);
}
//-----------------------------------------------------------------------------
//
// @mfunc Set the chosen color from the given color
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnPickerKeyDown (UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
//
// Get the key data
//
UINT nChar = wParam;
//
// Get the offset for movement
//
int nOffset = 0;
switch (nChar)
{
case VK_DOWN:
nOffset = m_nNumColumns;
break;
case VK_UP:
nOffset = -m_nNumColumns;
break;
case VK_RIGHT:
nOffset = 1;
break;
case VK_LEFT:
nOffset = -1;
break;
case VK_ESCAPE:
m_clrPicker = m_clrCurrent;
EndPickerSelection (FALSE);
break;
case VK_RETURN:
case VK_SPACE:
if (m_nCurrentSel == INVALID_COLOR)
m_clrPicker = m_clrCurrent;
EndPickerSelection (m_nCurrentSel != INVALID_COLOR);
break;
}
//
// If we have an offset
//
if (nOffset != 0)
{
//
// Based on our current position, compute a new position
//
int nNewSel;
if (m_nCurrentSel == INVALID_COLOR)
nNewSel = nOffset > 0 ? DEFAULT_BOX_VALUE : CUSTOM_BOX_VALUE;
else if (m_nCurrentSel == DEFAULT_BOX_VALUE)
nNewSel = nOffset > 0 ? 0 : CUSTOM_BOX_VALUE;
else if (m_nCurrentSel == CUSTOM_BOX_VALUE)
nNewSel = nOffset > 0 ? DEFAULT_BOX_VALUE : m_nNumColors - 1;
else
{
nNewSel = m_nCurrentSel + nOffset;
if (nNewSel < 0)
nNewSel = DEFAULT_BOX_VALUE;
else if (nNewSel >= m_nNumColors)
nNewSel = CUSTOM_BOX_VALUE;
}
//
// Now, for simplicity, the previous code blindly set new
// DEFAUT/CUSTOM indexes without caring if we really have those boxes.
// The following code makes sure we actually map those values into
// their proper locations. This loop will run AT the most, twice.
//
while (true)
{
if (nNewSel == DEFAULT_BOX_VALUE && !HasDefaultText ())
nNewSel = nOffset > 0 ? 0 : CUSTOM_BOX_VALUE;
else if (nNewSel == CUSTOM_BOX_VALUE && !HasCustomText ())
nNewSel = nOffset > 0 ? DEFAULT_BOX_VALUE : m_nNumColors - 1;
else
break;
}
//
// Set the new location
//
ChangePickerSelection (nNewSel);
}
bHandled = FALSE;
return FALSE;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle a button up event
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnPickerLButtonUp (UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
//
// Where did the button come up at?
//
CPoint pt (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
int nNewSelection = PickerHitTest (pt);
//
// If valid, then change selection and end
//
if (nNewSelection != m_nCurrentSel)
ChangePickerSelection (nNewSelection);
EndPickerSelection (nNewSelection != INVALID_COLOR);
return 0;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle mouse move
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnPickerMouseMove (UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL &bHandled)
{
//
// Do a hit test
//
CPoint pt (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
int nNewSelection = PickerHitTest (pt);
//
// 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)
ChangePickerSelection (nNewSelection);
return 0;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle a paint event
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnPickerPaint (UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
CPaintDC dc (m_wndPicker);
//
// Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
// but for some reason isn't
//
CRect rect;
m_wndPicker .GetClientRect (&rect);
if (m_fPickerFlat)
{
CPen pen;
pen .CreatePen (PS_SOLID, 0, ::GetSysColor (COLOR_GRAYTEXT));
HPEN hpenOld = dc .SelectPen (pen);
dc .Rectangle (rect .left, rect .top,
rect .Width (), rect .Height ());
dc .SelectPen (hpenOld);
}
else
{
dc .DrawEdge (&rect, EDGE_RAISED, BF_RECT);
}
//
// Draw the Default Area text
//
if (HasDefaultText ())
DrawPickerCell (dc, DEFAULT_BOX_VALUE);
//
// Draw colour cells
//
for (int i = 0; i < m_nNumColors; i++)
DrawPickerCell (dc, i);
//
// Draw custom text
//
if (HasCustomText ())
DrawPickerCell (dc, CUSTOM_BOX_VALUE);
return 0;
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle palette query for picker
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnPickerQueryNewPalette (UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
Invalidate ();
return DefWindowProc (uMsg, wParam, lParam);
}
//-----------------------------------------------------------------------------
//
// @mfunc Handle palette change for picker
//
// @parm UINT | uMsg | Message
//
// @parm WPARAM | wParam | Message w-parameter
//
// @parm LPARAM | lParam | Message l-parameter
//
// @parm BOOL & | bHandled | If handled, set to true
//
// @rdesc Routine results
//
//-----------------------------------------------------------------------------
LRESULT CColorButton::OnPickerPaletteChanged (UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
LRESULT lResult = DefWindowProc (uMsg, wParam, lParam);
if ((HWND) wParam != m_hWnd)
Invalidate ();
return lResult;
}
//-----------------------------------------------------------------------------
//
// @mfunc Send notification message
//
// @parm UINT | nCode | Notification code
//
// @parm COLORREF | clr | Color to be sent
//
// @parm BOOL | fColorValid | If true, the color is a valid color.
//
// @rdesc None
//
//-----------------------------------------------------------------------------
void CColorButton::SendNotification (UINT nCode, COLORREF clr, BOOL fColorValid)
{
NMCOLORBUTTON nmclr;
nmclr .hdr .code = nCode;
nmclr .hdr .hwndFrom = m_hWnd;
nmclr .hdr .idFrom = GetDlgCtrlID ();
nmclr .fColorValid = fColorValid;
nmclr .clr = clr;
::SendMessage (GetParent (), WM_NOTIFY,
(WPARAM) GetDlgCtrlID (), (LPARAM) &nmclr);
}
//-----------------------------------------------------------------------------
//
// @mfunc Do a hit test
//
// @parm const POINT & | pt | Point inside the window
//
// @rdesc Index/Item over or INVALID_COLOR
//
//-----------------------------------------------------------------------------
int CColorButton::PickerHitTest (const POINT &pt)
{
//
// If we are in the custom text
//
if (m_rectCustomText .PtInRect (pt))
return CUSTOM_BOX_VALUE;
//
// If we are in the default text
//
if (m_rectDefaultText .PtInRect (pt))
return DEFAULT_BOX_VALUE;
//
// If the point isn't in the boxes, return invalid color
//
if (!m_rectBoxes .PtInRect (pt))
return INVALID_COLOR;
//
// Convert the point to an index
//
int nRow = (pt .y - m_rectBoxes .top) / m_sizeBox .cy;
int nCol = (pt .x - m_rectBoxes .left) / m_sizeBox .cx;
if (nRow < 0 || nRow >= m_nNumRows || nCol < 0 || nCol >= m_nNumColumns)
return INVALID_COLOR;
int nIndex = nRow * m_nNumColumns + nCol;
if (nIndex >= m_nNumColors)
return INVALID_COLOR;
return nIndex;
}