ColourPopup.cpp
上传用户:kssdz899
上传日期:2007-01-08
资源大小:79k
文件大小:30k
源码类别:

钩子与API截获

开发平台:

Visual C++

  1. // ColourPopup.cpp : implementation file
  2. //
  3. // Written by Chris Maunder (chrismaunder@codeguru.com)
  4. // Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de)
  5. // Copyright (c) 1998.
  6. //
  7. // Updated 30 May 1998 to allow any number of colours, and to
  8. //                     make the appearance closer to Office 97. 
  9. //                     Also added "Default" text area.         (CJM)
  10. //
  11. //         13 June 1998 Fixed change of focus bug (CJM)
  12. //         30 June 1998 Fixed bug caused by focus bug fix (D'oh!!)
  13. //                      Solution suggested by Paul Wilkerson.
  14. //
  15. // ColourPopup is a helper class for the colour picker control
  16. // CColourPicker. Check out the header file or the accompanying 
  17. // HTML doc file for details.
  18. //
  19. // This code may be used in compiled form in any way you desire. This
  20. // file may be redistributed unmodified by any means PROVIDING it is 
  21. // not sold for profit without the authors written consent, and 
  22. // providing that this notice and the authors name is included. 
  23. //
  24. // This file is provided "as is" with no expressed or implied warranty.
  25. // The author accepts no liability if it causes any damage to you or your
  26. // computer whatsoever. It's free, so don't hassle me about it.
  27. //
  28. // Expect bugs.
  29. // 
  30. // Please use and enjoy. Please let me know of any bugs/mods/improvements 
  31. // that you have found/implemented and I will fix/incorporate them into this
  32. // file. 
  33. #include "stdafx.h"
  34. #include <math.h>
  35. #include "ColourPicker.h"
  36. #include "ColourPopup.h"
  37. #ifdef _DEBUG
  38. #define new DEBUG_NEW
  39. #undef THIS_FILE
  40. static char THIS_FILE[] = __FILE__;
  41. #endif
  42. #define DEFAULT_BOX_VALUE -3
  43. #define CUSTOM_BOX_VALUE  -2
  44. #define INVALID_COLOUR    -1
  45. #define MAX_COLOURS      100
  46. ColourTableEntry CColourPopup::m_crColours[] = 
  47. {
  48.     { RGB(0x00, 0x00, 0x00),    _T("Black")             },
  49.     { RGB(0xA5, 0x2A, 0x00),    _T("Brown")             },
  50.     { RGB(0x00, 0x40, 0x40),    _T("Dark Olive Green")  },
  51.     { RGB(0x00, 0x55, 0x00),    _T("Dark Green")        },
  52.     { RGB(0x00, 0x00, 0x5E),    _T("Dark Teal")         },
  53.     { RGB(0x00, 0x00, 0x8B),    _T("Dark blue")         },
  54.     { RGB(0x4B, 0x00, 0x82),    _T("Indigo")            },
  55.     { RGB(0x28, 0x28, 0x28),    _T("Dark grey")         },
  56.     { RGB(0x8B, 0x00, 0x00),    _T("Dark red")          },
  57.     { RGB(0xFF, 0x68, 0x20),    _T("Orange")            },
  58.     { RGB(0x8B, 0x8B, 0x00),    _T("Dark yellow")       },
  59.     { RGB(0x00, 0x93, 0x00),    _T("Green")             },
  60.     { RGB(0x38, 0x8E, 0x8E),    _T("Teal")              },
  61.     { RGB(0x00, 0x00, 0xFF),    _T("Blue")              },
  62.     { RGB(0x7B, 0x7B, 0xC0),    _T("Blue-grey")         },
  63.     { RGB(0x66, 0x66, 0x66),    _T("Grey - 40")         },
  64.     { RGB(0xFF, 0x00, 0x00),    _T("Red")               },
  65.     { RGB(0xFF, 0xAD, 0x5B),    _T("Light orange")      },
  66.     { RGB(0x32, 0xCD, 0x32),    _T("Lime")              }, 
  67.     { RGB(0x3C, 0xB3, 0x71),    _T("Sea green")         },
  68.     { RGB(0x7F, 0xFF, 0xD4),    _T("Aqua")              },
  69.     { RGB(0x7D, 0x9E, 0xC0),    _T("Light blue")        },
  70.     { RGB(0x80, 0x00, 0x80),    _T("Violet")            },
  71.     { RGB(0x7F, 0x7F, 0x7F),    _T("Grey - 50")         },
  72.     { RGB(0xFF, 0xC0, 0xCB),    _T("Pink")              },
  73.     { RGB(0xFF, 0xD7, 0x00),    _T("Gold")              },
  74.     { RGB(0xFF, 0xFF, 0x00),    _T("Yellow")            },    
  75.     { RGB(0x00, 0xFF, 0x00),    _T("Bright green")      },
  76.     { RGB(0x40, 0xE0, 0xD0),    _T("Turquoise")         },
  77.     { RGB(0xC0, 0xFF, 0xFF),    _T("Skyblue")           },
  78.     { RGB(0x48, 0x00, 0x48),    _T("Plum")              },
  79.     { RGB(0xC0, 0xC0, 0xC0),    _T("Light grey")        },
  80.     { RGB(0xFF, 0xE4, 0xE1),    _T("Rose")              },
  81.     { RGB(0xD2, 0xB4, 0x8C),    _T("Tan")               },
  82.     { RGB(0xFF, 0xFF, 0xE0),    _T("Light yellow")      },
  83.     { RGB(0x98, 0xFB, 0x98),    _T("Pale green ")       },
  84.     { RGB(0xAF, 0xEE, 0xEE),    _T("Pale turquoise")    },
  85.     { RGB(0x68, 0x83, 0x8B),    _T("Pale blue")         },
  86.     { RGB(0xE6, 0xE6, 0xFA),    _T("Lavender")          },
  87.     { RGB(0xFF, 0xFF, 0xFF),    _T("White")             }
  88. };
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CColourPopup
  91. CColourPopup::CColourPopup()
  92. {
  93.     Initialise();
  94. }
  95. CColourPopup::CColourPopup(CPoint p, COLORREF crColour, CWnd* pParentWnd,
  96.                            LPCTSTR szDefaultText /* = NULL */,
  97.                            LPCTSTR szCustomText  /* = NULL */)
  98. {
  99.     Initialise();
  100.     m_crColour       = m_crInitialColour = crColour;
  101.     m_pParent        = pParentWnd;
  102.     m_strDefaultText = (szDefaultText)? szDefaultText : _T("");
  103.     m_strCustomText  = (szCustomText)?  szCustomText  : _T("");
  104.     CColourPopup::Create(p, crColour, pParentWnd, szDefaultText, szCustomText);
  105. }
  106. void CColourPopup::Initialise()
  107. {
  108.     m_nNumColours       = sizeof(m_crColours)/sizeof(ColourTableEntry);
  109.     ASSERT(m_nNumColours <= MAX_COLOURS);
  110.     if (m_nNumColours > MAX_COLOURS)
  111.         m_nNumColours = MAX_COLOURS;
  112.     m_nNumColumns       = 0;
  113.     m_nNumRows          = 0;
  114.     m_nBoxSize          = 18;
  115.     m_nMargin           = ::GetSystemMetrics(SM_CXEDGE);
  116.     m_nCurrentSel       = INVALID_COLOUR;
  117.     m_nChosenColourSel  = INVALID_COLOUR;
  118.     m_pParent           = NULL;
  119.     m_crColour          = m_crInitialColour = RGB(0,0,0);
  120.     m_bChildWindowVisible = FALSE;
  121.     // Idiot check: Make sure the colour square is at least 5 x 5;
  122.     if (m_nBoxSize - 2*m_nMargin - 2 < 5) m_nBoxSize = 5 + 2*m_nMargin + 2;
  123.     // Create the font
  124.     NONCLIENTMETRICS ncm;
  125.     ncm.cbSize = sizeof(NONCLIENTMETRICS);
  126.     VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
  127.     m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
  128.     // Create the palette
  129.     struct {
  130.         LOGPALETTE    LogPalette;
  131.         PALETTEENTRY  PalEntry[MAX_COLOURS];
  132.     } pal;
  133.     LOGPALETTE* pLogPalette = (LOGPALETTE*) &pal;
  134.     pLogPalette->palVersion    = 0x300;
  135.     pLogPalette->palNumEntries = (WORD) m_nNumColours; 
  136.     for (int i = 0; i < m_nNumColours; i++)
  137.     {
  138.         pLogPalette->palPalEntry[i].peRed   = GetRValue(m_crColours[i].crColour);
  139.         pLogPalette->palPalEntry[i].peGreen = GetGValue(m_crColours[i].crColour);
  140.         pLogPalette->palPalEntry[i].peBlue  = GetBValue(m_crColours[i].crColour);
  141.         pLogPalette->palPalEntry[i].peFlags = 0;
  142.     }
  143.     m_Palette.CreatePalette(pLogPalette);
  144. }
  145. CColourPopup::~CColourPopup()
  146. {
  147.     m_Font.DeleteObject();
  148.     m_Palette.DeleteObject();
  149. }
  150. BOOL CColourPopup::Create(CPoint p, COLORREF crColour, CWnd* pParentWnd,
  151.                           LPCTSTR szDefaultText /* = NULL */,
  152.                           LPCTSTR szCustomText  /* = NULL */)
  153. {
  154.     ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd()));
  155.     ASSERT(pParentWnd->IsKindOf(RUNTIME_CLASS(CColourPicker)));
  156.     m_pParent  = pParentWnd;
  157.     m_crColour = m_crInitialColour = crColour;
  158.     // Get the class name and create the window
  159.     CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW,
  160.                                               0,
  161.                                               (HBRUSH) (COLOR_BTNFACE+1), 
  162.                                               0);
  163.     if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP, 
  164.                         p.x, p.y, 100, 100, // size updated soon
  165.                         pParentWnd->GetSafeHwnd(), 0, NULL))
  166.         return FALSE;
  167.     // Store the Custom text
  168.     if (szCustomText != NULL) 
  169.         m_strCustomText = szCustomText;
  170.     // Store the Default Area text
  171.     if (szDefaultText != NULL) 
  172.         m_strDefaultText = szDefaultText;
  173.         
  174.     // Set the window size
  175.     SetWindowSize();
  176.     // Create the tooltips
  177.     CreateToolTips();
  178.     // Find which cell (if any) corresponds to the initial colour
  179.     FindCellFromColour(crColour);
  180.     // Capture all mouse events for the life of this window
  181.     SetCapture();
  182.     return TRUE;
  183. }
  184. BEGIN_MESSAGE_MAP(CColourPopup, CWnd)
  185.     //{{AFX_MSG_MAP(CColourPopup)
  186.     ON_WM_NCDESTROY()
  187.     ON_WM_LBUTTONUP()
  188.     ON_WM_PAINT()
  189.     ON_WM_MOUSEMOVE()
  190.     ON_WM_KEYDOWN()
  191.     ON_WM_QUERYNEWPALETTE()
  192.     ON_WM_PALETTECHANGED()
  193. ON_WM_KILLFOCUS()
  194. ON_WM_ACTIVATEAPP()
  195. //}}AFX_MSG_MAP
  196. END_MESSAGE_MAP()
  197. /////////////////////////////////////////////////////////////////////////////
  198. // CColourPopup message handlers
  199. // For tooltips
  200. BOOL CColourPopup::PreTranslateMessage(MSG* pMsg) 
  201. {
  202.     m_ToolTip.RelayEvent(pMsg);
  203.     // Fix (Adrian Roman): Sometimes if the picker loses focus it is never destroyed
  204.     if (GetCapture()->GetSafeHwnd() != m_hWnd)
  205.         SetCapture(); 
  206.     return CWnd::PreTranslateMessage(pMsg);
  207. }
  208. // If an arrow key is pressed, then move the selection
  209. void CColourPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  210. {
  211.     int row = GetRow(m_nCurrentSel),
  212.         col = GetColumn(m_nCurrentSel);
  213.     if (nChar == VK_DOWN) 
  214.     {
  215.         if (row == DEFAULT_BOX_VALUE) 
  216.             row = col = 0; 
  217.         else if (row == CUSTOM_BOX_VALUE)
  218.         {
  219.             if (m_strDefaultText.GetLength())
  220.                 row = col = DEFAULT_BOX_VALUE;
  221.             else
  222.                 row = col = 0;
  223.         }
  224.         else
  225.         {
  226.             row++;
  227.             if (GetIndex(row,col) < 0)
  228.             {
  229.                 if (m_strCustomText.GetLength())
  230.                     row = col = CUSTOM_BOX_VALUE;
  231.                 else if (m_strDefaultText.GetLength())
  232.                     row = col = DEFAULT_BOX_VALUE;
  233.                 else
  234.                     row = col = 0;
  235.             }
  236.         }
  237.         ChangeSelection(GetIndex(row, col));
  238.     }
  239.     if (nChar == VK_UP) 
  240.     {
  241.         if (row == DEFAULT_BOX_VALUE)
  242.         {
  243.             if (m_strCustomText.GetLength())
  244.                 row = col = CUSTOM_BOX_VALUE;
  245.             else
  246.            { 
  247.                 row = GetRow(m_nNumColours-1); 
  248.                 col = GetColumn(m_nNumColours-1); 
  249.             }
  250.         }
  251.         else if (row == CUSTOM_BOX_VALUE)
  252.         { 
  253.             row = GetRow(m_nNumColours-1); 
  254.             col = GetColumn(m_nNumColours-1); 
  255.         }
  256.         else if (row > 0) row--;
  257.         else /* row == 0 */
  258.         {
  259.             if (m_strDefaultText.GetLength())
  260.                 row = col = DEFAULT_BOX_VALUE;
  261.             else if (m_strCustomText.GetLength())
  262.                 row = col = CUSTOM_BOX_VALUE;
  263.             else
  264.             { 
  265.                 row = GetRow(m_nNumColours-1); 
  266.                 col = GetColumn(m_nNumColours-1); 
  267.             }
  268.         }
  269.         ChangeSelection(GetIndex(row, col));
  270.     }
  271.     if (nChar == VK_RIGHT) 
  272.     {
  273.         if (row == DEFAULT_BOX_VALUE) 
  274.             row = col = 0; 
  275.         else if (row == CUSTOM_BOX_VALUE)
  276.         {
  277.             if (m_strDefaultText.GetLength())
  278.                 row = col = DEFAULT_BOX_VALUE;
  279.             else
  280.                 row = col = 0;
  281.         }
  282.         else if (col < m_nNumColumns-1) 
  283.             col++;
  284.         else 
  285.         { 
  286.             col = 0; row++;
  287.         }
  288.         if (GetIndex(row,col) == INVALID_COLOUR)
  289.         {
  290.             if (m_strCustomText.GetLength())
  291.                 row = col = CUSTOM_BOX_VALUE;
  292.             else if (m_strDefaultText.GetLength())
  293.                 row = col = DEFAULT_BOX_VALUE;
  294.             else
  295.                 row = col = 0;
  296.         }
  297.         ChangeSelection(GetIndex(row, col));
  298.     }
  299.     if (nChar == VK_LEFT) 
  300.     {
  301.         if (row == DEFAULT_BOX_VALUE)
  302.         {
  303.             if (m_strCustomText.GetLength())
  304.                 row = col = CUSTOM_BOX_VALUE;
  305.             else
  306.            { 
  307.                 row = GetRow(m_nNumColours-1); 
  308.                 col = GetColumn(m_nNumColours-1); 
  309.             }
  310.         }
  311.         else if (row == CUSTOM_BOX_VALUE)
  312.         { 
  313.             row = GetRow(m_nNumColours-1); 
  314.             col = GetColumn(m_nNumColours-1); 
  315.         }
  316.         else if (col > 0) col--;
  317.         else /* col == 0 */
  318.         {
  319.             if (row > 0) { row--; col = m_nNumColumns-1; }
  320.             else 
  321.             {
  322.                 if (m_strDefaultText.GetLength())
  323.                     row = col = DEFAULT_BOX_VALUE;
  324.                 else if (m_strCustomText.GetLength())
  325.                     row = col = CUSTOM_BOX_VALUE;
  326.                 else
  327.                 { 
  328.                     row = GetRow(m_nNumColours-1); 
  329.                     col = GetColumn(m_nNumColours-1); 
  330.                 }
  331.             }
  332.         }
  333.         ChangeSelection(GetIndex(row, col));
  334.     }
  335.     if (nChar == VK_ESCAPE) 
  336.     {
  337.         m_crColour = m_crInitialColour;
  338.         EndSelection(CPN_SELENDCANCEL);
  339.         return;
  340.     }
  341.     if (nChar == VK_RETURN || nChar == VK_SPACE)
  342.     {
  343.         EndSelection(CPN_SELENDOK);
  344.         return;
  345.     }
  346.     CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  347. }
  348. // auto-deletion
  349. void CColourPopup::OnNcDestroy() 
  350. {
  351.     CWnd::OnNcDestroy();
  352.     delete this;
  353. }
  354. void CColourPopup::OnPaint() 
  355. {
  356.     CPaintDC dc(this); // device context for painting
  357.     // Draw the Default Area text
  358.     if (m_strDefaultText.GetLength())
  359.         DrawCell(&dc, DEFAULT_BOX_VALUE);
  360.  
  361.     // Draw colour cells
  362.     for (int i = 0; i < m_nNumColours; i++)
  363.         DrawCell(&dc, i);
  364.     
  365.     // Draw custom text
  366.     if (m_strCustomText.GetLength())
  367.         DrawCell(&dc, CUSTOM_BOX_VALUE);
  368.     // Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
  369.     // but for some reason isn't
  370.     CRect rect;
  371.     GetClientRect(rect);
  372.     dc.DrawEdge(rect, EDGE_RAISED, BF_RECT);
  373. }
  374. void CColourPopup::OnMouseMove(UINT nFlags, CPoint point) 
  375. {
  376.     int nNewSelection = INVALID_COLOUR;
  377.     // Translate points to be relative raised window edge
  378.     point.x -= m_nMargin;
  379.     point.y -= m_nMargin;
  380.     // First check we aren't in text box
  381.     if (m_strCustomText.GetLength() && m_CustomTextRect.PtInRect(point))
  382.         nNewSelection = CUSTOM_BOX_VALUE;
  383.     else if (m_strDefaultText.GetLength() && m_DefaultTextRect.PtInRect(point))
  384.         nNewSelection = DEFAULT_BOX_VALUE;
  385.     else
  386.     {
  387.         // Take into account text box
  388.         if (m_strDefaultText.GetLength()) 
  389.             point.y -= m_DefaultTextRect.Height();  
  390.         // Get the row and column
  391.         nNewSelection = GetIndex(point.y / m_nBoxSize, point.x / m_nBoxSize);
  392.         // In range? If not, default and exit
  393.         if (nNewSelection < 0 || nNewSelection >= m_nNumColours)
  394.         {
  395.             CWnd::OnMouseMove(nFlags, point);
  396.             return;
  397.         }
  398.     }
  399.     // OK - we have the row and column of the current selection (may be CUSTOM_BOX_VALUE)
  400.     // Has the row/col selection changed? If yes, then redraw old and new cells.
  401.     if (nNewSelection != m_nCurrentSel)
  402.         ChangeSelection(nNewSelection);
  403.     CWnd::OnMouseMove(nFlags, point);
  404. }
  405. // End selection on LButtonUp
  406. void CColourPopup::OnLButtonUp(UINT nFlags, CPoint point) 
  407. {    
  408.     CWnd::OnLButtonUp(nFlags, point);
  409.     DWORD pos = GetMessagePos();
  410.     point = CPoint(LOWORD(pos), HIWORD(pos));
  411.     if (m_WindowRect.PtInRect(point))
  412.         EndSelection(CPN_SELENDOK);
  413.     else
  414.         EndSelection(CPN_SELENDCANCEL);
  415. }
  416. /////////////////////////////////////////////////////////////////////////////
  417. // CColourPopup implementation
  418. int CColourPopup::GetIndex(int row, int col) const
  419.     if ((row == CUSTOM_BOX_VALUE || col == CUSTOM_BOX_VALUE) && m_strCustomText.GetLength())
  420.         return CUSTOM_BOX_VALUE;
  421.     else if ((row == DEFAULT_BOX_VALUE || col == DEFAULT_BOX_VALUE) && m_strDefaultText.GetLength())
  422.         return DEFAULT_BOX_VALUE;
  423.     else if (row < 0 || col < 0 || row >= m_nNumRows || col >= m_nNumColumns)
  424.         return INVALID_COLOUR;
  425.     else
  426.     {
  427.         if (row*m_nNumColumns + col >= m_nNumColours)
  428.             return INVALID_COLOUR;
  429.         else
  430.             return row*m_nNumColumns + col;
  431.     }
  432. }
  433. int CColourPopup::GetRow(int nIndex) const               
  434.     if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength())
  435.         return CUSTOM_BOX_VALUE;
  436.     else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength())
  437.         return DEFAULT_BOX_VALUE;
  438.     else if (nIndex < 0 || nIndex >= m_nNumColours)
  439.         return INVALID_COLOUR;
  440.     else
  441.         return nIndex / m_nNumColumns; 
  442. }
  443. int CColourPopup::GetColumn(int nIndex) const            
  444.     if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength())
  445.         return CUSTOM_BOX_VALUE;
  446.     else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength())
  447.         return DEFAULT_BOX_VALUE;
  448.     else if (nIndex < 0 || nIndex >= m_nNumColours)
  449.         return INVALID_COLOUR;
  450.     else
  451.         return nIndex % m_nNumColumns; 
  452. }
  453. void CColourPopup::FindCellFromColour(COLORREF crColour)
  454. {
  455.     if (crColour == CLR_DEFAULT && m_strDefaultText.GetLength())
  456.     {
  457.         m_nChosenColourSel = DEFAULT_BOX_VALUE;
  458.         return;
  459.     }
  460.     for (int i = 0; i < m_nNumColours; i++)
  461.     {
  462.         if (GetColour(i) == crColour)
  463.         {
  464.             m_nChosenColourSel = i;
  465.             return;
  466.         }
  467.     }
  468.     if (m_strCustomText.GetLength())
  469.         m_nChosenColourSel = CUSTOM_BOX_VALUE;
  470.     else
  471.         m_nChosenColourSel = INVALID_COLOUR;
  472. }
  473. // Gets the dimensions of the colour cell given by (row,col)
  474. BOOL CColourPopup::GetCellRect(int nIndex, const LPRECT& rect)
  475. {
  476.     if (nIndex == CUSTOM_BOX_VALUE)
  477.     {
  478.         ::SetRect(rect, 
  479.                   m_CustomTextRect.left,  m_CustomTextRect.top,
  480.                   m_CustomTextRect.right, m_CustomTextRect.bottom);
  481.         return TRUE;
  482.     }
  483.     else if (nIndex == DEFAULT_BOX_VALUE)
  484.     {
  485.         ::SetRect(rect, 
  486.                   m_DefaultTextRect.left,  m_DefaultTextRect.top,
  487.                   m_DefaultTextRect.right, m_DefaultTextRect.bottom);
  488.         return TRUE;
  489.     }
  490.     if (nIndex < 0 || nIndex >= m_nNumColours)
  491.         return FALSE;
  492.     rect->left = GetColumn(nIndex) * m_nBoxSize + m_nMargin;
  493.     rect->top  = GetRow(nIndex) * m_nBoxSize + m_nMargin;
  494.     // Move everything down if we are displaying a default text area
  495.     if (m_strDefaultText.GetLength()) 
  496.         rect->top += (m_nMargin + m_DefaultTextRect.Height());
  497.     rect->right = rect->left + m_nBoxSize;
  498.     rect->bottom = rect->top + m_nBoxSize;
  499.     return TRUE;
  500. }
  501. // Works out an appropriate size and position of this window
  502. void CColourPopup::SetWindowSize()
  503. {
  504.     CSize TextSize;
  505.     // If we are showing a custom or default text area, get the font and text size.
  506.     if (m_strCustomText.GetLength() || m_strDefaultText.GetLength())
  507.     {
  508.         CClientDC dc(this);
  509.         CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font);
  510.         // Get the size of the custom text (if there IS custom text)
  511.         TextSize = CSize(0,0);
  512.         if (m_strCustomText.GetLength())
  513.             TextSize = dc.GetTextExtent(m_strCustomText);
  514.         // Get the size of the default text (if there IS default text)
  515.         if (m_strDefaultText.GetLength())
  516.         {
  517.             CSize DefaultSize = dc.GetTextExtent(m_strDefaultText);
  518.             if (DefaultSize.cx > TextSize.cx) TextSize.cx = DefaultSize.cx;
  519.             if (DefaultSize.cy > TextSize.cy) TextSize.cy = DefaultSize.cy;
  520.         }
  521.         dc.SelectObject(pOldFont);
  522.         TextSize += CSize(2*m_nMargin,2*m_nMargin);
  523.         // Add even more space to draw the horizontal line
  524.         TextSize.cy += 2*m_nMargin + 2;
  525.     }
  526.     // Get the number of columns and rows
  527.     //m_nNumColumns = (int) sqrt((double)m_nNumColours);    // for a square window (yuk)
  528.     m_nNumColumns = 8;
  529.     m_nNumRows = m_nNumColours / m_nNumColumns;
  530.     if (m_nNumColours % m_nNumColumns) m_nNumRows++;
  531.     // Get the current window position, and set the new size
  532.     CRect rect;
  533.     GetWindowRect(rect);
  534.     m_WindowRect.SetRect(rect.left, rect.top, 
  535.                          rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin,
  536.                          rect.top  + m_nNumRows*m_nBoxSize + 2*m_nMargin);
  537.     // if custom text, then expand window if necessary, and set text width as
  538.     // window width
  539.     if (m_strDefaultText.GetLength()) 
  540.     {
  541.         if (TextSize.cx > m_WindowRect.Width())
  542.             m_WindowRect.right = m_WindowRect.left + TextSize.cx;
  543.         TextSize.cx = m_WindowRect.Width()-2*m_nMargin;
  544.         // Work out the text area
  545.         m_DefaultTextRect.SetRect(m_nMargin, m_nMargin, 
  546.                                   m_nMargin+TextSize.cx, 2*m_nMargin+TextSize.cy);
  547.         m_WindowRect.bottom += m_DefaultTextRect.Height() + 2*m_nMargin;
  548.     }
  549.     // if custom text, then expand window if necessary, and set text width as
  550.     // window width
  551.     if (m_strCustomText.GetLength()) 
  552.     {
  553.         if (TextSize.cx > m_WindowRect.Width())
  554.             m_WindowRect.right = m_WindowRect.left + TextSize.cx;
  555.         TextSize.cx = m_WindowRect.Width()-2*m_nMargin;
  556.         // Work out the text area
  557.         m_CustomTextRect.SetRect(m_nMargin, m_WindowRect.Height(), 
  558.                                  m_nMargin+TextSize.cx, 
  559.                                  m_WindowRect.Height()+m_nMargin+TextSize.cy);
  560.         m_WindowRect.bottom += m_CustomTextRect.Height() + 2*m_nMargin;
  561.    }
  562.     // Need to check it'll fit on screen: Too far right?
  563.     CSize ScreenSize(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN));
  564.     if (m_WindowRect.right > ScreenSize.cx)
  565.         m_WindowRect.OffsetRect(-(m_WindowRect.right - ScreenSize.cx), 0);
  566.     // Too far left?
  567.     if (m_WindowRect.left < 0)
  568.         m_WindowRect.OffsetRect( -m_WindowRect.left, 0);
  569.     // Bottom falling out of screen?
  570.     if (m_WindowRect.bottom > ScreenSize.cy)
  571.     {
  572.         CRect ParentRect;
  573.         m_pParent->GetWindowRect(ParentRect);
  574.         m_WindowRect.OffsetRect(0, -(ParentRect.Height() + m_WindowRect.Height()));
  575.     }
  576.     // Set the window size and position
  577.     MoveWindow(m_WindowRect, TRUE);
  578. }
  579. void CColourPopup::CreateToolTips()
  580. {
  581.     // Create the tool tip
  582.     if (!m_ToolTip.Create(this)) return;
  583.     // Add a tool for each cell
  584.     for (int i = 0; i < m_nNumColours; i++)
  585.     {
  586.         CRect rect;
  587.         if (!GetCellRect(i, rect)) continue;
  588.             m_ToolTip.AddTool(this, GetColourName(i), rect, 1);
  589.     }
  590. }
  591. void CColourPopup::ChangeSelection(int nIndex)
  592. {
  593.     CClientDC dc(this);        // device context for drawing
  594.     if (nIndex > m_nNumColours)
  595.         nIndex = CUSTOM_BOX_VALUE; 
  596.     if ((m_nCurrentSel >= 0 && m_nCurrentSel < m_nNumColours) ||
  597.         m_nCurrentSel == CUSTOM_BOX_VALUE || m_nCurrentSel == DEFAULT_BOX_VALUE)
  598.     {
  599.         // Set Current selection as invalid and redraw old selection (this way
  600.         // the old selection will be drawn unselected)
  601.         int OldSel = m_nCurrentSel;
  602.         m_nCurrentSel = INVALID_COLOUR;
  603.         DrawCell(&dc, OldSel);
  604.     }
  605.     // Set the current selection as row/col and draw (it will be drawn selected)
  606.     m_nCurrentSel = nIndex;
  607.     DrawCell(&dc, m_nCurrentSel);
  608.     // Store the current colour
  609.     if (m_nCurrentSel == CUSTOM_BOX_VALUE)
  610.         m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crInitialColour, 0);
  611.     else if (m_nCurrentSel == DEFAULT_BOX_VALUE)
  612.     {
  613.         m_crColour = CLR_DEFAULT;
  614.         m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) CLR_DEFAULT, 0);
  615.     }
  616.     else
  617.     {
  618.         m_crColour = GetColour(m_nCurrentSel);
  619.         m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crColour, 0);
  620.     }
  621. }
  622. void CColourPopup::EndSelection(int nMessage)
  623. {
  624.     ReleaseCapture();
  625.     // If custom text selected, perform a custom colour selection
  626.     if (nMessage != CPN_SELENDCANCEL && m_nCurrentSel == CUSTOM_BOX_VALUE)
  627.     {
  628.         m_bChildWindowVisible = TRUE;
  629.         CColorDialog dlg(m_crInitialColour, CC_FULLOPEN | CC_ANYCOLOR, this);
  630.         if (dlg.DoModal() == IDOK)
  631.             m_crColour = dlg.GetColor();
  632.         else
  633.             nMessage = CPN_SELENDCANCEL;
  634.         m_bChildWindowVisible = FALSE;
  635.     } 
  636.     if (nMessage == CPN_SELENDCANCEL)
  637.         m_crColour = m_crInitialColour;
  638.     m_pParent->SendMessage(nMessage, (WPARAM) m_crColour, 0);
  639.     
  640.     // Kill focus bug fixed by Martin Wawrusch
  641.     if (!m_bChildWindowVisible)
  642.         DestroyWindow();
  643. }
  644. void CColourPopup::DrawCell(CDC* pDC, int nIndex)
  645. {
  646.     // For the Custom Text area
  647.     if (m_strCustomText.GetLength() && nIndex == CUSTOM_BOX_VALUE)
  648.     {
  649.         // The extent of the actual text button
  650.         CRect TextButtonRect = m_CustomTextRect;
  651.         TextButtonRect.top += 2*m_nMargin;
  652.         // Fill background
  653.         pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE));
  654.         // Draw horizontal line
  655.         pDC->FillSolidRect(m_CustomTextRect.left+2*m_nMargin, m_CustomTextRect.top,
  656.                            m_CustomTextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DSHADOW));
  657.         pDC->FillSolidRect(m_CustomTextRect.left+2*m_nMargin, m_CustomTextRect.top+1,
  658.                            m_CustomTextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DHILIGHT));
  659.         TextButtonRect.DeflateRect(1,1);
  660.         // fill background
  661.         if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex)
  662.             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DLIGHT));
  663.         else
  664.             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE));
  665.         // Draw button
  666.         if (m_nCurrentSel == nIndex) 
  667.             pDC->DrawEdge(TextButtonRect, BDR_RAISEDINNER, BF_RECT);
  668.         else if (m_nChosenColourSel == nIndex)
  669.             pDC->DrawEdge(TextButtonRect, BDR_SUNKENOUTER, BF_RECT);
  670.         // Draw custom text
  671.         CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font);
  672.         pDC->SetBkMode(TRANSPARENT);
  673.         pDC->DrawText(m_strCustomText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  674.         pDC->SelectObject(pOldFont);
  675.         return;
  676.     }        
  677.     // For the Default Text area
  678.     if (m_strDefaultText.GetLength() && nIndex == DEFAULT_BOX_VALUE)
  679.     {
  680.         // Fill background
  681.         pDC->FillSolidRect(m_DefaultTextRect, ::GetSysColor(COLOR_3DFACE));
  682.         // The extent of the actual text button
  683.         CRect TextButtonRect = m_DefaultTextRect;
  684.         TextButtonRect.DeflateRect(1,1);
  685.         // fill background
  686.         if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex)
  687.             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DLIGHT));
  688.         else
  689.             pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE));
  690.         // Draw thin line around text
  691.         CRect LineRect = TextButtonRect;
  692.         LineRect.DeflateRect(2*m_nMargin,2*m_nMargin);
  693.         CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
  694.         CPen* pOldPen = pDC->SelectObject(&pen);
  695.         pDC->SelectStockObject(NULL_BRUSH);
  696.         pDC->Rectangle(LineRect);
  697.         pDC->SelectObject(pOldPen);
  698.         // Draw button
  699.         if (m_nCurrentSel == nIndex) 
  700.             pDC->DrawEdge(TextButtonRect, BDR_RAISEDINNER, BF_RECT);
  701.         else if (m_nChosenColourSel == nIndex)
  702.             pDC->DrawEdge(TextButtonRect, BDR_SUNKENOUTER, BF_RECT);
  703.         // Draw custom text
  704.         CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font);
  705.         pDC->SetBkMode(TRANSPARENT);
  706.         pDC->DrawText(m_strDefaultText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  707.         pDC->SelectObject(pOldFont);
  708.         return;
  709.     }        
  710.     CRect rect;
  711.     if (!GetCellRect(nIndex, rect)) return;
  712.     // Select and realize the palette
  713.     CPalette* pOldPalette = NULL;
  714.     if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
  715.     {
  716.         pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
  717.         pDC->RealizePalette();
  718.     }
  719.     // fill background
  720.     if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex)
  721.         pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DHILIGHT));
  722.     else
  723.         pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
  724.     // Draw button
  725.     if (m_nCurrentSel == nIndex) 
  726.         pDC->DrawEdge(rect, BDR_RAISEDINNER, BF_RECT);
  727.     else if (m_nChosenColourSel == nIndex)
  728.         pDC->DrawEdge(rect, BDR_SUNKENOUTER, BF_RECT);
  729.     CBrush brush(PALETTERGB(GetRValue(GetColour(nIndex)), 
  730.                             GetGValue(GetColour(nIndex)), 
  731.                             GetBValue(GetColour(nIndex)) ));
  732.     CPen   pen;
  733.     pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
  734.     CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush);
  735.     CPen*   pOldPen   = (CPen*)   pDC->SelectObject(&pen);
  736.     // Draw the cell colour
  737.     rect.DeflateRect(m_nMargin+1, m_nMargin+1);
  738.     pDC->Rectangle(rect);
  739.     // restore DC and cleanup
  740.     pDC->SelectObject(pOldBrush);
  741.     pDC->SelectObject(pOldPen);
  742.     brush.DeleteObject();
  743.     pen.DeleteObject();
  744.     if (pOldPalette && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
  745.         pDC->SelectPalette(pOldPalette, FALSE);
  746. }
  747. BOOL CColourPopup::OnQueryNewPalette() 
  748. {
  749.     Invalidate();    
  750.     return CWnd::OnQueryNewPalette();
  751. }
  752. void CColourPopup::OnPaletteChanged(CWnd* pFocusWnd) 
  753. {
  754.     CWnd::OnPaletteChanged(pFocusWnd);
  755.     if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
  756.         Invalidate();
  757. }
  758. void CColourPopup::OnKillFocus(CWnd* pNewWnd) 
  759. {
  760. CWnd::OnKillFocus(pNewWnd);
  761.     ReleaseCapture();
  762.     //DestroyWindow(); - causes crash when Custom colour dialog appears.
  763. }
  764. // KillFocus problem fix suggested by Paul Wilkerson.
  765. void CColourPopup::OnActivateApp(BOOL bActive, HTASK hTask) 
  766. {
  767. CWnd::OnActivateApp(bActive, hTask);
  768. // If Deactivating App, cancel this selection
  769. if (!bActive)
  770.  EndSelection(CPN_SELENDCANCEL);
  771. }