GME  13
ColourPopup.cpp
Go to the documentation of this file.
00001 // ColourPopup.cpp : implementation file
00002 //
00003 // Written by Chris Maunder (chrismaunder@codeguru.com)
00004 // Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de)
00005 // Copyright (c) 1998.
00006 //
00007 // Updated 30 May 1998 to allow any number of colours, and to
00008 //                     make the appearance closer to Office 97. 
00009 //                     Also added "Default" text area.         (CJM)
00010 //
00011 //         13 June 1998 Fixed change of focus bug (CJM)
00012 //         30 June 1998 Fixed bug caused by focus bug fix (D'oh!!)
00013 //                      Solution suggested by Paul Wilkerson.
00014 //
00015 // ColourPopup is a helper class for the colour picker control
00016 // CColourPicker. Check out the header file or the accompanying 
00017 // HTML doc file for details.
00018 //
00019 // This code may be used in compiled form in any way you desire. This
00020 // file may be redistributed unmodified by any means PROVIDING it is 
00021 // not sold for profit without the authors written consent, and 
00022 // providing that this notice and the authors name is included. 
00023 //
00024 // This file is provided "as is" with no expressed or implied warranty.
00025 // The author accepts no liability if it causes any damage to you or your
00026 // computer whatsoever. It's free, so don't hassle me about it.
00027 //
00028 // Expect bugs.
00029 // 
00030 // Please use and enjoy. Please let me know of any bugs/mods/improvements 
00031 // that you have found/implemented and I will fix/incorporate them into this
00032 // file. 
00033 
00034 #include "stdafx.h"
00035 #include <math.h>
00036 #include "ColourPopup.h"
00037 #include "InPlaceCommon.h"
00038 
00039 #ifdef _DEBUG
00040 #define new DEBUG_NEW
00041 #undef THIS_FILE
00042 static char THIS_FILE[] = __FILE__;
00043 #endif
00044 
00045 #define CUSTOM_BOX_VALUE  -2
00046 #define INVALID_COLOUR    -1
00047 
00048 #define MAX_COLOURS      100
00049 
00050 IMPLEMENT_DYNAMIC(CColourPopup, CDialog)
00051 
00052 
00053 ColourTableEntry CColourPopup::m_crColours[] = 
00054 {
00055     { RGB(0x00, 0x00, 0x00),    _T("Black")             },
00056     { RGB(0xA5, 0x2A, 0x00),    _T("Brown")             },
00057     { RGB(0x00, 0x40, 0x40),    _T("Dark Olive Green")  },
00058     { RGB(0x00, 0x55, 0x00),    _T("Dark Green")        },
00059     { RGB(0x00, 0x00, 0x5E),    _T("Dark Teal")         },
00060     { RGB(0x00, 0x00, 0x8B),    _T("Dark blue")         },
00061     { RGB(0x4B, 0x00, 0x82),    _T("Indigo")            },
00062     { RGB(0x28, 0x28, 0x28),    _T("Dark grey")         },
00063 
00064     { RGB(0x8B, 0x00, 0x00),    _T("Dark red")          },
00065     { RGB(0xFF, 0x68, 0x20),    _T("Orange")            },
00066     { RGB(0x8B, 0x8B, 0x00),    _T("Dark yellow")       },
00067     { RGB(0x00, 0x93, 0x00),    _T("Green")             },
00068     { RGB(0x38, 0x8E, 0x8E),    _T("Teal")              },
00069     { RGB(0x00, 0x00, 0xFF),    _T("Blue")              },
00070     { RGB(0x7B, 0x7B, 0xC0),    _T("Blue-grey")         },
00071     { RGB(0x66, 0x66, 0x66),    _T("Grey - 40")         },
00072 
00073     { RGB(0xFF, 0x00, 0x00),    _T("Red")               },
00074     { RGB(0xFF, 0xAD, 0x5B),    _T("Light orange")      },
00075     { RGB(0x32, 0xCD, 0x32),    _T("Lime")              }, 
00076     { RGB(0x3C, 0xB3, 0x71),    _T("Sea green")         },
00077     { RGB(0x7F, 0xFF, 0xD4),    _T("Aqua")              },
00078     { RGB(0x7D, 0x9E, 0xC0),    _T("Light blue")        },
00079     { RGB(0x80, 0x00, 0x80),    _T("Violet")            },
00080     { RGB(0x7F, 0x7F, 0x7F),    _T("Grey - 50")         },
00081 
00082     { RGB(0xFF, 0xC0, 0xCB),    _T("Pink")              },
00083     { RGB(0xFF, 0xD7, 0x00),    _T("Gold")              },
00084     { RGB(0xFF, 0xFF, 0x00),    _T("Yellow")            },    
00085     { RGB(0x00, 0xFF, 0x00),    _T("Bright green")      },
00086     { RGB(0x40, 0xE0, 0xD0),    _T("Turquoise")         },
00087     { RGB(0xC0, 0xFF, 0xFF),    _T("Skyblue")           },
00088     { RGB(0x48, 0x00, 0x48),    _T("Plum")              },
00089     { RGB(0xC0, 0xC0, 0xC0),    _T("Light grey")        },
00090 
00091     { RGB(0xFF, 0xE4, 0xE1),    _T("Rose")              },
00092     { RGB(0xD2, 0xB4, 0x8C),    _T("Tan")               },
00093     { RGB(0xFF, 0xFF, 0xE0),    _T("Light yellow")      },
00094     { RGB(0x98, 0xFB, 0x98),    _T("Pale green ")       },
00095     { RGB(0xAF, 0xEE, 0xEE),    _T("Pale turquoise")    },
00096     { RGB(0x68, 0x83, 0x8B),    _T("Pale blue")         },
00097     { RGB(0xE6, 0xE6, 0xFA),    _T("Lavender")          },
00098     { RGB(0xFF, 0xFF, 0xFF),    _T("White")             }
00099 };
00100 
00102 // CColourPopup
00103 
00104 CColourPopup::CColourPopup(CWnd* pParent /*=NULL*/)
00105         : CDialog(CColourPopup::IDD, pParent)
00106 {
00107         m_bFirstMouseMsgReceived = false;
00108 }
00109 
00110 CColourPopup::~CColourPopup()
00111 {
00112     m_Font.DeleteObject();
00113     m_Palette.DeleteObject();
00114 }
00115 
00117 // CColourPopup implementation
00118 
00119 // Works out an appropriate size and position of this window
00120 void CColourPopup::SetWindowSize(void)
00121 {
00122     CSize TextSize;
00123 
00124     // If we are showing a custom or default text area, get the font and text size.
00125     if (m_strCustomText.GetLength() || m_strDefaultText.GetLength())
00126     {
00127         CClientDC dc(this);
00128         CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font);
00129 
00130         // Get the size of the custom text (if there IS custom text)
00131         TextSize = CSize(0,0);
00132         if (m_strCustomText.GetLength())
00133             TextSize = dc.GetTextExtent(m_strCustomText);
00134 
00135         // Get the size of the default text (if there IS default text)
00136         if (m_strDefaultText.GetLength())
00137         {
00138             CSize DefaultSize = dc.GetTextExtent(m_strDefaultText);
00139             if (DefaultSize.cx > TextSize.cx) TextSize.cx = DefaultSize.cx;
00140             if (DefaultSize.cy > TextSize.cy) TextSize.cy = DefaultSize.cy;
00141         }
00142 
00143         dc.SelectObject(pOldFont);
00144         TextSize += CSize(2*m_nMargin,2*m_nMargin);
00145 
00146         // Add even more space to draw the horizontal line
00147         TextSize.cy += 2*m_nMargin + 2;
00148     }
00149 
00150     // Get the number of columns and rows
00151     //m_nNumColumns = (int) sqrt((double)m_nNumColours);    // for a square window (yuk)
00152     m_nNumColumns = 8;
00153     m_nNumRows = m_nNumColours / m_nNumColumns;
00154     if (m_nNumColours % m_nNumColumns) m_nNumRows++;
00155 
00156     // Get the current window position, and set the new size
00157     CRect rect;
00158     GetWindowRect(rect);
00159 
00160     m_WindowRect.SetRect(rect.left, rect.top, 
00161                          rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin,
00162                          rect.top  + m_nNumRows*m_nBoxSize + 2*m_nMargin);
00163 
00164     // if custom text, then expand window if necessary, and set text width as
00165     // window width
00166     if (m_strDefaultText.GetLength()) 
00167     {
00168         if (TextSize.cx > m_WindowRect.Width())
00169             m_WindowRect.right = m_WindowRect.left + TextSize.cx;
00170         TextSize.cx = m_WindowRect.Width()-2*m_nMargin;
00171 
00172         // Work out the text area
00173         m_DefaultTextRect.SetRect(m_nMargin, m_nMargin, 
00174                                   m_nMargin+TextSize.cx, 2*m_nMargin+TextSize.cy);
00175         m_WindowRect.bottom += m_DefaultTextRect.Height() + 2*m_nMargin;
00176     }
00177 
00178     // if custom text, then expand window if necessary, and set text width as
00179     // window width
00180     if (m_strCustomText.GetLength()) 
00181     {
00182         if (TextSize.cx > m_WindowRect.Width())
00183             m_WindowRect.right = m_WindowRect.left + TextSize.cx;
00184         TextSize.cx = m_WindowRect.Width()-2*m_nMargin;
00185 
00186         // Work out the text area
00187         m_CustomTextRect.SetRect(m_nMargin, m_WindowRect.Height(), 
00188                                  m_nMargin+TextSize.cx, 
00189                                  m_WindowRect.Height()+m_nMargin+TextSize.cy);
00190         m_WindowRect.bottom += m_CustomTextRect.Height() + 2*m_nMargin;
00191    }
00192 
00193     // Need to check it'll fit on screen: Too far right?
00194         //
00195         // Beware of multi monitor systems! GetSystemMetrics(SM_CYSCREEN) and GetSystemMetrics(SM_CXSCREEN) is just for the primary screen!
00196         // We will use the dimensions of the virtual screen area (composed by the multiple monitor),
00197         // but we assume rectangular area, so if the area is composed by different resolution monitors this safety code
00198         // can be also misleading, but 99% it will be good. For more info see MSDN chapters about multiple monitor displays:
00199         // http://msdn.microsoft.com/en-us/library/ms534611(VS.85).aspx
00200 
00201         int virtualScreenLeft   = GetSystemMetrics(SM_XVIRTUALSCREEN);
00202         int virtualScreenTop    = GetSystemMetrics(SM_YVIRTUALSCREEN);
00203         int virtualScreenRight  = virtualScreenLeft + GetSystemMetrics(SM_CXVIRTUALSCREEN);
00204         int virtualScreenBottom = virtualScreenTop + GetSystemMetrics(SM_CYVIRTUALSCREEN);
00205 
00206         // Too far right?
00207         if (m_WindowRect.right > virtualScreenRight)
00208                 m_WindowRect.OffsetRect(virtualScreenRight - m_WindowRect.right, 0);
00209 
00210         // Too far left?
00211         if (m_WindowRect.left < virtualScreenLeft)
00212                 m_WindowRect.OffsetRect(virtualScreenLeft - m_WindowRect.left, 0);
00213 
00214         // Too far top?
00215         if (m_WindowRect.top < virtualScreenTop)
00216                 m_WindowRect.OffsetRect(virtualScreenTop - m_WindowRect.top, 0);
00217 
00218         // Bottom falling out of screen?
00219         if (m_WindowRect.bottom > virtualScreenBottom)
00220                 m_WindowRect.OffsetRect(virtualScreenBottom - m_WindowRect.bottom, 0);
00221 
00222         // Set the window size and position
00223         MoveWindow(m_WindowRect, TRUE);
00224 }
00225 
00226 void CColourPopup::SetParameters(CRect rectBound, COLORREF crColour, bool rightSideClick,
00227                                                                  LPCTSTR szDefaultText, LPCTSTR szCustomText)
00228 {
00229         m_RectBound      = rectBound;
00230     m_crColour       = m_crInitialColour = crColour;
00231         m_bRightSideClick= rightSideClick;
00232     m_strDefaultText = (szDefaultText)? szDefaultText : _T("");
00233     m_strCustomText  = (szCustomText)?  szCustomText  : _T("");
00234 }
00235 
00236 void CColourPopup::Initialize()
00237 {
00238     m_nNumColours       = sizeof(m_crColours)/sizeof(ColourTableEntry);
00239     ASSERT(m_nNumColours <= MAX_COLOURS);
00240     if (m_nNumColours > MAX_COLOURS)
00241         m_nNumColours = MAX_COLOURS;
00242 
00243     m_nNumColumns       = 0;
00244     m_nNumRows          = 0;
00245     m_nBoxSize          = 18;
00246     m_nMargin           = ::GetSystemMetrics(SM_CXEDGE);
00247     m_nCurrentSel       = INVALID_COLOUR;
00248     m_nChosenColourSel  = INVALID_COLOUR;
00249     m_crColour          = m_crInitialColour = RGB(0,0,0);
00250 
00251     m_bChildWindowVisible = FALSE;
00252 
00253     // Idiot check: Make sure the colour square is at least 5 x 5;
00254     if (m_nBoxSize - 2*m_nMargin - 2 < 5) m_nBoxSize = 5 + 2*m_nMargin + 2;
00255 
00256     // Create the font
00257     NONCLIENTMETRICS ncm;
00258     ncm.cbSize = sizeof(NONCLIENTMETRICS);
00259     VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
00260     m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
00261 
00262     // Create the palette
00263     struct {
00264         LOGPALETTE    LogPalette;
00265         PALETTEENTRY  PalEntry[MAX_COLOURS];
00266     } pal;
00267 
00268     LOGPALETTE* pLogPalette = (LOGPALETTE*) &pal;
00269     pLogPalette->palVersion    = 0x300;
00270     pLogPalette->palNumEntries = (WORD) m_nNumColours; 
00271 
00272     for (int i = 0; i < m_nNumColours; i++)
00273     {
00274         pLogPalette->palPalEntry[i].peRed   = GetRValue(m_crColours[i].crColour);
00275         pLogPalette->palPalEntry[i].peGreen = GetGValue(m_crColours[i].crColour);
00276         pLogPalette->palPalEntry[i].peBlue  = GetBValue(m_crColours[i].crColour);
00277         pLogPalette->palPalEntry[i].peFlags = 0;
00278     }
00279 
00280     m_Palette.CreatePalette(pLogPalette);
00281 }
00282 
00283 int CColourPopup::GetIndex(int row, int col) const
00284 { 
00285     if ((row == CUSTOM_BOX_VALUE || col == CUSTOM_BOX_VALUE) && m_strCustomText.GetLength())
00286         return CUSTOM_BOX_VALUE;
00287     else if ((row == DEFAULT_BOX_VALUE || col == DEFAULT_BOX_VALUE) && m_strDefaultText.GetLength())
00288         return DEFAULT_BOX_VALUE;
00289     else if (row < 0 || col < 0 || row >= m_nNumRows || col >= m_nNumColumns)
00290         return INVALID_COLOUR;
00291     else
00292     {
00293         if (row*m_nNumColumns + col >= m_nNumColours)
00294             return INVALID_COLOUR;
00295         else
00296             return row*m_nNumColumns + col;
00297     }
00298 }
00299 
00300 int CColourPopup::GetRow(int nIndex) const               
00301 { 
00302     if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength())
00303         return CUSTOM_BOX_VALUE;
00304     else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength())
00305         return DEFAULT_BOX_VALUE;
00306     else if (nIndex < 0 || nIndex >= m_nNumColours)
00307         return INVALID_COLOUR;
00308     else
00309         return nIndex / m_nNumColumns; 
00310 }
00311 
00312 int CColourPopup::GetColumn(int nIndex) const            
00313 { 
00314     if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength())
00315         return CUSTOM_BOX_VALUE;
00316     else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength())
00317         return DEFAULT_BOX_VALUE;
00318     else if (nIndex < 0 || nIndex >= m_nNumColours)
00319         return INVALID_COLOUR;
00320     else
00321         return nIndex % m_nNumColumns; 
00322 }
00323 
00324 void CColourPopup::FindCellFromColour(COLORREF crColour)
00325 {
00326     if (crColour == CLR_DEFAULT && m_strDefaultText.GetLength())
00327     {
00328         m_nChosenColourSel = DEFAULT_BOX_VALUE;
00329         return;
00330     }
00331 
00332     for (int i = 0; i < m_nNumColours; i++)
00333     {
00334         if (GetColour(i) == crColour)
00335         {
00336             m_nChosenColourSel = i;
00337             return;
00338         }
00339     }
00340 
00341     if (m_strCustomText.GetLength())
00342         m_nChosenColourSel = CUSTOM_BOX_VALUE;
00343     else
00344         m_nChosenColourSel = INVALID_COLOUR;
00345 }
00346 
00347 // Gets the dimensions of the colour cell given by (row,col)
00348 BOOL CColourPopup::GetCellRect(int nIndex, const LPRECT& rect)
00349 {
00350     if (nIndex == CUSTOM_BOX_VALUE)
00351     {
00352         ::SetRect(rect, 
00353                   m_CustomTextRect.left,  m_CustomTextRect.top,
00354                   m_CustomTextRect.right, m_CustomTextRect.bottom);
00355         return TRUE;
00356     }
00357     else if (nIndex == DEFAULT_BOX_VALUE)
00358     {
00359         ::SetRect(rect, 
00360                   m_DefaultTextRect.left,  m_DefaultTextRect.top,
00361                   m_DefaultTextRect.right, m_DefaultTextRect.bottom);
00362         return TRUE;
00363     }
00364 
00365     if (nIndex < 0 || nIndex >= m_nNumColours)
00366         return FALSE;
00367 
00368     rect->left = GetColumn(nIndex) * m_nBoxSize + m_nMargin;
00369     rect->top  = GetRow(nIndex) * m_nBoxSize + m_nMargin;
00370 
00371     // Move everything down if we are displaying a default text area
00372     if (m_strDefaultText.GetLength()) 
00373         rect->top += (m_nMargin + m_DefaultTextRect.Height());
00374 
00375     rect->right = rect->left + m_nBoxSize;
00376     rect->bottom = rect->top + m_nBoxSize;
00377 
00378     return TRUE;
00379 }
00380 
00381 void CColourPopup::CreateToolTips()
00382 {
00383     // Create the tool tip
00384     if (!m_ToolTip.Create(this)) return;
00385 
00386     // Add a tool for each cell
00387     for (int i = 0; i < m_nNumColours; i++)
00388     {
00389         CRect rect;
00390         if (!GetCellRect(i, rect)) continue;
00391             m_ToolTip.AddTool(this, GetColourName(i), rect, 1);
00392     }
00393 }
00394 
00395 void CColourPopup::ChangeSelection(int nIndex)
00396 {
00397     CClientDC dc(this);        // device context for drawing
00398 
00399     if (nIndex > m_nNumColours)
00400         nIndex = CUSTOM_BOX_VALUE; 
00401 
00402     if ((m_nCurrentSel >= 0 && m_nCurrentSel < m_nNumColours) ||
00403         m_nCurrentSel == CUSTOM_BOX_VALUE || m_nCurrentSel == DEFAULT_BOX_VALUE)
00404     {
00405         // Set Current selection as invalid and redraw old selection (this way
00406         // the old selection will be drawn unselected)
00407         int OldSel = m_nCurrentSel;
00408         m_nCurrentSel = INVALID_COLOUR;
00409         DrawCell(&dc, OldSel);
00410     }
00411 
00412     // Set the current selection as row/col and draw (it will be drawn selected)
00413     m_nCurrentSel = nIndex;
00414     DrawCell(&dc, m_nCurrentSel);
00415 
00416     // Store the current colour
00417     if (m_nCurrentSel == DEFAULT_BOX_VALUE)
00418     {
00419         m_crColour = CLR_DEFAULT;
00420     }
00421     else
00422     {
00423         m_crColour = GetColour(m_nCurrentSel);
00424     }
00425 }
00426 
00427 void CColourPopup::EndSelection(int nMessage)
00428 {
00429     ReleaseCapture();
00430 
00431     // If custom text selected, perform a custom colour selection
00432     if (nMessage != IDCANCEL && m_nCurrentSel == CUSTOM_BOX_VALUE)
00433     {
00434         m_bChildWindowVisible = TRUE;
00435 
00436         CColorDialog dlg(m_crInitialColour, CC_FULLOPEN | CC_ANYCOLOR, this);
00437 
00438         if (dlg.DoModal() == IDOK)
00439             m_crColour = dlg.GetColor();
00440         else
00441             nMessage = IDCANCEL;
00442 
00443         m_bChildWindowVisible = FALSE;
00444     } 
00445 
00446     if (nMessage == IDCANCEL)
00447         m_crColour = m_crInitialColour;
00448 
00449         if (nMessage == IDCANCEL)
00450                 OnCancel();
00451         else
00452                 OnOK();
00453 }
00454 
00455 void CColourPopup::DrawCell(CDC* pDC, int nIndex)
00456 {
00457     // For the Custom Text area
00458     if (m_strCustomText.GetLength() && nIndex == CUSTOM_BOX_VALUE)
00459     {
00460         // The extent of the actual text button
00461         CRect TextButtonRect = m_CustomTextRect;
00462         TextButtonRect.top += 2*m_nMargin;
00463 
00464         // Fill background
00465         pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE));
00466 
00467         // Draw horizontal line
00468         pDC->FillSolidRect(m_CustomTextRect.left+2*m_nMargin, m_CustomTextRect.top,
00469                            m_CustomTextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DSHADOW));
00470         pDC->FillSolidRect(m_CustomTextRect.left+2*m_nMargin, m_CustomTextRect.top+1,
00471                            m_CustomTextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DHILIGHT));
00472 
00473         TextButtonRect.DeflateRect(1,1);
00474 
00475         // fill background
00476         if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex)
00477             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DLIGHT));
00478         else
00479             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE));
00480 
00481         // Draw button
00482         if (m_nCurrentSel == nIndex) 
00483             pDC->DrawEdge(TextButtonRect, BDR_RAISEDINNER, BF_RECT);
00484         else if (m_nChosenColourSel == nIndex)
00485             pDC->DrawEdge(TextButtonRect, BDR_SUNKENOUTER, BF_RECT);
00486 
00487         // Draw custom text
00488         CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font);
00489         pDC->SetBkMode(TRANSPARENT);
00490         pDC->DrawText(m_strCustomText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
00491         pDC->SelectObject(pOldFont);
00492 
00493         return;
00494     }        
00495 
00496     // For the Default Text area
00497     if (m_strDefaultText.GetLength() && nIndex == DEFAULT_BOX_VALUE)
00498     {
00499         // Fill background
00500         pDC->FillSolidRect(m_DefaultTextRect, ::GetSysColor(COLOR_3DFACE));
00501 
00502         // The extent of the actual text button
00503         CRect TextButtonRect = m_DefaultTextRect;
00504         TextButtonRect.DeflateRect(1,1);
00505 
00506         // fill background
00507         if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex)
00508             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DLIGHT));
00509         else
00510             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE));
00511 
00512         // Draw thin line around text
00513         CRect LineRect = TextButtonRect;
00514         LineRect.DeflateRect(2*m_nMargin,2*m_nMargin);
00515         CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
00516         CPen* pOldPen = pDC->SelectObject(&pen);
00517         pDC->SelectStockObject(NULL_BRUSH);
00518         pDC->Rectangle(LineRect);
00519         pDC->SelectObject(pOldPen);
00520 
00521         // Draw button
00522         if (m_nCurrentSel == nIndex) 
00523             pDC->DrawEdge(TextButtonRect, BDR_RAISEDINNER, BF_RECT);
00524         else if (m_nChosenColourSel == nIndex)
00525             pDC->DrawEdge(TextButtonRect, BDR_SUNKENOUTER, BF_RECT);
00526 
00527         // Draw custom text
00528         CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font);
00529         pDC->SetBkMode(TRANSPARENT);
00530         pDC->DrawText(m_strDefaultText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
00531         pDC->SelectObject(pOldFont);
00532 
00533         return;
00534     }        
00535 
00536     CRect rect;
00537     if (!GetCellRect(nIndex, rect)) return;
00538 
00539     // Select and realize the palette
00540     CPalette* pOldPalette = NULL;
00541     if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
00542     {
00543         pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
00544         pDC->RealizePalette();
00545     }
00546 
00547     // fill background
00548     if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex)
00549         pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DHILIGHT));
00550     else
00551         pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
00552 
00553     // Draw button
00554     if (m_nCurrentSel == nIndex) 
00555         pDC->DrawEdge(rect, BDR_RAISEDINNER, BF_RECT);
00556     else if (m_nChosenColourSel == nIndex)
00557         pDC->DrawEdge(rect, BDR_SUNKENOUTER, BF_RECT);
00558 
00559     CBrush brush(PALETTERGB(GetRValue(GetColour(nIndex)), 
00560                             GetGValue(GetColour(nIndex)), 
00561                             GetBValue(GetColour(nIndex)) ));
00562     CPen   pen;
00563     pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
00564 
00565     CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush);
00566     CPen*   pOldPen   = (CPen*)   pDC->SelectObject(&pen);
00567 
00568     // Draw the cell colour
00569     rect.DeflateRect(m_nMargin+1, m_nMargin+1);
00570     pDC->Rectangle(rect);
00571 
00572     // restore DC and cleanup
00573     pDC->SelectObject(pOldBrush);
00574     pDC->SelectObject(pOldPen);
00575     brush.DeleteObject();
00576     pen.DeleteObject();
00577 
00578     if (pOldPalette && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
00579         pDC->SelectPalette(pOldPalette, FALSE);
00580 }
00581 
00582 
00583 BEGIN_MESSAGE_MAP(CColourPopup, CWnd)
00584     //{{AFX_MSG_MAP(CColourPopup)
00585         ON_WM_DESTROY()
00586         ON_WM_LBUTTONUP()
00587         ON_WM_LBUTTONDBLCLK()
00588     ON_WM_PAINT()
00589     ON_WM_MOUSEMOVE()
00590     ON_WM_KEYDOWN()
00591     ON_WM_QUERYNEWPALETTE()
00592     ON_WM_PALETTECHANGED()
00593         //}}AFX_MSG_MAP
00594 END_MESSAGE_MAP()
00595 
00597 // CColourPopup message handlers
00598 
00599 // CColourPopup message handlers
00600 
00601 BOOL CColourPopup::OnInitDialog() 
00602 {
00603         CDialog::OnInitDialog();
00604 
00605     Initialize();
00606 
00607     ASSERT(GetParent() && ::IsWindow(GetParent()->GetSafeHwnd()));
00608 
00609     // Set the window size
00610     SetWindowSize();
00611 
00612     // Create the tooltips
00613     CreateToolTips();
00614 
00615     // Find which cell (if any) corresponds to the initial colour
00616     FindCellFromColour(m_crColour);
00617 
00618         // Capture the mouse, this allows the dialog to close when the user clicks outside.
00619         // The dialog has no "close" button.
00620         SetCapture();
00621 
00622         // Align right
00623         CRect rectWnd;
00624         GetWindowRect(rectWnd);
00625         int nXOffset = m_RectBound.right - rectWnd.right;
00626         SetWindowPos(NULL, rectWnd.left + nXOffset, m_RectBound.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
00627         SetWindowSize();
00628 
00629         if (!m_bRightSideClick)
00630                 m_bFirstMouseMsgReceived = true;
00631 
00632         return TRUE;  // return TRUE unless you set the focus to a control
00633                       // EXCEPTION: OCX Property Pages should return FALSE
00634 }
00635 
00636 void CColourPopup::OnDestroy()
00637 {
00638         ReleaseCapture();
00639 
00640         CDialog::OnDestroy();
00641 }
00642 
00643 // If an arrow key is pressed, then move the selection
00644 void CColourPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
00645 {
00646     int row = GetRow(m_nCurrentSel),
00647         col = GetColumn(m_nCurrentSel);
00648 
00649     if (nChar == VK_DOWN) 
00650     {
00651         if (row == DEFAULT_BOX_VALUE) 
00652             row = col = 0; 
00653         else if (row == CUSTOM_BOX_VALUE)
00654         {
00655             if (m_strDefaultText.GetLength())
00656                 row = col = DEFAULT_BOX_VALUE;
00657             else
00658                 row = col = 0;
00659         }
00660         else
00661         {
00662             row++;
00663             if (GetIndex(row,col) < 0)
00664             {
00665                 if (m_strCustomText.GetLength())
00666                     row = col = CUSTOM_BOX_VALUE;
00667                 else if (m_strDefaultText.GetLength())
00668                     row = col = DEFAULT_BOX_VALUE;
00669                 else
00670                     row = col = 0;
00671             }
00672         }
00673         ChangeSelection(GetIndex(row, col));
00674     }
00675 
00676     if (nChar == VK_UP) 
00677     {
00678         if (row == DEFAULT_BOX_VALUE)
00679         {
00680             if (m_strCustomText.GetLength())
00681                 row = col = CUSTOM_BOX_VALUE;
00682             else
00683            { 
00684                 row = GetRow(m_nNumColours-1); 
00685                 col = GetColumn(m_nNumColours-1); 
00686             }
00687         }
00688         else if (row == CUSTOM_BOX_VALUE)
00689         { 
00690             row = GetRow(m_nNumColours-1); 
00691             col = GetColumn(m_nNumColours-1); 
00692         }
00693         else if (row > 0) row--;
00694         else /* row == 0 */
00695         {
00696             if (m_strDefaultText.GetLength())
00697                 row = col = DEFAULT_BOX_VALUE;
00698             else if (m_strCustomText.GetLength())
00699                 row = col = CUSTOM_BOX_VALUE;
00700             else
00701             { 
00702                 row = GetRow(m_nNumColours-1); 
00703                 col = GetColumn(m_nNumColours-1); 
00704             }
00705         }
00706         ChangeSelection(GetIndex(row, col));
00707     }
00708 
00709     if (nChar == VK_RIGHT) 
00710     {
00711         if (row == DEFAULT_BOX_VALUE) 
00712             row = col = 0; 
00713         else if (row == CUSTOM_BOX_VALUE)
00714         {
00715             if (m_strDefaultText.GetLength())
00716                 row = col = DEFAULT_BOX_VALUE;
00717             else
00718                 row = col = 0;
00719         }
00720         else if (col < m_nNumColumns-1) 
00721             col++;
00722         else 
00723         { 
00724             col = 0; row++;
00725         }
00726 
00727         if (GetIndex(row,col) == INVALID_COLOUR)
00728         {
00729             if (m_strCustomText.GetLength())
00730                 row = col = CUSTOM_BOX_VALUE;
00731             else if (m_strDefaultText.GetLength())
00732                 row = col = DEFAULT_BOX_VALUE;
00733             else
00734                 row = col = 0;
00735         }
00736 
00737         ChangeSelection(GetIndex(row, col));
00738     }
00739 
00740     if (nChar == VK_LEFT) 
00741     {
00742         if (row == DEFAULT_BOX_VALUE)
00743         {
00744             if (m_strCustomText.GetLength())
00745                 row = col = CUSTOM_BOX_VALUE;
00746             else
00747            { 
00748                 row = GetRow(m_nNumColours-1); 
00749                 col = GetColumn(m_nNumColours-1); 
00750             }
00751         }
00752         else if (row == CUSTOM_BOX_VALUE)
00753         { 
00754             row = GetRow(m_nNumColours-1); 
00755             col = GetColumn(m_nNumColours-1); 
00756         }
00757         else if (col > 0) col--;
00758         else /* col == 0 */
00759         {
00760             if (row > 0) { row--; col = m_nNumColumns-1; }
00761             else 
00762             {
00763                 if (m_strDefaultText.GetLength())
00764                     row = col = DEFAULT_BOX_VALUE;
00765                 else if (m_strCustomText.GetLength())
00766                     row = col = CUSTOM_BOX_VALUE;
00767                 else
00768                 { 
00769                     row = GetRow(m_nNumColours-1); 
00770                     col = GetColumn(m_nNumColours-1); 
00771                 }
00772             }
00773         }
00774         ChangeSelection(GetIndex(row, col));
00775     }
00776 
00777     if (nChar == VK_ESCAPE) 
00778     {
00779         m_crColour = m_crInitialColour;
00780         EndSelection(IDCANCEL);
00781         return;
00782     }
00783 
00784     if (nChar == VK_RETURN || nChar == VK_SPACE)
00785     {
00786         EndSelection(IDOK);
00787         return;
00788     }
00789 
00790     CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
00791 }
00792 
00793 void CColourPopup::OnPaint() 
00794 {
00795     CPaintDC dc(this); // device context for painting
00796 
00797     // Draw the Default Area text
00798     if (m_strDefaultText.GetLength())
00799         DrawCell(&dc, DEFAULT_BOX_VALUE);
00800  
00801     // Draw colour cells
00802     for (int i = 0; i < m_nNumColours; i++)
00803         DrawCell(&dc, i);
00804     
00805     // Draw custom text
00806     if (m_strCustomText.GetLength())
00807         DrawCell(&dc, CUSTOM_BOX_VALUE);
00808 
00809     // Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
00810     // but for some reason isn't
00811     CRect rect;
00812     GetClientRect(rect);
00813     dc.DrawEdge(rect, EDGE_RAISED, BF_RECT);
00814 }
00815 
00816 void CColourPopup::OnMouseMove(UINT nFlags, CPoint point) 
00817 {
00818         int nNewSelection = INVALID_COLOUR;
00819 
00820     // Translate points to be relative raised window edge
00821     point.x -= m_nMargin;
00822     point.y -= m_nMargin;
00823 
00824     // First check we aren't in text box
00825     if (m_strCustomText.GetLength() && m_CustomTextRect.PtInRect(point))
00826         nNewSelection = CUSTOM_BOX_VALUE;
00827     else if (m_strDefaultText.GetLength() && m_DefaultTextRect.PtInRect(point))
00828         nNewSelection = DEFAULT_BOX_VALUE;
00829     else
00830     {
00831         // Take into account text box
00832         if (m_strDefaultText.GetLength()) 
00833             point.y -= m_DefaultTextRect.Height();  
00834 
00835         // Get the row and column
00836         nNewSelection = GetIndex(point.y / m_nBoxSize, point.x / m_nBoxSize);
00837 
00838         // In range? If not, default and exit
00839         if (nNewSelection < 0 || nNewSelection >= m_nNumColours)
00840         {
00841             CDialog::OnMouseMove(nFlags, point);
00842             return;
00843         }
00844     }
00845 
00846     // OK - we have the row and column of the current selection (may be CUSTOM_BOX_VALUE)
00847     // Has the row/col selection changed? If yes, then redraw old and new cells.
00848     if (nNewSelection != m_nCurrentSel)
00849         ChangeSelection(nNewSelection);
00850 
00851     CDialog::OnMouseMove(nFlags, point);
00852 }
00853 
00854 // End selection on LButtonUp
00855 void CColourPopup::OnLButtonUp(UINT nFlags, CPoint point) 
00856 {
00857     CDialog::OnLButtonUp(nFlags, point);
00858 
00859         if (!m_bFirstMouseMsgReceived) {
00860                 m_bFirstMouseMsgReceived = true;
00861                 return;
00862         }
00863 
00864         CPoint sPoint = point;
00865         ClientToScreen(&sPoint);
00866         CRect cRect;
00867         GetClientRect(&cRect);
00868         if (cRect.PtInRect(point)) {
00869                 EndSelection(IDOK);
00870         } else {
00871                 EndSelection(IDCANCEL);
00872                 RelayMouseClickToInspectorList(m_pParentWnd, sPoint);
00873         }
00874 }
00875 
00876 BOOL CColourPopup::OnQueryNewPalette() 
00877 {
00878     Invalidate();    
00879     return CDialog::OnQueryNewPalette();
00880 }
00881 
00882 void CColourPopup::OnPaletteChanged(CWnd* pFocusWnd) 
00883 {
00884     CDialog::OnPaletteChanged(pFocusWnd);
00885 
00886     if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
00887         Invalidate();
00888 }
00889 
00890 void CColourPopup::EndDialog(int nResult)
00891 {
00892         ReleaseCapture();
00893 
00894         CDialog::EndDialog(nResult);
00895 }
00896 
00897 // For tooltips
00898 BOOL CColourPopup::PreTranslateMessage(MSG* pMsg) 
00899 {
00900     m_ToolTip.RelayEvent(pMsg);
00901 
00902     // Fix (Adrian Roman): Sometimes if the picker loses focus it is never destroyed
00903         if (GetCapture()->GetSafeHwnd() != m_hWnd)
00904         SetCapture();
00905 
00906     return CWnd::PreTranslateMessage(pMsg);
00907 }