ColourPopup.cpp 29 KB

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