ColourPopup.cpp
上传用户:yangzi5763
上传日期:2007-01-02
资源大小:239k
文件大小:29k
源码类别:

ActiveX/DCOM/ATL

开发平台:

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