ColourPopup.cpp
上传用户:cqzhuye
上传日期:2007-01-01
资源大小:72k
文件大小:21k
源码类别:

浏览器

开发平台:

Visual C++

  1. // ColourPopup.cpp : implementation file
  2. //
  3. // Written by Chris Maunder (Chris.Maunder@cbr.clw.csiro.au)
  4. // Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de)
  5. // Copyright (c) 1998.
  6. //
  7. // ColourPopup is a helper class for the colour picker control
  8. // CColourPicker. Check out the header file or the accompanying 
  9. // HTML doc file for details.
  10. //
  11. // This code may be used in compiled form in any way you desire. This
  12. // file may be redistributed unmodified by any means PROVIDING it is 
  13. // not sold for profit without the authors written consent, and 
  14. // providing that this notice and the authors name is included. 
  15. //
  16. // This file is provided "as is" with no expressed or implied warranty.
  17. // The author accepts no liability if it causes any damage to you or your
  18. // computer whatsoever. It's free, so don't hassle me about it.
  19. //
  20. // Expect bugs.
  21. // 
  22. // Please use and enjoy. Please let me know of any bugs/mods/improvements 
  23. // that you have found/implemented and I will fix/incorporate them into this
  24. // file. 
  25. #include "stdafx.h"
  26. #include <math.h>
  27. #include "ColourPicker.h"
  28. #include "ColourPopup.h"
  29. #ifdef _DEBUG
  30. #define new DEBUG_NEW
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34. #define TEXT_BOX_VALUE -2        // Sorry about this hack...
  35. #define MAX_COLOURS    100
  36. ColourTableEntry CColourPopup::m_crColours[] = 
  37. {
  38.     { RGB(0x00, 0x00, 0x00),    _T("Black")             },
  39.     { RGB(0xA5, 0x2A, 0x00),    _T("Brown")             },
  40.     { RGB(0x00, 0x40, 0x40),    _T("Dark Olive Green")  },
  41.     { RGB(0x00, 0x55, 0x00),    _T("Dark Green")        },
  42.     { RGB(0x00, 0x00, 0x5E),    _T("Dark Teal")         },
  43.     { RGB(0x00, 0x00, 0x8B),    _T("Dark blue")         },
  44.     { RGB(0x4B, 0x00, 0x82),    _T("Indigo")            },
  45.     { RGB(0x28, 0x28, 0x28),    _T("Dark grey")         },
  46.     { RGB(0x8B, 0x00, 0x00),    _T("Dark red")          },
  47.     { RGB(0xFF, 0x68, 0x20),    _T("Orange")            },
  48.     { RGB(0x8B, 0x8B, 0x00),    _T("Dark yellow")       },
  49.     { RGB(0x00, 0x93, 0x00),    _T("Green")             },
  50.     { RGB(0x38, 0x8E, 0x8E),    _T("Teal")              },
  51.     { RGB(0x00, 0x00, 0xFF),    _T("Blue")              },
  52.     { RGB(0x7B, 0x7B, 0xC0),    _T("Blue-grey")         },
  53.     { RGB(0x66, 0x66, 0x66),    _T("Grey - 40")         },
  54.     { RGB(0xFF, 0x00, 0x00),    _T("Red")               },
  55.     { RGB(0xFF, 0xAD, 0x5B),    _T("Light orange")      },
  56.     { RGB(0x32, 0xCD, 0x32),    _T("Lime")              }, 
  57.     { RGB(0x3C, 0xB3, 0x71),    _T("Sea green")         },
  58.     { RGB(0x7F, 0xFF, 0xD4),    _T("Aqua")              },
  59.     { RGB(0x7D, 0x9E, 0xC0),    _T("Light blue")        },
  60.     { RGB(0x80, 0x00, 0x80),    _T("Violet")            },
  61.     { RGB(0x7F, 0x7F, 0x7F),    _T("Grey - 50")         },
  62.     { RGB(0xFF, 0xC0, 0xCB),    _T("Pink")              },
  63.     { RGB(0xFF, 0xD7, 0x00),    _T("Gold")              },
  64.     { RGB(0xFF, 0xFF, 0x00),    _T("Yellow")            },    
  65.     { RGB(0x00, 0xFF, 0x00),    _T("Bright green")      },
  66.     { RGB(0x40, 0xE0, 0xD0),    _T("Turquoise")         },
  67.     { RGB(0xC0, 0xFF, 0xFF),    _T("Skyblue")           },
  68.     { RGB(0x48, 0x00, 0x48),    _T("Plum")              },
  69.     { RGB(0xC0, 0xC0, 0xC0),    _T("Light grey")        },
  70.     { RGB(0xFF, 0xE4, 0xE1),    _T("Rose")              },
  71.     { RGB(0xD2, 0xB4, 0x8C),    _T("Tan")               },
  72.     { RGB(0xFF, 0xFF, 0xE0),    _T("Light yellow")      },
  73.     { RGB(0x98, 0xFB, 0x98),    _T("Pale green ")       },
  74.     { RGB(0xAF, 0xEE, 0xEE),    _T("Pale turquoise")    },
  75.     { RGB(0x68, 0x83, 0x8B),    _T("Pale blue")         },
  76.     { RGB(0xE6, 0xE6, 0xFA),    _T("Lavender")          },
  77.     { RGB(0xFF, 0xFF, 0xFF),    _T("White")             }
  78. };
  79. /////////////////////////////////////////////////////////////////////////////
  80. // CColourPopup
  81. CColourPopup::CColourPopup()
  82. {
  83.     Initialise();
  84. }
  85. CColourPopup::CColourPopup(CPoint p, COLORREF crColour, CWnd* pParentWnd, UINT nID, 
  86.                            LPCTSTR szCustomText /* = NULL */)
  87. {
  88.     Initialise();
  89.     m_crColour = m_crInitialColour = crColour;
  90.     if (szCustomText != NULL)
  91.     {
  92.         m_bShowCustom   = TRUE;
  93.         m_strCustomText = szCustomText;
  94.     } else
  95.         m_bShowCustom = FALSE;
  96.     m_pParent           = pParentWnd;
  97.     CColourPopup::Create(p, crColour, pParentWnd, nID, szCustomText);
  98. }
  99. void CColourPopup::Initialise()
  100. {
  101.     m_nNumColours       = sizeof(m_crColours)/sizeof(ColourTableEntry);
  102.     ASSERT(m_nNumColours <= MAX_COLOURS);
  103.     if (m_nNumColours > MAX_COLOURS)
  104.         m_nNumColours = MAX_COLOURS;
  105.     m_nNumColumns       = 0;
  106.     m_nNumRows          = 0;
  107.     m_nBoxSize          = 18;
  108.     m_nMargin           = ::GetSystemMetrics(SM_CXEDGE);
  109.     m_nCurrentRow       = -1;
  110.     m_nCurrentCol       = -1;
  111.     m_nChosenColourRow  = -1;
  112.     m_nChosenColourCol  = -1;
  113.     m_strCustomText     = _T("More...");
  114.     m_bShowCustom       = TRUE;
  115.     m_pParent           = NULL;
  116.     m_crColour          = m_crInitialColour = RGB(0,0,0);
  117.     // Idiot check: Make sure the colour square is at least 5 x 5;
  118.     if (m_nBoxSize - 2*m_nMargin - 2 < 5) m_nBoxSize = 5 + 2*m_nMargin + 2;
  119.     // Create the font
  120.     NONCLIENTMETRICS ncm;
  121.     ncm.cbSize = sizeof(NONCLIENTMETRICS);
  122.     VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
  123.     m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
  124.     // Create the palette
  125.     struct {
  126.         LOGPALETTE    LogPalette;
  127.         PALETTEENTRY  PalEntry[MAX_COLOURS];
  128.     } pal;
  129.     LOGPALETTE* pLogPalette = (LOGPALETTE*) &pal;
  130.     pLogPalette->palVersion    = 0x300;
  131.     pLogPalette->palNumEntries = m_nNumColours; 
  132.     for (int i = 0; i < m_nNumColours; i++)
  133.     {
  134.         pLogPalette->palPalEntry[i].peRed   = GetRValue(m_crColours[i].crColour);
  135.         pLogPalette->palPalEntry[i].peGreen = GetGValue(m_crColours[i].crColour);
  136.         pLogPalette->palPalEntry[i].peBlue  = GetBValue(m_crColours[i].crColour);
  137.         pLogPalette->palPalEntry[i].peFlags = 0;
  138.     }
  139.     m_Palette.CreatePalette(pLogPalette);
  140. }
  141. CColourPopup::~CColourPopup()
  142. {
  143.     m_Font.DeleteObject();
  144.     m_Palette.DeleteObject();
  145. }
  146. BOOL CColourPopup::Create(CPoint p, COLORREF crColour, CWnd* pParentWnd, UINT nID, 
  147.                           LPCTSTR szCustomText /* = NULL */)
  148. {
  149.     ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd()));
  150.     ASSERT(pParentWnd->IsKindOf(RUNTIME_CLASS(CColourPicker)));
  151.     m_pParent  = pParentWnd;
  152.     m_crColour = m_crInitialColour = crColour;
  153.     // Get the class name and create the window
  154.     CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW,
  155.                                               0, (HBRUSH)GetStockObject(LTGRAY_BRUSH),0);
  156.     if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP, 
  157.                         p.x, p.y, 100, 100, // size updated soon
  158.                         pParentWnd->GetSafeHwnd(), 0, NULL))
  159.         return FALSE;
  160.     // Store the Custom text
  161.     if (szCustomText != NULL) 
  162.         m_strCustomText = szCustomText;
  163.     // Set the window size
  164.     SetWindowSize();
  165.     // Create the tooltips
  166.     CreateToolTips();
  167.     // Find which cell (if any) corresponds to the initial colour
  168.     FindCellFromColour(crColour);
  169.     // Capture all mouse events for the life of this window
  170.     SetCapture();
  171.     return TRUE;
  172. }
  173. BEGIN_MESSAGE_MAP(CColourPopup, CWnd)
  174.     //{{AFX_MSG_MAP(CColourPopup)
  175.     ON_WM_NCDESTROY()
  176.     ON_WM_LBUTTONUP()
  177.     ON_WM_PAINT()
  178.     ON_WM_MOUSEMOVE()
  179.     ON_WM_KEYDOWN()
  180.     ON_WM_QUERYNEWPALETTE()
  181.     ON_WM_PALETTECHANGED()
  182.     //}}AFX_MSG_MAP
  183. END_MESSAGE_MAP()
  184. /////////////////////////////////////////////////////////////////////////////
  185. // CColourPopup message handlers
  186. // For tooltips
  187. BOOL CColourPopup::PreTranslateMessage(MSG* pMsg) 
  188. {
  189.     m_ToolTip.RelayEvent(pMsg);
  190.     return CWnd::PreTranslateMessage(pMsg);
  191. }
  192. // If an arrow key is pressed, then move the selection
  193. void CColourPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  194. {
  195.     int row = m_nCurrentRow,
  196.         col = m_nCurrentCol;
  197.     if (nChar == VK_DOWN) 
  198.     {
  199.         if (row < 0) { row = 0; col = 0; }
  200.         else if (row < m_nNumRows-1) row++;
  201.         else { row = TEXT_BOX_VALUE; col = TEXT_BOX_VALUE; }
  202.         ChangeSelection(row, col);
  203.     }
  204.       if (nChar == VK_UP) 
  205.     {
  206.         if (row < 0) { row = m_nNumRows-1; col = 0; }
  207.         else if (row > 0) row--;
  208.         else { row = TEXT_BOX_VALUE; col = TEXT_BOX_VALUE; }
  209.         ChangeSelection(row, col);
  210.     }
  211.     if (nChar == VK_RIGHT) 
  212.     {
  213.         if (col < 0) { row = 0; col = 0; }
  214.         else if (col < m_nNumColumns-1) col++;
  215.         else col = 0;
  216.         ChangeSelection(row, col);
  217.     }
  218.     if (nChar == VK_LEFT) 
  219.     {
  220.         if (col < 0) { row = m_nNumRows-1; col = m_nNumColumns-1; }
  221.         else if (col > 0) col--;
  222.         else col = m_nNumColumns-1;
  223.         ChangeSelection(row, col);
  224.     }
  225.     if (nChar == VK_ESCAPE) 
  226.     {
  227.         m_crColour = m_crInitialColour;
  228.         EndSelection(CPN_SELENDCANCEL);
  229.         return;
  230.     }
  231.     if (nChar == VK_RETURN)
  232.     {
  233.         EndSelection(CPN_SELENDOK);
  234.         return;
  235.     }
  236.     CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  237. }
  238. // auto-deletion
  239. void CColourPopup::OnNcDestroy() 
  240. {
  241.     CWnd::OnNcDestroy();
  242.     delete this;
  243. }
  244. void CColourPopup::OnPaint() 
  245. {
  246.     CPaintDC dc(this); // device context for painting
  247.     // Draw colour cells
  248.     for (int row = 0; row < m_nNumRows; row++)
  249.         for (int col = 0; col < m_nNumColumns; col++)
  250.             DrawCell(&dc, row, col);
  251.     
  252.     // Draw custom text
  253.     if (m_bShowCustom)
  254.         DrawCell(&dc, TEXT_BOX_VALUE, TEXT_BOX_VALUE);
  255.     // Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this,
  256.     // but for some reason isn't
  257.     CRect rect;
  258.     GetClientRect(rect);
  259.     dc.DrawEdge(rect, EDGE_RAISED, BF_RECT);
  260. }
  261. void CColourPopup::OnMouseMove(UINT nFlags, CPoint point) 
  262. {
  263.     int row, col;
  264.     // Translate points to be relative raised window edge
  265.     point.x -= m_nMargin;
  266.     point.y -= m_nMargin;
  267.     // First check we aren't in text box
  268.     if (m_bShowCustom && m_TextRect.PtInRect(point))
  269.         row = col = TEXT_BOX_VALUE;        // Special value meaning Text Box (hack!)
  270.     else
  271.     {
  272.         // Take into account text box
  273.         if (m_bShowCustom) 
  274.             point.y -= m_TextRect.Height();  
  275.         // Get the row and column
  276.         row = point.y / m_nBoxSize,
  277.         col = point.x / m_nBoxSize;
  278.         // In range? If not, default and exit
  279.         if (row < 0 || row >= m_nNumRows ||
  280.             col < 0 || col >= m_nNumColumns)
  281.         {
  282.             CWnd::OnMouseMove(nFlags, point);
  283.             return;
  284.         }
  285.     }
  286.     // OK - we have the row and column of the current selection (may be TEXT_BOX_VALUE)
  287.     // Has the row/col selection changed? If yes, then redraw old and new cells.
  288.     if (row != m_nCurrentRow || col != m_nCurrentCol)
  289.     {
  290.         ChangeSelection(row, col);
  291.     }
  292.     CWnd::OnMouseMove(nFlags, point);
  293. }
  294. // End selection on LButtonUp
  295. void CColourPopup::OnLButtonUp(UINT nFlags, CPoint point) 
  296. {    
  297.     CWnd::OnLButtonUp(nFlags, point);
  298.     DWORD pos = GetMessagePos();
  299.     point = CPoint(LOWORD(pos), HIWORD(pos));
  300.     if (m_WindowRect.PtInRect(point))
  301.         EndSelection(CPN_SELENDOK);
  302.     else
  303.         EndSelection(CPN_SELENDCANCEL);
  304. }
  305. /////////////////////////////////////////////////////////////////////////////
  306. // CColourPopup implementation
  307. void CColourPopup::FindCellFromColour(COLORREF crColour)
  308. {
  309.     for (int row = 0; row < m_nNumRows; row++)
  310.         for (int col = 0; col < m_nNumColumns; col++)
  311.         {
  312.             if (GetColour(row, col) == crColour)
  313.             {
  314.                 m_nChosenColourRow  = row;
  315.                 m_nChosenColourCol  = col;
  316.                 return;
  317.             }
  318.         }
  319.     m_nChosenColourRow  = TEXT_BOX_VALUE;
  320.     m_nChosenColourCol  = TEXT_BOX_VALUE;
  321. }
  322. // Gets the dimensions of the colour cell given by (row,col)
  323. BOOL CColourPopup::GetCellRect(int row, int col, const LPRECT& rect)
  324. {
  325.     if (row < 0 || row >= m_nNumRows || col < 0 || col >= m_nNumColumns)
  326.         return FALSE;
  327.     rect->left = col*m_nBoxSize + m_nMargin;
  328.     rect->top  = row*m_nBoxSize + m_nMargin;
  329.     // Move everything down if we are displaying text
  330.     if (m_bShowCustom) 
  331.         rect->top += (m_nMargin + m_TextRect.Height());
  332.     rect->right = rect->left + m_nBoxSize;
  333.     rect->bottom = rect->top + m_nBoxSize;
  334.     return TRUE;
  335. }
  336. // Works out an appropriate size and position of this window
  337. void CColourPopup::SetWindowSize()
  338. {
  339.     CSize TextSize;
  340.     // If we are showing a custom text area, get the font and text size.
  341.     if (m_bShowCustom)
  342.     {
  343.         // Get the size of the custom text
  344.         CClientDC dc(this);
  345.         CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font);
  346.         TextSize = dc.GetTextExtent(m_strCustomText) + CSize(2*m_nMargin,2*m_nMargin);
  347.         dc.SelectObject(pOldFont);
  348.         // Add even more space to draw the horizontal line
  349.         TextSize.cy += 2*m_nMargin + 2;
  350.     }
  351.     // Get the number of columns and rows
  352.     //m_nNumColumns = (int) sqrt((double)m_nNumColours);    // for a square window (yuk)
  353.     m_nNumColumns = 8;
  354.     m_nNumRows = m_nNumColours / m_nNumColumns;
  355.     if (m_nNumColours % m_nNumColumns) m_nNumRows++;
  356.     // Get the current window position, and set the new size
  357.     CRect rect;
  358.     GetWindowRect(rect);
  359.     m_WindowRect.SetRect(rect.left, rect.top, 
  360.                          rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin,
  361.                          rect.top  + m_nNumRows*m_nBoxSize + 2*m_nMargin);
  362.     // if custom text, then expand window if necessary, and set text width as
  363.     // window width
  364.     if (m_bShowCustom) 
  365.     {
  366.         m_WindowRect.bottom += (m_nMargin + TextSize.cy);
  367.         if (TextSize.cx > m_WindowRect.Width())
  368.             m_WindowRect.right = m_WindowRect.left + TextSize.cx;
  369.         TextSize.cx = m_WindowRect.Width()-2*m_nMargin;
  370.         // Work out the text area
  371.         m_TextRect.SetRect(m_nMargin, m_nMargin, 
  372.                            m_nMargin+TextSize.cx, m_nMargin+TextSize.cy);
  373.     }
  374.     // Need to check it'll fit on screen: Too far right?
  375.     CSize ScreenSize(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN));
  376.     if (m_WindowRect.right > ScreenSize.cx)
  377.         m_WindowRect.OffsetRect(-(m_WindowRect.right - ScreenSize.cx), 0);
  378.     // Too far left?
  379.     if (m_WindowRect.left < 0)
  380.         m_WindowRect.OffsetRect( -m_WindowRect.left, 0);
  381.     // Bottom falling out of screen?
  382.     if (m_WindowRect.bottom > ScreenSize.cy)
  383.     {
  384.         CRect ParentRect;
  385.         m_pParent->GetWindowRect(ParentRect);
  386.         m_WindowRect.OffsetRect(0, -(ParentRect.Height() + m_WindowRect.Height()));
  387.     }
  388.     // Set the window size and position
  389.     MoveWindow(m_WindowRect, TRUE);
  390. }
  391. void CColourPopup::CreateToolTips()
  392. {
  393.     // Create the tool tip
  394.     if (!m_ToolTip.Create(this)) return;
  395.     // Add a tool for each cell
  396.     for (int row = 0; row < m_nNumRows; row++)
  397.         for (int col = 0; col < m_nNumColumns; col++)
  398.         {
  399.             CRect rect;
  400.             if (!GetCellRect(row, col, rect)) continue;
  401.             m_ToolTip.AddTool(this, GetColourName(row, col), rect, 1);
  402.         }
  403. }
  404. void CColourPopup::ChangeSelection(int row, int col)
  405. {
  406.     CClientDC dc(this);        // device context for drawing
  407.     if ((m_nCurrentRow >= 0 && m_nCurrentRow < m_nNumRows &&
  408.          m_nCurrentCol >= 0 && m_nCurrentCol < m_nNumColumns) ||
  409.         (m_nCurrentCol == TEXT_BOX_VALUE && m_nCurrentCol == TEXT_BOX_VALUE))
  410.     {
  411.         // Set Current selection as invalid and redraw old selection (this way
  412.         // the old selection will be drawn unselected)
  413.         int OldRow = m_nCurrentRow, OldCol = m_nCurrentCol;
  414.         m_nCurrentRow = m_nCurrentCol = -1;
  415.         DrawCell(&dc, OldRow, OldCol);
  416.     }
  417.     // Set the current selection as row/col and draw (it will be drawn selected)
  418.     m_nCurrentRow = row; m_nCurrentCol = col;
  419.     DrawCell(&dc, m_nCurrentRow, m_nCurrentCol);
  420.     // Store the current colour
  421.     if (m_nCurrentRow == TEXT_BOX_VALUE && m_nCurrentCol == TEXT_BOX_VALUE)
  422.         m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crInitialColour, 0);
  423.     else
  424.     {
  425.         m_crColour = GetColour(m_nCurrentRow, m_nCurrentCol);
  426.         m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crColour, 0);
  427.     }
  428. }
  429. void CColourPopup::EndSelection(int nMessage)
  430. {
  431.     ReleaseCapture();
  432.     // If custom text selected, perform a custom colour selection
  433.     if (nMessage != CPN_SELENDCANCEL && 
  434.         m_nCurrentCol == TEXT_BOX_VALUE && m_nCurrentRow == TEXT_BOX_VALUE)
  435.     {
  436.         CColorDialog dlg(m_crInitialColour, CC_FULLOPEN | CC_ANYCOLOR, this);
  437.         if (dlg.DoModal() == IDOK)
  438.             m_crColour = dlg.GetColor();
  439.         else
  440.             m_crColour = m_crInitialColour;
  441.    } 
  442.     if (nMessage == CPN_SELENDCANCEL)
  443.         m_crColour = m_crInitialColour;
  444.     m_pParent->SendMessage(nMessage, (WPARAM) m_crColour, 0);
  445.     
  446.     DestroyWindow();
  447. }
  448. void CColourPopup::DrawCell(CDC* pDC, int row, int col)
  449. {
  450.     // This is a special hack for the text box
  451.     if (m_bShowCustom && row == TEXT_BOX_VALUE && row == TEXT_BOX_VALUE)
  452.     {
  453.         // The extent of the actual text button
  454.          CRect TextButtonRect = m_TextRect;
  455.         TextButtonRect.bottom -= (2*m_nMargin+2);
  456.         // Fill background
  457.         //if ( (m_nChosenColourRow == row && m_nChosenColourCol == col)
  458.         //    && !(m_nCurrentRow == row && m_nCurrentCol == col) )
  459.         //    pDC->FillSolidRect(m_TextRect, ::GetSysColor(COLOR_3DHILIGHT));
  460.         //else
  461.             pDC->FillSolidRect(m_TextRect, ::GetSysColor(COLOR_3DFACE));
  462.         // Draw button
  463.         //if (m_nChosenColourRow == row && m_nChosenColourCol == col)
  464.         //    pDC->DrawEdge(TextButtonRect, EDGE_SUNKEN, BF_RECT);
  465.         //else 
  466.         if (m_nCurrentRow == row && m_nCurrentCol == col) 
  467.             pDC->DrawEdge(TextButtonRect, EDGE_RAISED, BF_RECT);
  468.         // Draw custom text
  469.         CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font);
  470.         pDC->DrawText(m_strCustomText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  471.         pDC->SelectObject(pOldFont);
  472.         // Draw horizontal line
  473.         pDC->FillSolidRect(m_TextRect.left+2*m_nMargin, m_TextRect.bottom-m_nMargin-2,
  474.                            m_TextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DSHADOW));
  475.         pDC->FillSolidRect(m_TextRect.left+2*m_nMargin, m_TextRect.bottom-m_nMargin-1,
  476.                            m_TextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DHILIGHT));
  477.         return;
  478.     }        
  479.     // row/col in range?
  480.     ASSERT(row >= 0 && row < m_nNumRows);
  481.     ASSERT(col >= 0 && col < m_nNumColumns);
  482.     // Select and realize the palette
  483.     CPalette* pOldPalette;
  484.     if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
  485.     {
  486.         pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
  487.         pDC->RealizePalette();
  488.     }
  489.     CRect rect;
  490.     if (!GetCellRect(row, col, rect)) return;
  491.     // fill background
  492.     if ( (m_nChosenColourRow == row && m_nChosenColourCol == col)
  493.         && !(m_nCurrentRow == row && m_nCurrentCol == col) )
  494.         pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DHILIGHT));
  495.     else
  496.         pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
  497.     // Draw button
  498.     if (m_nChosenColourRow == row && m_nChosenColourCol == col)
  499.         pDC->DrawEdge(rect, EDGE_SUNKEN, BF_RECT);
  500.     else if (m_nCurrentRow == row && m_nCurrentCol == col) 
  501.         pDC->DrawEdge(rect, EDGE_RAISED, BF_RECT);
  502.     // Draw raised edge if selected
  503.     if (m_nCurrentRow == row && m_nCurrentCol == col)
  504.         pDC->DrawEdge(rect, EDGE_RAISED, BF_RECT);
  505.     CBrush brush(PALETTERGB(GetRValue(GetColour(row, col)), 
  506.                             GetGValue(GetColour(row, col)), 
  507.                             GetBValue(GetColour(row, col)) ));
  508.     CPen   pen;
  509.     pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
  510.     CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush);
  511.     CPen*   pOldPen   = (CPen*)   pDC->SelectObject(&pen);
  512.     // Draw the cell colour
  513.     rect.DeflateRect(m_nMargin+1, m_nMargin+1);
  514.     pDC->Rectangle(rect);
  515.     // restore DC and cleanup
  516.     pDC->SelectObject(pOldBrush);
  517.     pDC->SelectObject(pOldPen);
  518.     brush.DeleteObject();
  519.     pen.DeleteObject();
  520.     if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
  521.         pDC->SelectPalette(pOldPalette, FALSE);
  522. }
  523. BOOL CColourPopup::OnQueryNewPalette() 
  524. {
  525.     Invalidate();    
  526.     return CWnd::OnQueryNewPalette();
  527. }
  528. void CColourPopup::OnPaletteChanged(CWnd* pFocusWnd) 
  529. {
  530.     CWnd::OnPaletteChanged(pFocusWnd);
  531.     if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd())
  532.         Invalidate();
  533. }