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.

597 lines
19 KiB

  1. /*****************************************************************************\
  2. FILE: colorpic.cpp
  3. DESCRIPTION:
  4. This code will display a color picker UI.
  5. ??????? ?/??/1993 Created
  6. BryanSt 3/23/2000 Updated and Converted to C++ (Bryan Starbuck)
  7. Copyright (C) Microsoft Corp 1993-2000. All rights reserved.
  8. \*****************************************************************************/
  9. #include "priv.h"
  10. #include "AdvAppearPg.h"
  11. #include "PreviewSM.h"
  12. #define NUM_COLORSMAX 64
  13. #define NUM_COLORSPERROW 4
  14. typedef struct {
  15. LPCOLORPICK_INFO lpcpi;
  16. int dxColor;
  17. int dyColor;
  18. int iCurColor;
  19. int iNumColors;
  20. BOOL capturing;
  21. BOOL justdropped;
  22. COLORREF Colors[NUM_COLORSMAX];
  23. } MYDATA, * PMYDATA, FAR * LPMYDATA;
  24. BOOL g_bCursorHidden;
  25. INT_PTR CALLBACK ColorPickDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam);
  26. BOOL NEAR PASCAL UseColorPicker( LPCOLORPICK_INFO lpcpi )
  27. {
  28. CHOOSECOLOR cc;
  29. extern COLORREF g_CustomColors[16];
  30. cc.lStructSize = sizeof(cc);
  31. cc.hwndOwner = lpcpi->hwndParent; // NOT lpcpi->hwndOwner
  32. cc.hInstance = NULL;
  33. cc.rgbResult = lpcpi->rgb;
  34. cc.lpCustColors = g_CustomColors;
  35. cc.Flags = CC_RGBINIT | lpcpi->flags;
  36. cc.lCustData = 0L;
  37. cc.lpfnHook = NULL;
  38. cc.lpTemplateName = NULL;
  39. if (ChooseColor(&cc))
  40. {
  41. lpcpi->rgb = cc.rgbResult;
  42. return TRUE;
  43. }
  44. return FALSE;
  45. }
  46. void NEAR PASCAL DrawColorSquare(HDC hdc, int iColor, PMYDATA pmd)
  47. {
  48. RECT rc;
  49. COLORREF rgb;
  50. HPALETTE hpalOld = NULL;
  51. HBRUSH hbr;
  52. // custom color
  53. if (iColor == pmd->iNumColors)
  54. {
  55. rc.left = 0;
  56. rc.top = 0;
  57. rgb = pmd->lpcpi->rgb;
  58. }
  59. else
  60. {
  61. rc.left = (iColor % NUM_COLORSPERROW) * pmd->dxColor;
  62. rc.top = (iColor / NUM_COLORSPERROW) * pmd->dyColor;
  63. rgb = pmd->Colors[iColor];
  64. }
  65. rc.right = rc.left + pmd->dxColor;
  66. rc.bottom = rc.top + pmd->dyColor;
  67. // focused one
  68. if (iColor == pmd->iCurColor)
  69. {
  70. PatBlt(hdc, rc.left, rc.top, pmd->dxColor, 3, BLACKNESS);
  71. PatBlt(hdc, rc.left, rc.bottom - 3, pmd->dxColor, 3, BLACKNESS);
  72. PatBlt(hdc, rc.left, rc.top + 3, 3, pmd->dyColor - 6, BLACKNESS);
  73. PatBlt(hdc, rc.right - 3, rc.top + 3, 3, pmd->dyColor - 6, BLACKNESS);
  74. InflateRect(&rc, -1, -1);
  75. HBRUSH hBrushWhite = (HBRUSH) GetStockObject(WHITE_BRUSH);
  76. if (hBrushWhite)
  77. {
  78. FrameRect(hdc, &rc, hBrushWhite);
  79. }
  80. InflateRect(&rc, -2, -2);
  81. }
  82. else
  83. {
  84. // clean up possible focus thing from above
  85. FrameRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
  86. InflateRect(&rc, -cxBorder, -cyBorder);
  87. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  88. }
  89. if ((pmd->lpcpi->flags & CC_SOLIDCOLOR) && !(rgb & 0xFF000000))
  90. rgb = GetNearestColor(hdc, rgb);
  91. hbr = CreateSolidBrush(rgb);
  92. if (pmd->lpcpi->hpal)
  93. {
  94. hpalOld = SelectPalette(hdc, pmd->lpcpi->hpal, FALSE);
  95. RealizePalette(hdc);
  96. }
  97. hbr = (HBRUSH) SelectObject(hdc, hbr);
  98. PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
  99. hbr = (HBRUSH) SelectObject(hdc, hbr);
  100. if (hpalOld)
  101. {
  102. hpalOld = SelectPalette(hdc, hpalOld, TRUE);
  103. RealizePalette(hdc);
  104. }
  105. if (hbr)
  106. {
  107. DeleteObject(hbr);
  108. }
  109. }
  110. /*
  111. ** set the focus to the given color.
  112. **
  113. ** in the process, also take the focus off of the old focus color.
  114. */
  115. void NEAR PASCAL FocusColor(HWND hDlg, int iNewColor, PMYDATA pmd)
  116. {
  117. int i;
  118. HDC hdc = NULL;
  119. HWND hwnd;
  120. if (iNewColor == pmd->iCurColor)
  121. return;
  122. i = pmd->iCurColor;
  123. pmd->iCurColor = iNewColor;
  124. // unfocus the old one
  125. if( i >= 0 )
  126. {
  127. if (i == pmd->iNumColors)
  128. hwnd = GetDlgItem(hDlg, IDC_CPDLG_COLORCUST);
  129. else
  130. hwnd = GetDlgItem(hDlg, IDC_CPDLG_16COLORS);
  131. hdc = GetDC(hwnd);
  132. DrawColorSquare(hdc, i, pmd);
  133. ReleaseDC(hwnd, hdc);
  134. }
  135. // focus the new one
  136. if( iNewColor >= 0 )
  137. {
  138. if (iNewColor == pmd->iNumColors)
  139. hwnd = GetDlgItem(hDlg, IDC_CPDLG_COLORCUST);
  140. else
  141. hwnd = GetDlgItem(hDlg, IDC_CPDLG_16COLORS);
  142. hdc = GetDC(hwnd);
  143. DrawColorSquare(hdc, iNewColor, pmd);
  144. ReleaseDC(hwnd, hdc);
  145. }
  146. }
  147. void NEAR PASCAL Color_TrackMouse(HWND hDlg, POINT pt, PMYDATA pmd)
  148. {
  149. HWND hwndKid;
  150. int id;
  151. hwndKid = ChildWindowFromPoint(hDlg, pt);
  152. if (hwndKid == NULL || hwndKid == hDlg)
  153. return;
  154. id = GetWindowLong(hwndKid, GWL_ID);
  155. switch (id)
  156. {
  157. case IDC_CPDLG_16COLORS:
  158. MapWindowPoints(hDlg, GetDlgItem(hDlg, IDC_CPDLG_16COLORS), &pt, 1);
  159. pt.x /= pmd->dxColor;
  160. pt.y /= pmd->dyColor;
  161. FocusColor(hDlg, pt.x + (pt.y * NUM_COLORSPERROW), pmd);
  162. break;
  163. case IDC_CPDLG_COLORCUST:
  164. if (IsWindowVisible(hwndKid))
  165. FocusColor(hDlg, pmd->iNumColors, pmd);
  166. break;
  167. case IDC_CPDLG_COLOROTHER:
  168. FocusColor(hDlg, -1, pmd);
  169. break;
  170. }
  171. }
  172. void NEAR PASCAL Color_DrawItem(HWND hDlg, LPDRAWITEMSTRUCT lpdis, PMYDATA pmd)
  173. {
  174. int i;
  175. if (lpdis->CtlID == IDC_CPDLG_COLORCUST)
  176. {
  177. DrawColorSquare(lpdis->hDC, pmd->iNumColors, pmd);
  178. }
  179. else
  180. {
  181. for (i = 0; i < pmd->iNumColors; i++)
  182. DrawColorSquare(lpdis->hDC, i, pmd);
  183. }
  184. }
  185. /*
  186. ** init the mini-color-picker
  187. **
  188. ** the dialog is pretending to be a menu, so figure out where to pop
  189. ** it up so that it is visible all around.
  190. **
  191. ** also because this dialog is pretty darn concerned with its look,
  192. ** hand-align the components in pixel units. THIS IS GROSS!
  193. */
  194. void NEAR PASCAL Color_InitDialog(HWND hDlg, PMYDATA pmd)
  195. {
  196. RECT rcOwner;
  197. RECT rc, rc2;
  198. int dx, dy;
  199. int x, y;
  200. int i;
  201. HWND hwndColors, hwnd;
  202. HWND hwndEtch, hwndCust;
  203. int width, widthCust, widthEtch;
  204. int cyEdge = ClassicGetSystemMetrics(SM_CYEDGE);
  205. HPALETTE hpal = pmd->lpcpi->hpal;
  206. MONITORINFO mi;
  207. TCHAR szBuf[50];
  208. LONG cbBuf = ARRAYSIZE( szBuf );
  209. HDC hDC;
  210. SIZE size;
  211. if (hpal == NULL)
  212. hpal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
  213. pmd->iNumColors = 0;
  214. GetObject(hpal, sizeof(int), &pmd->iNumColors);
  215. if (pmd->iNumColors > NUM_COLORSMAX)
  216. pmd->iNumColors = NUM_COLORSMAX;
  217. if (GetPaletteEntries(hpal,0, pmd->iNumColors, (LPPALETTEENTRY)pmd->Colors))
  218. {
  219. for (i = 0; i < pmd->iNumColors; i++)
  220. {
  221. pmd->Colors[i] &= 0x00FFFFFF;
  222. pmd->Colors[i] |= 0x02000000;
  223. }
  224. for (i = 0; i < pmd->iNumColors; i++)
  225. {
  226. if ((pmd->Colors[i] & 0x00FFFFFF) == (pmd->lpcpi->rgb & 0x00FFFFFF))
  227. {
  228. ShowWindow(GetDlgItem(hDlg, IDC_CPDLG_COLORCUST), SW_HIDE);
  229. break;
  230. }
  231. }
  232. // current is either one of 16 or the custom color (== pmd->iNumColors
  233. pmd->iCurColor = i;
  234. // size the 16 colors to be square
  235. hwndColors = GetDlgItem(hDlg, IDC_CPDLG_16COLORS);
  236. GetClientRect(hwndColors, &rc);
  237. // To make localization easy..
  238. //
  239. hwndEtch=GetDlgItem(hDlg, IDC_CPDLG_COLORETCH);
  240. GetClientRect(hwndEtch, &rc2);
  241. widthEtch = rc2.right-rc2.left;
  242. hwndCust=GetDlgItem(hDlg, IDC_CPDLG_COLORCUST);
  243. GetClientRect(hwndCust, &rc2);
  244. widthCust = rc2.right-rc2.left;
  245. hwnd = GetDlgItem(hDlg, IDC_CPDLG_COLOROTHER);
  246. GetWindowRect(hwnd, &rc2); // we must initialize rc2 with this control.
  247. // Make sure the button is big enough to contain its text
  248. width = rc.right - rc.left;
  249. if( GetDlgItemText( hDlg, IDC_CPDLG_COLOROTHER, szBuf, cbBuf ) )
  250. {
  251. RECT rcTemp;
  252. int iRet;
  253. HFONT hfont, hfontOld;
  254. // Get the font for the button
  255. hDC = GetDC( hwnd );
  256. if( hDC )
  257. {
  258. hfont = (HFONT)SendMessage( hwnd, WM_GETFONT, 0, 0 );
  259. ASSERT(hfont);
  260. hfontOld = (HFONT) SelectObject( hDC, hfont );
  261. // Get the size of the text
  262. iRet = DrawTextEx( hDC, szBuf, lstrlen(szBuf), &rcTemp, DT_CALCRECT | DT_SINGLELINE, NULL );
  263. ASSERT( iRet );
  264. size.cx = rcTemp.right - rcTemp.left + 7; //account for the button border
  265. size.cy = rcTemp.bottom - rcTemp.top;
  266. // Adjust the button size if the text needs more space
  267. if( size.cx > width )
  268. {
  269. rc2.right = rc2.left + size.cx;
  270. rc2.bottom = rc2.top + size.cy;
  271. MoveWindow( hwnd, rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top, FALSE );
  272. }
  273. SelectObject( hDC, hfontOld );
  274. ReleaseDC( hwnd, hDC );
  275. }
  276. }
  277. // Take possible biggest width to calculate sels
  278. //
  279. width = (widthEtch > widthCust+(rc2.right-rc2.left)) ? widthEtch : widthCust+(rc2.right-rc2.left);
  280. width = (width > rc.right-rc.left) ? width: rc.right-rc.left;
  281. #define NUM_COLORSPERCOL (pmd->iNumColors / NUM_COLORSPERROW)
  282. pmd->dxColor = pmd->dyColor
  283. = ((rc.bottom - rc.top) / NUM_COLORSPERCOL > width / NUM_COLORSPERROW )
  284. ? (rc.bottom - rc.top) / NUM_COLORSPERCOL : width / NUM_COLORSPERROW;
  285. // Make sure custum color can fit
  286. //
  287. if (pmd->dxColor*(NUM_COLORSPERROW-1) < rc2.right-rc2.left )
  288. pmd->dxColor = pmd->dyColor = (rc2.right-rc2.left)/(NUM_COLORSPERROW-1);
  289. // make each color square's width the same as the height
  290. SetWindowPos(hwndColors, NULL, 0, 0, pmd->dxColor * NUM_COLORSPERROW,
  291. pmd->dyColor * NUM_COLORSPERCOL,
  292. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW);
  293. rc.right = rc.left + pmd->dxColor * NUM_COLORSPERROW;
  294. rc.bottom = rc.top + pmd->dyColor * NUM_COLORSPERCOL;
  295. MapWindowPoints(hwndColors, hDlg, (LPPOINT)(LPRECT)&rc, 2);
  296. // move/size the etch to the right place
  297. // (compensate for the colors being "inset" by one)
  298. MoveWindow(hwndEtch, rc.left + 1, rc.bottom + cyEdge,
  299. rc.right - rc.left - 2, cyEdge, FALSE);
  300. y = rc.bottom + 3 * cyEdge;
  301. // size the custom color to the same square and right-align
  302. MoveWindow(hwndCust, rc.right - pmd->dxColor, y,
  303. pmd->dxColor, pmd->dyColor, FALSE);
  304. // do same for button
  305. MapWindowPoints(NULL, hDlg, (LPPOINT)(LPRECT)&rc2, 2);
  306. // base the width of the custom button on the remaining space to
  307. // the left of the custom color. Also move the custom button one pix right
  308. // of the left edge. This only is done if a custom color is selected...
  309. if (pmd->iCurColor != pmd->iNumColors) {
  310. // no custom color
  311. MoveWindow(hwnd, rc2.left, y, rc2.right-rc2.left, pmd->dyColor, FALSE);
  312. }
  313. else {
  314. // custom color, adjust the Other... button
  315. dx = rc2.right - rc2.left++;
  316. if (rc2.left + dx >= rc.right - pmd->dxColor - 2)
  317. MoveWindow(hwnd, rc2.left, y, rc.right - pmd->dxColor - 2 , pmd->dyColor, FALSE);
  318. else
  319. MoveWindow(hwnd, rc2.left, y, dx, pmd->dyColor, FALSE);
  320. }
  321. // now figure out the size for the dialog itself
  322. rc.left = rc.top = 0;
  323. rc.right = rc.left + pmd->dxColor * NUM_COLORSPERROW;
  324. // (compensate for the colors being "inset" by one)
  325. rc.bottom = y + pmd->dyColor + 1;
  326. AdjustWindowRect(&rc, GetWindowLong(hDlg, GWL_STYLE), FALSE);
  327. dx = rc.right - rc.left;
  328. dy = rc.bottom - rc.top;
  329. GetWindowRect(pmd->lpcpi->hwndOwner, &rcOwner);
  330. // Make sure the window is entirely on the monitor
  331. mi.cbSize = sizeof(mi);
  332. GetMonitorInfo(MonitorFromRect(&rcOwner, MONITOR_DEFAULTTONEAREST), &mi);
  333. if (rcOwner.left < mi.rcMonitor.left) { // overlap left side
  334. x = mi.rcMonitor.left;
  335. }
  336. else if (rcOwner.left + dx >= mi.rcMonitor.right) { // overlap right side
  337. x = mi.rcMonitor.right - dx - 1;
  338. }
  339. else { // no overlap
  340. x = rcOwner.left;
  341. }
  342. if (rcOwner.top < mi.rcMonitor.top) { // overlap top side
  343. y = rcOwner.bottom;
  344. }
  345. else if (rcOwner.bottom + dy >= mi.rcMonitor.bottom) {// overlap bottom side
  346. y = rcOwner.top - dy;
  347. }
  348. else { // no overlap
  349. y = rcOwner.bottom;
  350. }
  351. MoveWindow(hDlg, x, y, dx, dy, FALSE);
  352. }
  353. }
  354. INT_PTR CALLBACK ColorPickDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  355. {
  356. PMYDATA pmd = (PMYDATA)GetWindowLongPtr(hDlg, DWLP_USER);
  357. HWND hwndKid;
  358. int wRet;
  359. int id;
  360. POINT pt;
  361. BOOL fEnd = FALSE;
  362. if (!pmd && (WM_INITDIALOG != message))
  363. {
  364. return FALSE;
  365. }
  366. switch(message)
  367. {
  368. case WM_INITDIALOG:
  369. pmd = (PMYDATA)LocalAlloc(LPTR, sizeof(MYDATA));
  370. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pmd);
  371. if (pmd)
  372. {
  373. pmd->lpcpi = (LPCOLORPICK_INFO)lParam;
  374. pmd->capturing = FALSE;
  375. pmd->justdropped = TRUE;
  376. Color_InitDialog(hDlg, pmd);
  377. SetFocus(GetDlgItem(hDlg, IDC_CPDLG_16COLORS));
  378. // post self a message to setcapture after painting
  379. PostMessage(hDlg, WM_APP+1, 0, 0L);
  380. }
  381. else
  382. {
  383. EndDialog(hDlg, IDCANCEL);
  384. }
  385. return FALSE;
  386. case WM_APP+1:
  387. if (g_bCursorHidden)
  388. {
  389. ShowCursor(TRUE);
  390. g_bCursorHidden = FALSE;
  391. }
  392. SetCursor(LoadCursor(NULL, IDC_ARROW));
  393. pmd->capturing = TRUE;
  394. SetCapture(hDlg);
  395. pmd->capturing = FALSE;
  396. break;
  397. case WM_DESTROY:
  398. LocalFree((HLOCAL)pmd);
  399. break;
  400. case WM_CAPTURECHANGED:
  401. if( pmd->capturing )
  402. return TRUE; // ignore if we're doing this on purpose
  403. // if this wasn't a button in the dialog, dismiss ourselves
  404. if( !pmd->justdropped || (HWND)lParam == NULL || GetParent((HWND)lParam) != hDlg)
  405. {
  406. EndDialog(hDlg, IDCANCEL);
  407. return TRUE;
  408. }
  409. break;
  410. case WM_MOUSEMOVE:
  411. LPARAM2POINT(lParam, &pt );
  412. Color_TrackMouse(hDlg, pt, pmd);
  413. break;
  414. // if button up is on the parent, leave picker up and untrammeled.
  415. // otherwise, we must have "menu-tracked" to get here, so select.
  416. case WM_LBUTTONUP:
  417. case WM_RBUTTONUP:
  418. LPARAM2POINT(lParam, &pt);
  419. MapWindowPoints(hDlg, pmd->lpcpi->hwndOwner, &pt, 1);
  420. if (ChildWindowFromPoint(pmd->lpcpi->hwndOwner, pt))
  421. return 0;
  422. pmd->capturing = TRUE;
  423. pmd->justdropped = FALSE; // user could not be dragging from owner
  424. ReleaseCapture();
  425. pmd->capturing = FALSE;
  426. fEnd = TRUE;
  427. // || fall ||
  428. // || through ||
  429. // \/ \/
  430. case WM_LBUTTONDOWN:
  431. case WM_RBUTTONDOWN:
  432. LPARAM2POINT(lParam, &pt);
  433. hwndKid = ChildWindowFromPoint(hDlg, pt);
  434. // assume it's a dismissal if we're going to close...
  435. wRet = IDCANCEL;
  436. // if not on parent, dismiss picker
  437. if (hwndKid != NULL && hwndKid != hDlg)
  438. {
  439. id = GetWindowLong(hwndKid, GWL_ID);
  440. switch (id)
  441. {
  442. case IDC_CPDLG_16COLORS:
  443. // make sure that iCurColor is valid
  444. Color_TrackMouse(hDlg, pt, pmd);
  445. pmd->lpcpi->rgb = pmd->Colors[pmd->iCurColor] & 0x00FFFFFF;
  446. wRet = IDOK;
  447. break;
  448. case IDC_CPDLG_COLOROTHER:
  449. FocusColor(hDlg, -1, pmd);
  450. wRet = id; // this will fall thru to use the picker
  451. fEnd = TRUE; // we have capture, the button won't click
  452. break;
  453. default:
  454. // if this is a down, we will track until the up
  455. // if this is an up, we will close with no change
  456. break;
  457. }
  458. }
  459. if( fEnd )
  460. {
  461. EndDialog(hDlg, wRet);
  462. return TRUE;
  463. }
  464. // make sure we have the capture again since we didn't close
  465. pmd->capturing = TRUE;
  466. SetCapture(hDlg);
  467. pmd->capturing = FALSE;
  468. break;
  469. case WM_DRAWITEM:
  470. Color_DrawItem(hDlg, (LPDRAWITEMSTRUCT)lParam, pmd);
  471. break;
  472. case WM_COMMAND:
  473. // all commands close the dialog
  474. // note IDC_CPDLG_COLOROTHER will fall through to the caller...
  475. // cannot pass ok with no color selected
  476. if( LOWORD(wParam) == IDOK && pmd->iCurColor < 0 )
  477. *((WORD *)(&wParam)) = IDCANCEL;
  478. EndDialog( hDlg, LOWORD(wParam) );
  479. break;
  480. }
  481. return FALSE;
  482. }
  483. BOOL WINAPI ChooseColorMini(LPCOLORPICK_INFO lpcpi)
  484. {
  485. INT_PTR iAnswer;
  486. ShowCursor(FALSE);
  487. g_bCursorHidden = TRUE;
  488. iAnswer = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_COLORPICK),
  489. lpcpi->hwndOwner, ColorPickDlgProc, (LPARAM)lpcpi);
  490. if (g_bCursorHidden)
  491. {
  492. ShowCursor(TRUE);
  493. g_bCursorHidden = FALSE;
  494. }
  495. switch( iAnswer )
  496. {
  497. case IDC_CPDLG_COLOROTHER: // the user picked the "Other..." button
  498. return UseColorPicker( lpcpi );
  499. case IDOK: // the user picked a color in our little window
  500. return TRUE;
  501. default:
  502. break;
  503. }
  504. return FALSE;
  505. }