CJColorPopup.cpp
上传用户:xmgzsj
上传日期:2007-01-01
资源大小:46k
文件大小:30k
源码类别:

组合框控件

开发平台:

Visual C++

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