// ColourPicker.cpp : implementation file // // ColourPicker is a drop-in colour picker control. Check out the // header file or the accompanying HTML doc file for details. // // Written by Chris Maunder (chrismaunder@codeguru.com) // Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de) // Copyright (c) 1998. // // 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. If // the source code in this file is used in any commercial application // then a simple email would be nice. // // This file is provided "as is" with no expressed or implied warranty. // The author accepts no liability if it causes any damage to your // computer, causes your pet cat to fall ill, increases baldness or // makes you car start emitting strange noises when you start it up. // // 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. // // Updated 16 May 1998 // 31 May 1998 - added Default text (CJM) // 9 Jan 1999 - minor vis update #include "stdafx.h" #include "ColourPopup.h" #include "ColourPicker.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif void AFXAPI DDX_ColourPicker(CDataExchange *pDX, int nIDC, COLORREF& crColour) { HWND hWndCtrl = pDX->PrepareCtrl(nIDC); ASSERT (hWndCtrl != NULL); CColourPicker* pColourPicker = (CColourPicker*) CWnd::FromHandle(hWndCtrl); if (pDX->m_bSaveAndValidate) { crColour = pColourPicker->GetColour(); } else // initializing { pColourPicker->SetColour(crColour); } } ///////////////////////////////////////////////////////////////////////////// // CColourPicker CColourPicker::CColourPicker() { SetBkColour(GetSysColor(COLOR_3DFACE)); SetTextColour(GetSysColor(COLOR_BTNTEXT)); m_bTrackSelection = FALSE; m_nSelectionMode = CP_MODE_BK; m_bActive = FALSE; m_strDefaultText = _T("Automatic"); m_strCustomText = _T("More Colours..."); } CColourPicker::~CColourPicker() { } IMPLEMENT_DYNCREATE(CColourPicker, CButton) BEGIN_MESSAGE_MAP(CColourPicker, CButton) //{{AFX_MSG_MAP(CColourPicker) ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked) ON_WM_CREATE() //}}AFX_MSG_MAP ON_MESSAGE(CPN_SELENDOK, OnSelEndOK) ON_MESSAGE(CPN_SELENDCANCEL, OnSelEndCancel) ON_MESSAGE(CPN_SELCHANGE, OnSelChange) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CColourPicker message handlers LONG CColourPicker::OnSelEndOK(UINT lParam, LONG /*wParam*/) { COLORREF crNewColour = (COLORREF) lParam; m_bActive = FALSE; SetColour(crNewColour); CWnd *pParent = GetParent(); if (pParent) { pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID()); pParent->SendMessage(CPN_SELENDOK, lParam, (WPARAM) GetDlgCtrlID()); } if (crNewColour != GetColour()) if (pParent) pParent->SendMessage(CPN_SELCHANGE, lParam, (WPARAM) GetDlgCtrlID()); return TRUE; } LONG CColourPicker::OnSelEndCancel(UINT lParam, LONG /*wParam*/) { m_bActive = FALSE; SetColour((COLORREF) lParam); CWnd *pParent = GetParent(); if (pParent) { pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID()); pParent->SendMessage(CPN_SELENDCANCEL, lParam, (WPARAM) GetDlgCtrlID()); } return TRUE; } LONG CColourPicker::OnSelChange(UINT lParam, LONG /*wParam*/) { if (m_bTrackSelection) SetColour((COLORREF) lParam); CWnd *pParent = GetParent(); if (pParent) pParent->SendMessage(CPN_SELCHANGE, lParam, (WPARAM) GetDlgCtrlID()); return TRUE; } int CColourPicker::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CButton::OnCreate(lpCreateStruct) == -1) return -1; SetWindowSize(); // resize appropriately return 0; } // On mouse click, create and show a CColourPopup window for colour selection BOOL CColourPicker::OnClicked() { m_bActive = TRUE; CRect rect; GetWindowRect(rect); new CColourPopup(CPoint(rect.left, rect.bottom), // Point to display popup GetColour(), // Selected colour this, // parent m_strDefaultText, // "Default" text area m_strCustomText); // Custom Text CWnd *pParent = GetParent(); if (pParent) pParent->SendMessage(CPN_DROPDOWN, (LPARAM)GetColour(), (WPARAM) GetDlgCtrlID()); // Docs say I should return FALSE to stop the parent also getting the message. // HA! What a joke. return TRUE; } void CColourPicker::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { ASSERT(lpDrawItemStruct); CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); CRect rect = lpDrawItemStruct->rcItem; UINT state = lpDrawItemStruct->itemState; CString m_strText; CSize Margins(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE)); // Draw arrow if (m_bActive) state |= ODS_SELECTED; pDC->DrawFrameControl(&m_ArrowRect, DFC_SCROLL, DFCS_SCROLLDOWN | ((state & ODS_SELECTED) ? DFCS_PUSHED : 0) | ((state & ODS_DISABLED) ? DFCS_INACTIVE : 0)); pDC->DrawEdge(rect, EDGE_SUNKEN, BF_RECT); // Must reduce the size of the "client" area of the button due to edge thickness. rect.DeflateRect(Margins.cx, Margins.cy); // Fill remaining area with colour rect.right -= m_ArrowRect.Width(); CBrush brush( ((state & ODS_DISABLED) || m_crColourBk == CLR_DEFAULT)? ::GetSysColor(COLOR_3DFACE) : m_crColourBk); CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush); pDC->SelectStockObject(NULL_PEN); pDC->Rectangle(rect); pDC->SelectObject(pOldBrush); // Draw the window text (if any) GetWindowText(m_strText); if (m_strText.GetLength()) { pDC->SetBkMode(TRANSPARENT); if (state & ODS_DISABLED) { rect.OffsetRect(1,1); pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT)); pDC->DrawText(m_strText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); rect.OffsetRect(-1,-1); pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW)); pDC->DrawText(m_strText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); } else { pDC->SetTextColor((m_crColourText == CLR_DEFAULT)? 0 : m_crColourText); pDC->DrawText(m_strText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); } } // Draw focus rect if (state & ODS_FOCUS) { rect.DeflateRect(1,1); pDC->DrawFocusRect(rect); } } ///////////////////////////////////////////////////////////////////////////// // CColourPicker overrides void CColourPicker::PreSubclassWindow() { ModifyStyle(0, BS_OWNERDRAW); // Make it owner drawn CButton::PreSubclassWindow(); SetWindowSize(); // resize appropriately } ///////////////////////////////////////////////////////////////////////////// // CColourPicker attributes COLORREF CColourPicker::GetColour() { return (m_nSelectionMode == CP_MODE_TEXT)? GetTextColour(): GetBkColour(); } void CColourPicker::SetColour(COLORREF crColour) { (m_nSelectionMode == CP_MODE_TEXT)? SetTextColour(crColour): SetBkColour(crColour); } void CColourPicker::SetBkColour(COLORREF crColourBk) { m_crColourBk = crColourBk; if (IsWindow(m_hWnd)) RedrawWindow(); } void CColourPicker::SetTextColour(COLORREF crColourText) { m_crColourText = crColourText; if (IsWindow(m_hWnd)) RedrawWindow(); } void CColourPicker::SetDefaultText(LPCTSTR szDefaultText) { m_strDefaultText = (szDefaultText)? szDefaultText : _T(""); } void CColourPicker::SetCustomText(LPCTSTR szCustomText) { m_strCustomText = (szCustomText)? szCustomText : _T(""); } ///////////////////////////////////////////////////////////////////////////// // CColourPicker implementation void CColourPicker::SetWindowSize() { // Get size dimensions of edges CSize MarginSize(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE)); // Get size of dropdown arrow int nArrowWidth = max(::GetSystemMetrics(SM_CXHTHUMB), 5*MarginSize.cx); int nArrowHeight = max(::GetSystemMetrics(SM_CYVTHUMB), 5*MarginSize.cy); CSize ArrowSize(max(nArrowWidth, nArrowHeight), max(nArrowWidth, nArrowHeight)); // Get window size CRect rect; GetWindowRect(rect); CWnd* pParent = GetParent(); if (pParent) pParent->ScreenToClient(rect); // Set window size at least as wide as 2 arrows, and as high as arrow + margins int nWidth = max(rect.Width(), 2*ArrowSize.cx + 2*MarginSize.cx); MoveWindow(rect.left, rect.top, nWidth, ArrowSize.cy+2*MarginSize.cy, TRUE); // Get the new coords of this window GetWindowRect(rect); ScreenToClient(rect); // Get the rect where the arrow goes, and convert to client coords. m_ArrowRect.SetRect(rect.right - ArrowSize.cx - MarginSize.cx, rect.top + MarginSize.cy, rect.right - MarginSize.cx, rect.bottom - MarginSize.cy); }