Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1079 lines
30 KiB

  1. /*****************************************************************************\
  2. FILE: ColorCtrl.cpp
  3. DESCRIPTION:
  4. This code will display a ColorPicking control. It will preview a color
  5. and have a drop down arrow. When dropped down, it will show 16 or so common
  6. colors with a "Other..." option for a full color picker.
  7. BryanSt 7/25/2000 Converted from the Display Control Panel.
  8. Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
  9. \*****************************************************************************/
  10. #include "stdafx.h"
  11. #include "utils.h"
  12. #include "ColorCtrl.h"
  13. #include "uxtheme.h"
  14. #include "tmschema.h"
  15. #pragma hdrstop
  16. //============================================================================================================
  17. // *** Globals ***
  18. //============================================================================================================
  19. #define WM_USER_STARTCAPTURE_COLORPICKER (WM_APP+1)
  20. #define CPI_VGAONLY 0x0001
  21. #define CPI_PALETTEOK 0x0002
  22. typedef struct {
  23. HWND hwndParent; // parent for any modal dialogs (choosecolor et al)
  24. HWND hwndOwner; // control that owns mini color picker
  25. COLORREF rgb;
  26. UINT flags;
  27. HPALETTE hpal;
  28. } COLORPICK_INFO, FAR * LPCOLORPICK_INFO;
  29. #define ZERO_DIV_PROTECT(number) (((number) == 0) ? 1 : (number))
  30. // Macro to replace MAKEPOINT() since points now have 32 bit x & y
  31. #define LPARAM2POINT( lp, ppt ) ((ppt)->x = (int)(short)LOWORD(lp), (ppt)->y = (int)(short)HIWORD(lp))
  32. //===========================
  33. // *** Class Internals & Helpers ***
  34. //===========================
  35. /////////////////////////////////////////////////////////////////////
  36. // Palette Helpers
  37. /////////////////////////////////////////////////////////////////////
  38. COLORREF GetNearestPaletteColor(HPALETTE hpal, COLORREF rgb)
  39. {
  40. PALETTEENTRY pe;
  41. GetPaletteEntries(hpal, GetNearestPaletteIndex(hpal, rgb & 0x00FFFFFF), 1, &pe);
  42. return RGB(pe.peRed, pe.peGreen, pe.peBlue);
  43. }
  44. BOOL IsPaletteColor(HPALETTE hpal, COLORREF rgb)
  45. {
  46. return GetNearestPaletteColor(hpal, rgb) == (rgb & 0xFFFFFF);
  47. }
  48. HRESULT CColorControl::_InitColorAndPalette(void)
  49. {
  50. HDC hdc = GetDC(NULL);
  51. m_fPalette = FALSE;
  52. if (hdc)
  53. {
  54. m_fPalette = GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE;
  55. ReleaseDC(NULL, hdc);
  56. }
  57. // always make a palette even on non-pal device
  58. DWORD pal[21];
  59. HPALETTE hpal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
  60. pal[1] = RGB(255, 255, 255);
  61. pal[2] = RGB(0, 0, 0 );
  62. pal[3] = RGB(192, 192, 192);
  63. pal[4] = RGB(128, 128, 128);
  64. pal[5] = RGB(255, 0, 0 );
  65. pal[6] = RGB(128, 0, 0 );
  66. pal[7] = RGB(255, 255, 0 );
  67. pal[8] = RGB(128, 128, 0 );
  68. pal[9] = RGB(0 , 255, 0 );
  69. pal[10] = RGB(0 , 128, 0 );
  70. pal[11] = RGB(0 , 255, 255);
  71. pal[12] = RGB(0 , 128, 128);
  72. pal[13] = RGB(0 , 0, 255);
  73. pal[14] = RGB(0 , 0, 128);
  74. pal[15] = RGB(255, 0, 255);
  75. pal[16] = RGB(128, 0, 128);
  76. GetPaletteEntries(hpal, 11, 1, (LPPALETTEENTRY)&pal[17]);
  77. pal[0] = MAKELONG(0x300, 17);
  78. m_hpalVGA = CreatePalette((LPLOGPALETTE)pal);
  79. // get magic colors
  80. GetPaletteEntries(hpal, 8, 4, (LPPALETTEENTRY)&pal[17]);
  81. pal[0] = MAKELONG(0x300, 20);
  82. m_hpal3D = CreatePalette((LPLOGPALETTE)pal);
  83. return S_OK;
  84. }
  85. #define RGB_PALETTE 0x02000000
  86. // make the color a solid color if it needs to be.
  87. // on a palette device make is a palette relative color, if we need to.
  88. COLORREF CColorControl::_NearestColor(COLORREF rgb)
  89. {
  90. rgb &= 0x00FFFFFF;
  91. // if we are on a palette device, we need to do special stuff...
  92. if (m_fPalette)
  93. {
  94. if (IsPaletteColor(m_hpal3D, rgb))
  95. rgb |= RGB_PALETTE;
  96. else if (IsPaletteColor((HPALETTE)GetStockObject(DEFAULT_PALETTE), rgb))
  97. rgb ^= 0x000001; // force a dither
  98. }
  99. return rgb;
  100. }
  101. HRESULT CColorControl::_SaveCustomColors(void)
  102. {
  103. HRESULT hr = E_FAIL;
  104. HKEY hkAppear;
  105. // save out possible changes to custom color table
  106. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_APPEARANCE, 0, KEY_WRITE, &hkAppear) == ERROR_SUCCESS)
  107. {
  108. DWORD dwError = RegSetValueEx(hkAppear, REGSTR_VAL_CUSTOMCOLORS, 0L, REG_BINARY, (LPBYTE)m_rbgCustomColors, sizeof(m_rbgCustomColors));
  109. hr = HRESULT_FROM_WIN32(dwError);
  110. RegCloseKey(hkAppear);
  111. }
  112. return hr;
  113. }
  114. void CColorControl::_DrawDownArrow(HDC hdc, LPRECT lprc, BOOL bDisabled)
  115. {
  116. HBRUSH hbr;
  117. int x, y;
  118. x = lprc->right - m_cxEdgeSM - 5;
  119. y = lprc->top + ((lprc->bottom - lprc->top)/2 - 1);
  120. if (bDisabled)
  121. {
  122. hbr = GetSysColorBrush(COLOR_3DHILIGHT);
  123. hbr = (HBRUSH) SelectObject(hdc, hbr);
  124. x++;
  125. y++;
  126. PatBlt(hdc, x, y, 5, 1, PATCOPY);
  127. PatBlt(hdc, x+1, y+1, 3, 1, PATCOPY);
  128. PatBlt(hdc, x+2, y+2, 1, 1, PATCOPY);
  129. SelectObject(hdc, hbr);
  130. x--;
  131. y--;
  132. }
  133. hbr = GetSysColorBrush(bDisabled ? COLOR_3DSHADOW : COLOR_BTNTEXT);
  134. hbr = (HBRUSH) SelectObject(hdc, hbr);
  135. PatBlt(hdc, x, y, 5, 1, PATCOPY);
  136. PatBlt(hdc, x+1, y+1, 3, 1, PATCOPY);
  137. PatBlt(hdc, x+2, y+2, 1, 1, PATCOPY);
  138. SelectObject(hdc, hbr);
  139. lprc->right = x;
  140. }
  141. BOOL CColorControl::_UseColorPicker(void)
  142. {
  143. CHOOSECOLOR cc = {0};
  144. cc.lStructSize = sizeof(cc);
  145. cc.hwndOwner = m_hwndParent;
  146. cc.hInstance = NULL;
  147. cc.rgbResult = m_rbgColorTemp;
  148. cc.lpCustColors = m_rbgCustomColors;
  149. cc.Flags = CC_RGBINIT | m_dwFlags;
  150. cc.lCustData = 0L;
  151. cc.lpfnHook = NULL;
  152. cc.lpTemplateName = NULL;
  153. if (ChooseColor(&cc))
  154. {
  155. SetColor(cc.rgbResult); // Replace m_rbgColor with our new color.
  156. return TRUE;
  157. }
  158. return FALSE;
  159. }
  160. void CColorControl::_DrawColorSquare(HDC hdc, int iColor)
  161. {
  162. RECT rc;
  163. COLORREF rgb;
  164. HPALETTE hpalOld = NULL;
  165. HBRUSH hbr;
  166. // custom color
  167. if (iColor == m_iNumColors)
  168. {
  169. rc.left = 0;
  170. rc.top = 0;
  171. rgb = m_rbgColorTemp;
  172. }
  173. else
  174. {
  175. rc.left = (iColor % NUM_COLORSPERROW) * m_dxColor;
  176. rc.top = (iColor / NUM_COLORSPERROW) * m_dyColor;
  177. rgb = m_rbgColors[iColor];
  178. }
  179. rc.right = rc.left + m_dxColor;
  180. rc.bottom = rc.top + m_dyColor;
  181. // focused one
  182. if (iColor == m_nCurColor)
  183. {
  184. PatBlt(hdc, rc.left, rc.top, m_dxColor, 3, BLACKNESS);
  185. PatBlt(hdc, rc.left, rc.bottom - 3, m_dxColor, 3, BLACKNESS);
  186. PatBlt(hdc, rc.left, rc.top + 3, 3, m_dyColor - 6, BLACKNESS);
  187. PatBlt(hdc, rc.right - 3, rc.top + 3, 3, m_dyColor - 6, BLACKNESS);
  188. InflateRect(&rc, -1, -1);
  189. HBRUSH hBrushWhite = (HBRUSH) GetStockObject(WHITE_BRUSH);
  190. if (hBrushWhite)
  191. {
  192. FrameRect(hdc, &rc, hBrushWhite);
  193. }
  194. InflateRect(&rc, -2, -2);
  195. }
  196. else
  197. {
  198. // clean up possible focus thing from above
  199. FrameRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
  200. InflateRect(&rc, -m_cxEdgeSM, -m_cyEdgeSM);
  201. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  202. }
  203. if ((m_dwFlags & CC_SOLIDCOLOR) && !(rgb & 0xFF000000))
  204. rgb = GetNearestColor(hdc, rgb);
  205. hbr = CreateSolidBrush(rgb);
  206. if (m_hpal3D)
  207. {
  208. hpalOld = SelectPalette(hdc, m_hpal3D, FALSE);
  209. RealizePalette(hdc);
  210. }
  211. hbr = (HBRUSH) SelectObject(hdc, hbr);
  212. PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
  213. hbr = (HBRUSH) SelectObject(hdc, hbr);
  214. if (hpalOld)
  215. {
  216. hpalOld = SelectPalette(hdc, hpalOld, TRUE);
  217. RealizePalette(hdc);
  218. }
  219. if (hbr)
  220. {
  221. DeleteObject(hbr);
  222. }
  223. }
  224. // set the focus to the given color.
  225. // in the process, also take the focus off of the old focus color.
  226. void CColorControl::_FocusColor(HWND hDlg, int iNewColor)
  227. {
  228. int i;
  229. HDC hdc = NULL;
  230. HWND hwnd;
  231. if (iNewColor == m_nCurColor)
  232. return;
  233. i = m_nCurColor;
  234. m_nCurColor = iNewColor;
  235. // unfocus the old one
  236. if (i >= 0)
  237. {
  238. if (i == m_iNumColors)
  239. hwnd = GetDlgItem(hDlg, IDC_CPDLG_COLORCUST);
  240. else
  241. hwnd = GetDlgItem(hDlg, IDC_CPDLG_16COLORS);
  242. hdc = GetDC(hwnd);
  243. if (hdc)
  244. {
  245. _DrawColorSquare(hdc, i);
  246. ReleaseDC(hwnd, hdc);
  247. }
  248. }
  249. // focus the new one
  250. if (iNewColor >= 0)
  251. {
  252. if (iNewColor == m_iNumColors)
  253. hwnd = GetDlgItem(hDlg, IDC_CPDLG_COLORCUST);
  254. else
  255. hwnd = GetDlgItem(hDlg, IDC_CPDLG_16COLORS);
  256. hdc = GetDC(hwnd);
  257. if (hdc)
  258. {
  259. _DrawColorSquare(hdc, iNewColor);
  260. ReleaseDC(hwnd, hdc);
  261. }
  262. }
  263. }
  264. void CColorControl::_TrackMouse(HWND hDlg, POINT pt)
  265. {
  266. HWND hwndKid;
  267. int id;
  268. hwndKid = ChildWindowFromPoint(hDlg, pt);
  269. if (hwndKid == NULL || hwndKid == hDlg)
  270. return;
  271. id = GetWindowLong(hwndKid, GWL_ID);
  272. switch (id)
  273. {
  274. case IDC_CPDLG_16COLORS:
  275. MapWindowPoints(hDlg, GetDlgItem(hDlg, IDC_CPDLG_16COLORS), &pt, 1);
  276. pt.x /= ZERO_DIV_PROTECT(m_dxColor);
  277. pt.y /= ZERO_DIV_PROTECT(m_dyColor);
  278. _FocusColor(hDlg, pt.x + (pt.y * NUM_COLORSPERROW));
  279. break;
  280. case IDC_CPDLG_COLORCUST:
  281. if (IsWindowVisible(hwndKid))
  282. _FocusColor(hDlg, m_iNumColors);
  283. break;
  284. case IDC_CPDLG_COLOROTHER:
  285. _FocusColor(hDlg, -1);
  286. break;
  287. }
  288. }
  289. void CColorControl::_DrawItem(HWND hDlg, LPDRAWITEMSTRUCT lpdis)
  290. {
  291. int i;
  292. if (lpdis->CtlID == IDC_CPDLG_COLORCUST)
  293. {
  294. _DrawColorSquare(lpdis->hDC, m_iNumColors);
  295. }
  296. else
  297. {
  298. for (i = 0; i < m_iNumColors; i++)
  299. {
  300. _DrawColorSquare(lpdis->hDC, i);
  301. }
  302. }
  303. }
  304. /*
  305. ** init the mini-color-picker
  306. **
  307. ** the dialog is pretending to be a menu, so figure out where to pop
  308. ** it up so that it is visible all around.
  309. **
  310. ** also because this dialog is pretty darn concerned with its look,
  311. ** hand-align the components in pixel units. THIS IS GROSS!
  312. */
  313. void CColorControl::_InitDialog(HWND hDlg)
  314. {
  315. RECT rcOwner;
  316. RECT rc, rc2;
  317. int dx, dy;
  318. int x, y;
  319. int i;
  320. HWND hwndColors, hwnd;
  321. HWND hwndEtch, hwndCust;
  322. int width, widthCust, widthEtch;
  323. HPALETTE hpal = m_hpal3D;
  324. MONITORINFO mi;
  325. TCHAR szBuf[50];
  326. LONG cbBuf = ARRAYSIZE(szBuf);
  327. HDC hDC;
  328. SIZE size;
  329. m_fCapturing = FALSE;
  330. m_fJustDropped = TRUE;
  331. if (hpal == NULL)
  332. hpal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
  333. m_iNumColors = 0;
  334. GetObject(hpal, sizeof(int), &m_iNumColors);
  335. if (m_iNumColors > NUM_COLORSMAX)
  336. m_iNumColors = NUM_COLORSMAX;
  337. GetPaletteEntries(hpal,0, m_iNumColors, (LPPALETTEENTRY)m_rbgColors);
  338. for (i = 0; i < m_iNumColors; i++)
  339. {
  340. m_rbgColors[i] &= 0x00FFFFFF;
  341. m_rbgColors[i] |= 0x02000000;
  342. }
  343. for (i = 0; i < m_iNumColors; i++)
  344. {
  345. if ((m_rbgColors[i] & 0x00FFFFFF) == (m_rbgColorTemp & 0x00FFFFFF))
  346. {
  347. ShowWindow(GetDlgItem(hDlg, IDC_CPDLG_COLORCUST), SW_HIDE);
  348. break;
  349. }
  350. }
  351. // current is either one of 16 or the custom color (== m_iNumColors
  352. m_nCurColor = i;
  353. // size the 16 colors to be square
  354. hwndColors = GetDlgItem(hDlg, IDC_CPDLG_16COLORS);
  355. GetClientRect(hwndColors, &rc);
  356. // To make localization easy..
  357. //
  358. hwndEtch=GetDlgItem(hDlg, IDC_CPDLG_COLORETCH);
  359. GetClientRect(hwndEtch, &rc2);
  360. widthEtch = rc2.right-rc2.left;
  361. hwndCust=GetDlgItem(hDlg, IDC_CPDLG_COLORCUST);
  362. GetClientRect(hwndCust, &rc2);
  363. widthCust = rc2.right-rc2.left;
  364. hwnd = GetDlgItem(hDlg, IDC_CPDLG_COLOROTHER);
  365. GetWindowRect(hwnd, &rc2); // we must initialize rc2 with this control.
  366. // Make sure the button is big enough to contain its text
  367. width = rc.right - rc.left;
  368. if( GetDlgItemText( hDlg, IDC_CPDLG_COLOROTHER, szBuf, cbBuf ) )
  369. {
  370. RECT rcTemp;
  371. int iRet;
  372. HFONT hfont, hfontOld;
  373. // Get the font for the button
  374. hDC = GetDC(hwnd);
  375. if (hDC)
  376. {
  377. hfont = (HFONT)SendMessage( hwnd, WM_GETFONT, 0, 0 );
  378. ASSERT(hfont);
  379. hfontOld = (HFONT) SelectObject( hDC, hfont );
  380. // Get the size of the text
  381. iRet = DrawTextEx( hDC, szBuf, lstrlen(szBuf), &rcTemp, DT_CALCRECT | DT_SINGLELINE, NULL );
  382. ASSERT( iRet );
  383. size.cx = rcTemp.right - rcTemp.left + 7; //account for the button border
  384. size.cy = rcTemp.bottom - rcTemp.top;
  385. // Adjust the button size if the text needs more space
  386. if( size.cx > width )
  387. {
  388. rc2.right = rc2.left + size.cx;
  389. rc2.bottom = rc2.top + size.cy;
  390. MoveWindow( hwnd, rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top, FALSE );
  391. }
  392. SelectObject( hDC, hfontOld );
  393. ReleaseDC( hwnd, hDC );
  394. }
  395. }
  396. // Take possible biggest width to calculate sels
  397. //
  398. width = (widthEtch > widthCust+(rc2.right-rc2.left)) ? widthEtch : widthCust+(rc2.right-rc2.left);
  399. width = (width > rc.right-rc.left) ? width: rc.right-rc.left;
  400. #define NUM_COLORSPERCOL (m_iNumColors / NUM_COLORSPERROW)
  401. m_dxColor = m_dyColor
  402. = ((rc.bottom - rc.top) / NUM_COLORSPERCOL > width / NUM_COLORSPERROW )
  403. ? (rc.bottom - rc.top) / NUM_COLORSPERCOL : width / NUM_COLORSPERROW;
  404. // Make sure custum color can fit
  405. //
  406. if (m_dxColor*(NUM_COLORSPERROW-1) < rc2.right-rc2.left )
  407. {
  408. m_dxColor = m_dyColor = (rc2.right-rc2.left)/(NUM_COLORSPERROW-1);
  409. }
  410. // make each color square's width the same as the height
  411. SetWindowPos(hwndColors, NULL, 0, 0, m_dxColor * NUM_COLORSPERROW,
  412. m_dyColor * NUM_COLORSPERCOL,
  413. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW);
  414. rc.right = rc.left + m_dxColor * NUM_COLORSPERROW;
  415. rc.bottom = rc.top + m_dyColor * NUM_COLORSPERCOL;
  416. MapWindowPoints(hwndColors, hDlg, (LPPOINT)(LPRECT)&rc, 2);
  417. // move/size the etch to the right place
  418. // (compensate for the colors being "inset" by one)
  419. MoveWindow(hwndEtch, rc.left + 1, rc.bottom + m_cyEdgeSM, rc.right - rc.left - 2, m_cyEdgeSM, FALSE);
  420. y = rc.bottom + 3 * m_cyEdgeSM;
  421. // size the custom color to the same square and right-align
  422. MoveWindow(hwndCust, rc.right - m_dxColor, y, m_dxColor, m_dyColor, FALSE);
  423. // do same for button
  424. MapWindowPoints(NULL, hDlg, (LPPOINT)(LPRECT)&rc2, 2);
  425. // base the width of the custom button on the remaining space to
  426. // the left of the custom color. Also move the custom button one pix right
  427. // of the left edge. This only is done if a custom color is selected...
  428. if (m_nCurColor != m_iNumColors)
  429. {
  430. // no custom color
  431. MoveWindow(hwnd, rc2.left, y, rc2.right-rc2.left, m_dyColor, FALSE);
  432. }
  433. else
  434. {
  435. // custom color, adjust the Other... button
  436. dx = rc2.right - rc2.left++;
  437. if (rc2.left + dx >= rc.right - m_dxColor - 2)
  438. MoveWindow(hwnd, rc2.left, y, rc.right - m_dxColor - 2 , m_dyColor, FALSE);
  439. else
  440. MoveWindow(hwnd, rc2.left, y, dx, m_dyColor, FALSE);
  441. }
  442. // now figure out the size for the dialog itself
  443. rc.left = rc.top = 0;
  444. rc.right = rc.left + m_dxColor * NUM_COLORSPERROW;
  445. // (compensate for the colors being "inset" by one)
  446. rc.bottom = y + m_dyColor + 1;
  447. AdjustWindowRect(&rc, GetWindowLong(hDlg, GWL_STYLE), FALSE);
  448. dx = rc.right - rc.left;
  449. dy = rc.bottom - rc.top;
  450. GetWindowRect(_hwnd, &rcOwner);
  451. // Make sure the window is entirely on the monitor
  452. mi.cbSize = sizeof(mi);
  453. GetMonitorInfo(MonitorFromRect(&rcOwner, MONITOR_DEFAULTTONEAREST), &mi);
  454. if (rcOwner.left < mi.rcMonitor.left)
  455. { // overlap left side
  456. x = mi.rcMonitor.left;
  457. }
  458. else if (rcOwner.left + dx >= mi.rcMonitor.right)
  459. { // overlap right side
  460. x = mi.rcMonitor.right - dx - 1;
  461. }
  462. else
  463. { // no overlap
  464. x = rcOwner.left;
  465. }
  466. if (rcOwner.top < mi.rcMonitor.top)
  467. { // overlap top side
  468. y = rcOwner.bottom;
  469. }
  470. else if (rcOwner.bottom + dy >= mi.rcMonitor.bottom)
  471. {// overlap bottom side
  472. y = rcOwner.top - dy;
  473. }
  474. else
  475. { // no overlap
  476. y = rcOwner.bottom;
  477. }
  478. MoveWindow(hDlg, x, y, dx, dy, FALSE);
  479. SetFocus(GetDlgItem(hDlg, IDC_CPDLG_16COLORS));
  480. // post self a message to setcapture after painting
  481. PostMessage(hDlg, WM_USER_STARTCAPTURE_COLORPICKER, 0, 0L);
  482. }
  483. INT_PTR CALLBACK CColorControl::ColorPickDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  484. {
  485. CColorControl * pThis = (CColorControl *)GetWindowLongPtr(hDlg, DWLP_USER);
  486. if (WM_INITDIALOG == wMsg)
  487. {
  488. pThis = (CColorControl *) lParam;
  489. if (pThis)
  490. {
  491. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  492. }
  493. }
  494. if (pThis)
  495. return pThis->_ColorPickDlgProc(hDlg, wMsg, wParam, lParam);
  496. return DefWindowProc(hDlg, wMsg, wParam, lParam);
  497. }
  498. INT_PTR CColorControl::_ColorPickDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  499. {
  500. HWND hwndKid;
  501. int wRet;
  502. int id;
  503. POINT pt;
  504. BOOL fEnd = FALSE;
  505. switch(message)
  506. {
  507. case WM_INITDIALOG:
  508. _InitDialog(hDlg);
  509. return FALSE;
  510. case WM_USER_STARTCAPTURE_COLORPICKER:
  511. if (m_fCursorHidden)
  512. {
  513. ShowCursor(TRUE);
  514. m_fCursorHidden = FALSE;
  515. }
  516. SetCursor(LoadCursor(NULL, IDC_ARROW));
  517. m_fCapturing = TRUE;
  518. SetCapture(hDlg);
  519. m_fCapturing = FALSE;
  520. break;
  521. case WM_DESTROY:
  522. break;
  523. case WM_CAPTURECHANGED:
  524. if (m_fCapturing)
  525. return TRUE; // ignore if we're doing this on purpose
  526. // if this wasn't a button in the dialog, dismiss ourselves
  527. if (!m_fJustDropped || (HWND)lParam == NULL || GetParent((HWND)lParam) != hDlg)
  528. {
  529. EndDialog(hDlg, IDCANCEL);
  530. return TRUE;
  531. }
  532. break;
  533. case WM_MOUSEMOVE:
  534. LPARAM2POINT(lParam, &pt );
  535. _TrackMouse(hDlg, pt);
  536. break;
  537. // if button up is on the parent, leave picker up and untrammeled.
  538. // otherwise, we must have "menu-tracked" to get here, so select.
  539. case WM_LBUTTONUP:
  540. case WM_RBUTTONUP:
  541. LPARAM2POINT(lParam, &pt);
  542. MapWindowPoints(hDlg, _hwnd, &pt, 1);
  543. if (ChildWindowFromPoint(_hwnd, pt))
  544. return 0;
  545. m_fCapturing = TRUE;
  546. m_fJustDropped = FALSE; // user could not be dragging from owner
  547. ReleaseCapture();
  548. m_fCapturing = FALSE;
  549. fEnd = TRUE;
  550. // || fall ||
  551. // || through ||
  552. // \/ \/
  553. case WM_LBUTTONDOWN:
  554. case WM_RBUTTONDOWN:
  555. LPARAM2POINT(lParam, &pt);
  556. hwndKid = ChildWindowFromPoint(hDlg, pt);
  557. // assume it's a dismissal if we're going to close...
  558. wRet = IDCANCEL;
  559. // if not on parent, dismiss picker
  560. if (hwndKid != NULL && hwndKid != hDlg)
  561. {
  562. id = GetWindowLong(hwndKid, GWL_ID);
  563. switch (id)
  564. {
  565. case IDC_CPDLG_16COLORS:
  566. // make sure that iCurColor is valid
  567. _TrackMouse(hDlg, pt);
  568. m_rbgColorTemp = m_rbgColors[m_nCurColor] & 0x00FFFFFF;
  569. wRet = IDOK;
  570. break;
  571. case IDC_CPDLG_COLOROTHER:
  572. _FocusColor(hDlg, -1);
  573. wRet = id; // this will fall thru to use the picker
  574. fEnd = TRUE; // we have capture, the button won't click
  575. break;
  576. default:
  577. // if this is a down, we will track until the up
  578. // if this is an up, we will close with no change
  579. break;
  580. }
  581. }
  582. if( fEnd )
  583. {
  584. EndDialog(hDlg, wRet);
  585. return TRUE;
  586. }
  587. // make sure we have the capture again since we didn't close
  588. m_fCapturing = TRUE;
  589. SetCapture(hDlg);
  590. m_fCapturing = FALSE;
  591. break;
  592. case WM_DRAWITEM:
  593. _DrawItem(hDlg, (LPDRAWITEMSTRUCT)lParam);
  594. break;
  595. case WM_COMMAND:
  596. // all commands close the dialog
  597. // note IDC_CPDLG_COLOROTHER will fall through to the caller...
  598. // cannot pass ok with no color selected
  599. if ((LOWORD(wParam) == IDOK) && (m_nCurColor < 0))
  600. {
  601. *((WORD *)(&wParam)) = IDCANCEL;
  602. }
  603. EndDialog(hDlg, LOWORD(wParam));
  604. break;
  605. }
  606. return FALSE;
  607. }
  608. BOOL CColorControl::_ChooseColorMini(void)
  609. {
  610. ShowCursor(FALSE);
  611. m_fCursorHidden = TRUE;
  612. m_hwndParent = GetParent(GetParent(_hwnd)); // Property Sheet
  613. m_rbgColorTemp = m_rbgColor;
  614. INT_PTR iAnswer = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(IDD_COLORPICK), _hwnd, ColorPickDlgProc, (LPARAM)this);
  615. if (m_fCursorHidden)
  616. {
  617. ShowCursor(TRUE);
  618. m_fCursorHidden = FALSE;
  619. }
  620. switch (iAnswer)
  621. {
  622. case IDC_CPDLG_COLOROTHER: // the user picked the "Other..." button
  623. return _UseColorPicker();
  624. case IDOK: // the user picked a color in our little window
  625. SetColor(m_rbgColorTemp);
  626. return TRUE;
  627. default:
  628. break;
  629. }
  630. return FALSE;
  631. }
  632. //===========================
  633. // *** IColorControl Interface ***
  634. //===========================
  635. HRESULT CColorControl::Initialize(IN HWND hwnd, IN COLORREF rgbColor)
  636. {
  637. HRESULT hr = E_INVALIDARG;
  638. if (hwnd)
  639. {
  640. _hwnd = hwnd;
  641. hr = SetColor(rgbColor);
  642. }
  643. return hr;
  644. }
  645. HRESULT CColorControl::GetColor(IN COLORREF * pColor)
  646. {
  647. HRESULT hr = E_INVALIDARG;
  648. if (pColor)
  649. {
  650. *pColor = m_rbgColor;
  651. hr = S_OK;
  652. }
  653. return hr;
  654. }
  655. HRESULT CColorControl::SetColor(IN COLORREF rgbColor)
  656. {
  657. m_rbgColor = rgbColor;
  658. if (_hwnd)
  659. {
  660. if (m_brColor)
  661. {
  662. DeleteObject(m_brColor);
  663. }
  664. m_brColor = CreateSolidBrush(_NearestColor(rgbColor));
  665. m_rbgColorTemp = m_rbgColor;
  666. InvalidateRect(_hwnd, NULL, FALSE);
  667. UpdateWindow(_hwnd);
  668. }
  669. return S_OK;
  670. }
  671. HRESULT CColorControl::OnCommand(IN HWND hDlg, IN UINT message, IN WPARAM wParam, IN LPARAM lParam)
  672. {
  673. HRESULT hr = S_OK;
  674. WORD wEvent = GET_WM_COMMAND_CMD(wParam, lParam);
  675. if (wEvent == BN_CLICKED)
  676. {
  677. m_dwFlags = CC_RGBINIT | CC_FULLOPEN;
  678. _ChooseColorMini();
  679. }
  680. return S_OK;
  681. }
  682. HRESULT CColorControl::OnDrawItem(IN HWND hDlg, IN UINT message, IN WPARAM wParam, IN LPARAM lParam)
  683. {
  684. HRESULT hr = S_OK;
  685. LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
  686. if (lpdis && m_brColor)
  687. {
  688. SIZE thin = { m_cxEdgeSM / 2, m_cyEdgeSM / 2 };
  689. RECT rc = lpdis->rcItem;
  690. HDC hdc = lpdis->hDC;
  691. BOOL bFocus = ((lpdis->itemState & ODS_FOCUS) && !(lpdis->itemState & ODS_DISABLED));
  692. if (!thin.cx) thin.cx = 1;
  693. if (!thin.cy) thin.cy = 1;
  694. if (!m_hTheme)
  695. {
  696. if (lpdis->itemState & ODS_SELECTED)
  697. {
  698. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  699. OffsetRect(&rc, 1, 1);
  700. }
  701. else
  702. {
  703. DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_ADJUST);
  704. }
  705. FillRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
  706. }
  707. else
  708. {
  709. int iStateId;
  710. if (lpdis->itemState & ODS_SELECTED)
  711. {
  712. iStateId = PBS_PRESSED;
  713. }
  714. else if (lpdis->itemState & ODS_HOTLIGHT)
  715. {
  716. iStateId = PBS_HOT;
  717. }
  718. else if (lpdis->itemState & ODS_DISABLED)
  719. {
  720. iStateId = PBS_DISABLED;
  721. }
  722. else if (lpdis->itemState & ODS_FOCUS)
  723. {
  724. iStateId = PBS_DEFAULTED;
  725. }
  726. else
  727. {
  728. iStateId = PBS_NORMAL;
  729. }
  730. DrawThemeBackground(m_hTheme, hdc, BP_PUSHBUTTON, iStateId, &rc, 0);
  731. GetThemeBackgroundContentRect(m_hTheme, hdc, BP_PUSHBUTTON, iStateId, &rc, &rc);
  732. }
  733. if (bFocus)
  734. {
  735. InflateRect(&rc, -thin.cx, -thin.cy);
  736. DrawFocusRect(hdc, &rc);
  737. InflateRect(&rc, thin.cx, thin.cy);
  738. }
  739. InflateRect(&rc, 1-thin.cx, -m_cyEdgeSM);
  740. rc.left += m_cxEdgeSM;
  741. _DrawDownArrow(hdc, &rc, lpdis->itemState & ODS_DISABLED);
  742. InflateRect(&rc, -thin.cx, 0);
  743. DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RIGHT);
  744. rc.right -= ( 2 * m_cxEdgeSM ) + thin.cx;
  745. // color sample
  746. if ( !(lpdis->itemState & ODS_DISABLED) )
  747. {
  748. HPALETTE hpalOld = NULL;
  749. FrameRect(hdc, &rc, GetSysColorBrush(COLOR_BTNTEXT));
  750. InflateRect(&rc, -thin.cx, -thin.cy);
  751. if (m_hpal3D)
  752. {
  753. hpalOld = SelectPalette(hdc, m_hpal3D, FALSE);
  754. RealizePalette(hdc);
  755. }
  756. if (m_brColor)
  757. {
  758. HBRUSH brOldBrush = (HBRUSH) SelectObject(hdc, m_brColor);
  759. PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
  760. SelectObject(hdc, brOldBrush);
  761. }
  762. if (hpalOld)
  763. {
  764. SelectPalette(hdc, hpalOld, TRUE);
  765. RealizePalette(hdc);
  766. }
  767. }
  768. }
  769. return hr;
  770. }
  771. HRESULT CColorControl::ChangeTheme(IN HWND hDlg)
  772. {
  773. if (m_hTheme)
  774. {
  775. CloseThemeData(m_hTheme);
  776. }
  777. m_hTheme = OpenThemeData(GetDlgItem(hDlg, IDC_BACK_COLORPICKER), WC_BUTTON);
  778. return S_OK;
  779. }
  780. //===========================
  781. // *** IUnknown Interface ***
  782. //===========================
  783. ULONG CColorControl::AddRef()
  784. {
  785. m_cRef++;
  786. return m_cRef;
  787. }
  788. ULONG CColorControl::Release()
  789. {
  790. ASSERT(m_cRef > 0);
  791. m_cRef--;
  792. if (m_cRef > 0)
  793. return m_cRef;
  794. // We do this because we want to make this class a member variable of another class.
  795. // We should move this file to comctl32 and make it a real control in the future.
  796. // In that case, we could make it a full com object.
  797. // delete this; // We currently need our destructor called.
  798. return 0;
  799. }
  800. HRESULT CColorControl::QueryInterface(REFIID riid, void **ppvObj)
  801. {
  802. HRESULT hr = E_NOINTERFACE;
  803. static const QITAB qit[] =
  804. {
  805. QITABENT(CColorControl, IObjectWithSite),
  806. QITABENT(CColorControl, IOleWindow),
  807. { 0 },
  808. };
  809. return QISearch(this, qit, riid, ppvObj);
  810. }
  811. //===========================
  812. // *** Class Methods ***
  813. //===========================
  814. CColorControl::CColorControl() : m_cRef(1)
  815. {
  816. DllAddRef();
  817. m_hwndParent = NULL;
  818. m_brColor = NULL;
  819. m_rbgColor = RGB(255, 255, 255); // Default to white
  820. m_cxEdgeSM = GetSystemMetrics(SM_CXEDGE);
  821. m_cyEdgeSM = GetSystemMetrics(SM_CYEDGE);
  822. HKEY hkSchemes;
  823. // if no colors are there, initialize to all white
  824. for (int nIndex = 0; nIndex < ARRAYSIZE(m_rbgCustomColors); nIndex++)
  825. {
  826. m_rbgCustomColors[nIndex] = RGB(255, 255, 255);
  827. }
  828. // select the current scheme
  829. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_APPEARANCE, 0, KEY_QUERY_VALUE, &hkSchemes) == ERROR_SUCCESS)
  830. {
  831. // also, since this key is already open, get the custom colors
  832. DWORD dwSize = sizeof(m_rbgCustomColors);
  833. DWORD dwType = REG_BINARY;
  834. // It's okay if this call fails. We handle the case where the user
  835. // didn't create custom colors.
  836. RegQueryValueEx(hkSchemes, REGSTR_VAL_CUSTOMCOLORS, NULL, &dwType, (LPBYTE)m_rbgCustomColors, &dwSize);
  837. RegCloseKey(hkSchemes);
  838. }
  839. _InitColorAndPalette();
  840. }
  841. CColorControl::~CColorControl()
  842. {
  843. // We ignore the return value for _SaveCustomColors() because
  844. // we don't want to fail the changing of the color if the user can't
  845. // save the customized palette.
  846. _SaveCustomColors();
  847. if (m_brColor)
  848. {
  849. DeleteObject(m_brColor);
  850. }
  851. if (m_hpal3D)
  852. {
  853. DeleteObject(m_hpal3D);
  854. m_hpal3D = NULL;
  855. }
  856. if (m_hpalVGA)
  857. {
  858. DeleteObject(m_hpalVGA);
  859. m_hpalVGA = NULL;
  860. }
  861. if (m_hTheme)
  862. {
  863. CloseThemeData(m_hTheme);
  864. m_hTheme = NULL;
  865. }
  866. DllRelease();
  867. }