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.

990 lines
28 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. color2.c
  5. Abstract:
  6. This module implements the support for the Win32 color dialog.
  7. Revision History:
  8. --*/
  9. // precompiled headers
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include "color.h"
  13. // from pwin32.h
  14. #define MMoveTo(hdc, x, y) MoveToEx(hdc, x, y, NULL)
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. // ChangeColorSettings
  18. //
  19. // Updates color shown.
  20. //
  21. ////////////////////////////////////////////////////////////////////////////
  22. VOID ChangeColorSettings(
  23. register PCOLORINFO pCI)
  24. {
  25. register HDC hDC;
  26. HWND hDlg = pCI->hDialog;
  27. DWORD dwRGBcolor = pCI->currentRGB;
  28. RGBtoHLS(dwRGBcolor);
  29. if (gLum != pCI->currentLum)
  30. {
  31. hDC = GetDC(hDlg);
  32. EraseLumArrow(hDC, pCI);
  33. pCI->currentLum = gLum;
  34. HLStoHLSPos(COLOR_LUM, pCI);
  35. LumArrowPaint(hDC, pCI->nLumPos, pCI);
  36. ReleaseDC(hDlg, hDC);
  37. }
  38. if ((gHue != pCI->currentHue) || (gSat != pCI->currentSat))
  39. {
  40. pCI->currentHue = gHue;
  41. pCI->currentSat = gSat;
  42. InvalidateRect(hDlg, (LPRECT)&pCI->rLumPaint, FALSE);
  43. hDC = GetDC(hDlg);
  44. EraseCrossHair(hDC, pCI);
  45. HLStoHLSPos(COLOR_HUE, pCI);
  46. HLStoHLSPos(COLOR_SAT, pCI);
  47. CrossHairPaint(hDC, pCI->nHuePos, pCI->nSatPos, pCI);
  48. ReleaseDC(hDlg, hDC);
  49. }
  50. }
  51. ////////////////////////////////////////////////////////////////////////////
  52. //
  53. // LumArrowPaint
  54. //
  55. ////////////////////////////////////////////////////////////////////////////
  56. VOID LumArrowPaint(
  57. HDC hDC,
  58. SHORT y,
  59. PCOLORINFO pCI)
  60. {
  61. HBRUSH hBrush;
  62. int x, h;
  63. hBrush = SelectObject(hDC, GetSysColorBrush(COLOR_BTNTEXT));
  64. for (x = pCI->rLumScroll.left + 2, h = 1;
  65. x < pCI->rLumScroll.right - 2;
  66. x++, h += 2)
  67. {
  68. PatBlt(hDC, x, y - h / 2, 1, h, PATCOPY);
  69. }
  70. SelectObject(hDC, hBrush);
  71. }
  72. ////////////////////////////////////////////////////////////////////////////
  73. //
  74. // EraseLumArrow
  75. //
  76. ////////////////////////////////////////////////////////////////////////////
  77. VOID EraseLumArrow(
  78. HDC hDC,
  79. PCOLORINFO pCI)
  80. {
  81. HBRUSH hBrush;
  82. RECT Rect;
  83. hBrush = (HBRUSH)SendMessage( pCI->hDialog,
  84. WM_CTLCOLORDLG,
  85. (WPARAM)hDC,
  86. (LPARAM)pCI->hDialog );
  87. Rect.left = pCI->rLumScroll.left + 1;
  88. Rect.right = pCI->rLumScroll.right;
  89. Rect.top = pCI->nLumPos - (pCI->rLumScroll.right - pCI->rLumScroll.left);
  90. Rect.bottom = pCI->nLumPos + (pCI->rLumScroll.right - pCI->rLumScroll.left) + 1;
  91. FillRect(hDC, &Rect, hBrush);
  92. }
  93. ////////////////////////////////////////////////////////////////////////////
  94. //
  95. // EraseCrossHair
  96. //
  97. ////////////////////////////////////////////////////////////////////////////
  98. VOID EraseCrossHair(
  99. HDC hDC,
  100. PCOLORINFO pCI)
  101. {
  102. HBITMAP hOldBitmap;
  103. WORD distancex, distancey;
  104. WORD topy, bottomy, leftx, rightx;
  105. RECT rRainbow;
  106. CopyRect(&rRainbow, &pCI->rRainbow);
  107. distancex = (WORD)(10 * cxBorder);
  108. distancey = (WORD)(10 * cyBorder);
  109. topy = ((WORD)rRainbow.top > pCI->nSatPos - distancey)
  110. ? (WORD)rRainbow.top
  111. : pCI->nSatPos - distancey;
  112. bottomy = ((WORD)rRainbow.bottom < pCI->nSatPos + distancey)
  113. ? (WORD)rRainbow.bottom
  114. : pCI->nSatPos + distancey;
  115. leftx = ((WORD)rRainbow.left > pCI->nHuePos - distancex)
  116. ? (WORD)rRainbow.left
  117. : pCI->nHuePos - distancex;
  118. rightx = ((WORD)rRainbow.right < pCI->nHuePos + distancex)
  119. ? (WORD)rRainbow.right
  120. : pCI->nHuePos + distancex;
  121. hOldBitmap = SelectObject(hDCFastBlt, hRainbowBitmap);
  122. BitBlt( hDC,
  123. leftx,
  124. topy,
  125. rightx - leftx,
  126. bottomy - topy,
  127. hDCFastBlt,
  128. leftx - (WORD)rRainbow.left,
  129. topy - (WORD)rRainbow.top,
  130. SRCCOPY );
  131. SelectObject(hDCFastBlt, hOldBitmap);
  132. }
  133. ////////////////////////////////////////////////////////////////////////////
  134. //
  135. // CrossHairPaint
  136. //
  137. ////////////////////////////////////////////////////////////////////////////
  138. VOID CrossHairPaint(
  139. register HDC hDC,
  140. SHORT x,
  141. SHORT y,
  142. PCOLORINFO pCI)
  143. {
  144. SHORT distancex, distancey;
  145. SHORT topy, bottomy, topy2, bottomy2;
  146. SHORT leftx, rightx, leftx2, rightx2;
  147. RECT rRainbow;
  148. CopyRect(&rRainbow, &pCI->rRainbow);
  149. distancex = (SHORT)(5 * cxBorder);
  150. distancey = (SHORT)(5 * cyBorder);
  151. topy = (SHORT)((rRainbow.top > y - 2 * distancey)
  152. ? rRainbow.top
  153. : y - 2 * distancey);
  154. bottomy = (SHORT)((rRainbow.bottom < y + 2 * distancey)
  155. ? rRainbow.bottom
  156. : y + 2 * distancey);
  157. leftx = (SHORT)((rRainbow.left > x - 2 * distancex)
  158. ? rRainbow.left
  159. : x - 2 * distancex);
  160. rightx = (SHORT)((rRainbow.right < x + 2 * distancex)
  161. ? rRainbow.right
  162. : x + 2 * distancex);
  163. topy2 = (SHORT)((rRainbow.top > y - distancey)
  164. ? rRainbow.top
  165. : y - distancey);
  166. bottomy2 = (SHORT)((rRainbow.bottom < y + distancey)
  167. ? rRainbow.bottom
  168. : y + distancey);
  169. leftx2 = (SHORT)((rRainbow.left > x - distancex)
  170. ? rRainbow.left
  171. : x - distancex);
  172. rightx2 = (SHORT)((rRainbow.right < x + distancex)
  173. ? rRainbow.right
  174. : x + distancex);
  175. if (rRainbow.top < topy2)
  176. {
  177. if ((x - 1) >= rRainbow.left)
  178. {
  179. MMoveTo(hDC, x - 1, topy2);
  180. LineTo(hDC, x - 1, topy);
  181. }
  182. if ((int)x < rRainbow.right)
  183. {
  184. MMoveTo(hDC, x, topy2);
  185. LineTo(hDC, x, topy);
  186. }
  187. if ((x + 1) < rRainbow.right)
  188. {
  189. MMoveTo(hDC, x + 1, topy2);
  190. LineTo(hDC, x + 1, topy);
  191. }
  192. }
  193. if (rRainbow.bottom > bottomy2)
  194. {
  195. if ((x - 1) >= rRainbow.left)
  196. {
  197. MMoveTo(hDC, x - 1, bottomy2);
  198. LineTo(hDC, x - 1, bottomy);
  199. }
  200. if ((int)x < rRainbow.right)
  201. {
  202. MMoveTo(hDC, x, bottomy2);
  203. LineTo(hDC, x, bottomy);
  204. }
  205. if ((x + 1) < rRainbow.right)
  206. {
  207. MMoveTo(hDC, x + 1, bottomy2);
  208. LineTo(hDC, x + 1, bottomy);
  209. }
  210. }
  211. if (rRainbow.left < leftx2)
  212. {
  213. if ((y - 1) >= rRainbow.top)
  214. {
  215. MMoveTo(hDC, leftx2, y - 1);
  216. LineTo(hDC, leftx, y - 1);
  217. }
  218. if ((int)y < rRainbow.bottom)
  219. {
  220. MMoveTo(hDC, leftx2, y);
  221. LineTo(hDC, leftx, y);
  222. }
  223. if ((y + 1) < rRainbow.bottom)
  224. {
  225. MMoveTo(hDC, leftx2, y + 1);
  226. LineTo(hDC, leftx, y + 1);
  227. }
  228. }
  229. if (rRainbow.right > rightx2)
  230. {
  231. if ((y - 1) >= rRainbow.top)
  232. {
  233. MMoveTo(hDC, rightx2, y - 1);
  234. LineTo(hDC, rightx, y - 1);
  235. }
  236. if ((int)y < rRainbow.bottom)
  237. {
  238. MMoveTo(hDC, rightx2, y);
  239. LineTo(hDC, rightx, y);
  240. }
  241. if ((y + 1) < rRainbow.bottom)
  242. {
  243. MMoveTo(hDC, rightx2, y + 1);
  244. LineTo(hDC, rightx, y + 1);
  245. }
  246. }
  247. }
  248. ////////////////////////////////////////////////////////////////////////////
  249. //
  250. // NearestSolid
  251. //
  252. ////////////////////////////////////////////////////////////////////////////
  253. VOID NearestSolid(
  254. register PCOLORINFO pCI)
  255. {
  256. register HDC hDC;
  257. HWND hDlg = pCI->hDialog;
  258. hDC = GetDC(hDlg);
  259. EraseCrossHair(hDC, pCI);
  260. EraseLumArrow(hDC, pCI);
  261. RGBtoHLS(pCI->currentRGB = GetNearestColor(hDC, pCI->currentRGB));
  262. pCI->currentHue = gHue;
  263. pCI->currentLum = gLum;
  264. pCI->currentSat = gSat;
  265. HLStoHLSPos(0, pCI);
  266. CrossHairPaint(hDC, pCI->nHuePos, pCI->nSatPos, pCI);
  267. LumArrowPaint(hDC, pCI->nLumPos, pCI);
  268. ReleaseDC(hDlg, hDC);
  269. SetHLSEdit(0, pCI);
  270. SetRGBEdit(0, pCI);
  271. InvalidateRect(hDlg, (LPRECT)&pCI->rColorSamples, FALSE);
  272. InvalidateRect(hDlg, (LPRECT)&pCI->rLumPaint, FALSE);
  273. }
  274. ////////////////////////////////////////////////////////////////////////////
  275. //
  276. // HLSPostoHLS
  277. //
  278. ////////////////////////////////////////////////////////////////////////////
  279. VOID HLSPostoHLS(
  280. SHORT nHLSEdit,
  281. register PCOLORINFO pCI)
  282. {
  283. switch (nHLSEdit)
  284. {
  285. case COLOR_HUE:
  286. {
  287. pCI->currentHue = (WORD)((pCI->nHuePos - pCI->rRainbow.left) *
  288. (RANGE - 1) / (pCI->nHueWidth - 1));
  289. break;
  290. }
  291. case COLOR_SAT:
  292. {
  293. pCI->currentSat = (WORD)(RANGE -
  294. (pCI->nSatPos - pCI->rRainbow.top) *
  295. RANGE / (pCI->nSatHeight - 1));
  296. break;
  297. }
  298. case COLOR_LUM:
  299. {
  300. pCI->currentLum = (WORD)(RANGE -
  301. (pCI->nLumPos - pCI->rLumPaint.top) *
  302. RANGE / (pCI->nLumHeight - 1));
  303. break;
  304. }
  305. default:
  306. {
  307. pCI->currentHue = (WORD)((pCI->nHuePos - pCI->rRainbow.left) *
  308. (RANGE - 1) / pCI->nHueWidth);
  309. pCI->currentSat = (WORD)(RANGE -
  310. (pCI->nSatPos - pCI->rRainbow.top) *
  311. RANGE / pCI->nSatHeight);
  312. pCI->currentLum = (WORD)(RANGE -
  313. (pCI->nLumPos - pCI->rLumPaint.top) *
  314. RANGE / pCI->nLumHeight);
  315. break;
  316. }
  317. }
  318. }
  319. ////////////////////////////////////////////////////////////////////////////
  320. //
  321. // HLStoHLSPos
  322. //
  323. ////////////////////////////////////////////////////////////////////////////
  324. VOID HLStoHLSPos(
  325. SHORT nHLSEdit,
  326. register PCOLORINFO pCI)
  327. {
  328. switch (nHLSEdit)
  329. {
  330. case ( COLOR_HUE ) :
  331. {
  332. pCI->nHuePos = (WORD)(pCI->rRainbow.left + pCI->currentHue *
  333. pCI->nHueWidth / (RANGE - 1));
  334. break;
  335. }
  336. case COLOR_SAT:
  337. {
  338. pCI->nSatPos = (WORD)(pCI->rRainbow.top +
  339. (RANGE - pCI->currentSat) *
  340. (pCI->nSatHeight - 1) / RANGE);
  341. break;
  342. }
  343. case COLOR_LUM:
  344. {
  345. pCI->nLumPos = (WORD)(pCI->rLumPaint.top +
  346. (RANGE - pCI->currentLum) *
  347. (pCI->nLumHeight - 1) / RANGE);
  348. break;
  349. }
  350. default:
  351. {
  352. pCI->nHuePos = (WORD)(pCI->rRainbow.left + pCI->currentHue *
  353. pCI->nHueWidth / (RANGE - 1));
  354. pCI->nSatPos = (WORD)(pCI->rRainbow.top +
  355. (RANGE - pCI->currentSat) *
  356. (pCI->nSatHeight - 1) / RANGE);
  357. pCI->nLumPos = (WORD)(pCI->rLumPaint.top +
  358. (RANGE - pCI->currentLum) *
  359. (pCI->nLumHeight - 1) / RANGE);
  360. break;
  361. }
  362. }
  363. }
  364. ////////////////////////////////////////////////////////////////////////////
  365. //
  366. // SetHLSEdit
  367. //
  368. ////////////////////////////////////////////////////////////////////////////
  369. VOID SetHLSEdit(
  370. SHORT nHLSEdit,
  371. register PCOLORINFO pCI)
  372. {
  373. register HWND hRainbowDlg = pCI->hDialog;
  374. switch (nHLSEdit)
  375. {
  376. case ( COLOR_HUE ) :
  377. {
  378. SetDlgItemInt(hRainbowDlg, COLOR_HUE, pCI->currentHue, FALSE);
  379. break;
  380. }
  381. case ( COLOR_SAT ) :
  382. {
  383. SetDlgItemInt(hRainbowDlg, COLOR_SAT, pCI->currentSat, FALSE);
  384. break;
  385. }
  386. case ( COLOR_LUM ) :
  387. {
  388. SetDlgItemInt(hRainbowDlg, COLOR_LUM, pCI->currentLum, FALSE);
  389. break;
  390. }
  391. default :
  392. {
  393. SetDlgItemInt(hRainbowDlg, COLOR_HUE, pCI->currentHue, FALSE);
  394. SetDlgItemInt(hRainbowDlg, COLOR_SAT, pCI->currentSat, FALSE);
  395. SetDlgItemInt(hRainbowDlg, COLOR_LUM, pCI->currentLum, FALSE);
  396. break;
  397. }
  398. }
  399. }
  400. ////////////////////////////////////////////////////////////////////////////
  401. //
  402. // SetRGBEdit
  403. //
  404. ////////////////////////////////////////////////////////////////////////////
  405. VOID SetRGBEdit(
  406. SHORT nRGBEdit,
  407. PCOLORINFO pCI)
  408. {
  409. register HWND hRainbowDlg = pCI->hDialog;
  410. DWORD rainbowRGB = pCI->currentRGB;
  411. switch (nRGBEdit)
  412. {
  413. case ( COLOR_RED ) :
  414. {
  415. SetDlgItemInt(hRainbowDlg, COLOR_RED, GetRValue(rainbowRGB), FALSE);
  416. break;
  417. }
  418. case ( COLOR_GREEN ) :
  419. {
  420. SetDlgItemInt(hRainbowDlg, COLOR_GREEN, GetGValue(rainbowRGB), FALSE);
  421. break;
  422. }
  423. case ( COLOR_BLUE ) :
  424. {
  425. SetDlgItemInt(hRainbowDlg, COLOR_BLUE, GetBValue(rainbowRGB), FALSE);
  426. break;
  427. }
  428. default :
  429. {
  430. SetDlgItemInt(hRainbowDlg, COLOR_RED, GetRValue(rainbowRGB), FALSE);
  431. SetDlgItemInt(hRainbowDlg, COLOR_GREEN, GetGValue(rainbowRGB), FALSE);
  432. SetDlgItemInt(hRainbowDlg, COLOR_BLUE, GetBValue(rainbowRGB), FALSE);
  433. break;
  434. }
  435. }
  436. }
  437. ////////////////////////////////////////////////////////////////////////////
  438. //
  439. // InitRainbow
  440. //
  441. // Returns TRUE iff we make it.
  442. //
  443. ////////////////////////////////////////////////////////////////////////////
  444. BOOL InitRainbow(
  445. register PCOLORINFO pCI)
  446. {
  447. HDC hDC;
  448. WORD Sat, Hue;
  449. HBITMAP hOldBitmap;
  450. RECT Rect;
  451. HBRUSH hbrSwipe;
  452. WORD nHueWidth, nSatHeight;
  453. register HWND hRainbowDlg = pCI->hDialog;
  454. RGBtoHLS(pCI->currentRGB);
  455. SetupRainbowCapture(pCI);
  456. nHueWidth = pCI->nHueWidth = (WORD)(pCI->rRainbow.right -
  457. pCI->rRainbow.left);
  458. nSatHeight = pCI->nSatHeight = (WORD)(pCI->rRainbow.bottom -
  459. pCI->rRainbow.top);
  460. pCI->currentHue = gHue;
  461. pCI->currentSat = gSat;
  462. pCI->currentLum = gLum;
  463. HLStoHLSPos(0, pCI);
  464. SetRGBEdit(0, pCI);
  465. SetHLSEdit(0, pCI);
  466. if (!hRainbowBitmap)
  467. {
  468. hDC = GetDC(hRainbowDlg);
  469. hRainbowBitmap = CreateCompatibleBitmap(hDC, nHueWidth, nSatHeight);
  470. if (!hRainbowBitmap)
  471. {
  472. return (FALSE);
  473. }
  474. }
  475. hOldBitmap = SelectObject(hDCFastBlt, hRainbowBitmap);
  476. //
  477. // NOTE: The final pass through this loop paints on and past the end
  478. // of the selected bitmap. Windows is a good product, and doesn't
  479. // let such foolishness happen.
  480. //
  481. Rect.bottom = 0;
  482. for (Sat = RANGE; Sat > 0; Sat -= SATINC)
  483. {
  484. Rect.top = Rect.bottom;
  485. Rect.bottom = (nSatHeight * RANGE - (Sat - SATINC) * nSatHeight) / RANGE;
  486. Rect.right = 0;
  487. for (Hue = 0; Hue < (RANGE - 1); Hue += HUEINC)
  488. {
  489. Rect.left = Rect.right;
  490. Rect.right = ((Hue + HUEINC) * nHueWidth) / RANGE;
  491. hbrSwipe = CreateSolidBrush(HLStoRGB(Hue, RANGE / 2, Sat));
  492. FillRect(hDCFastBlt, &Rect, hbrSwipe);
  493. DeleteObject(hbrSwipe);
  494. }
  495. }
  496. SelectObject(hDCFastBlt, hOldBitmap);
  497. ReleaseDC(hRainbowDlg, hDC);
  498. UpdateWindow(hRainbowDlg);
  499. return (TRUE);
  500. }
  501. ////////////////////////////////////////////////////////////////////////////
  502. //
  503. // PaintRainbow
  504. //
  505. ////////////////////////////////////////////////////////////////////////////
  506. VOID PaintRainbow(
  507. HDC hDC,
  508. LPRECT lpRect,
  509. register PCOLORINFO pCI)
  510. {
  511. HBITMAP hOldBitmap;
  512. if (!hRainbowBitmap)
  513. {
  514. return;
  515. }
  516. hOldBitmap = SelectObject(hDCFastBlt, hRainbowBitmap);
  517. BitBlt( hDC,
  518. lpRect->left,
  519. lpRect->top,
  520. lpRect->right - lpRect->left,
  521. lpRect->bottom - lpRect->top,
  522. hDCFastBlt,
  523. lpRect->left - pCI->rRainbow.left,
  524. lpRect->top - pCI->rRainbow.top,
  525. SRCCOPY );
  526. SelectObject(hDCFastBlt, hOldBitmap);
  527. CrossHairPaint(hDC, pCI->nHuePos, pCI->nSatPos, pCI);
  528. UpdateWindow(pCI->hDialog);
  529. }
  530. ////////////////////////////////////////////////////////////////////////////
  531. //
  532. // RainbowPaint
  533. //
  534. ////////////////////////////////////////////////////////////////////////////
  535. void RainbowPaint(
  536. register PCOLORINFO pCI,
  537. HDC hDC,
  538. LPRECT lpPaintRect)
  539. {
  540. WORD Lum;
  541. RECT Rect;
  542. HBRUSH hbrSwipe;
  543. //
  544. // Paint the Current Color Sample.
  545. //
  546. if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&(pCI->rCurrentColor)))
  547. {
  548. hbrSwipe = CreateSolidBrush(pCI->currentRGB);
  549. FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
  550. DeleteObject(hbrSwipe);
  551. }
  552. //
  553. // Paint the Nearest Pure Color Sample.
  554. //
  555. if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&(pCI->rNearestPure)))
  556. {
  557. hbrSwipe = CreateSolidBrush(GetNearestColor(hDC, pCI->currentRGB));
  558. FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
  559. DeleteObject(hbrSwipe);
  560. }
  561. //
  562. // Paint the Luminosity Range.
  563. //
  564. if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&(pCI->rLumPaint)))
  565. {
  566. Rect.left = pCI->rLumPaint.left;
  567. Rect.right = pCI->rLumPaint.right;
  568. Rect.top = pCI->rLumPaint.bottom - LUMINC / 2;
  569. Rect.bottom = pCI->rLumPaint.bottom;
  570. hbrSwipe = CreateSolidBrush(HLStoRGB( pCI->currentHue,
  571. 0,
  572. pCI->currentSat ));
  573. FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
  574. DeleteObject(hbrSwipe);
  575. for (Lum = LUMINC; Lum < RANGE; Lum += LUMINC)
  576. {
  577. Rect.bottom = Rect.top;
  578. Rect.top = (((pCI->rLumPaint.bottom + LUMINC / 2) * (DWORD)RANGE -
  579. (Lum + LUMINC) * pCI->nLumHeight) / RANGE);
  580. hbrSwipe = CreateSolidBrush(HLStoRGB( pCI->currentHue,
  581. Lum,
  582. pCI->currentSat ));
  583. FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
  584. DeleteObject(hbrSwipe);
  585. }
  586. Rect.bottom = Rect.top;
  587. Rect.top = pCI->rLumPaint.top;
  588. hbrSwipe = CreateSolidBrush(HLStoRGB( pCI->currentHue,
  589. RANGE,
  590. pCI->currentSat ));
  591. FillRect(hDC, (LPRECT)&Rect, hbrSwipe);
  592. DeleteObject(hbrSwipe);
  593. //
  594. // Paint the bounding rectangle only when it might be necessary.
  595. //
  596. if (!EqualRect(lpPaintRect, (LPRECT)&pCI->rLumPaint))
  597. {
  598. hbrSwipe = SelectObject(hDC, GetStockObject(NULL_BRUSH));
  599. Rectangle( hDC,
  600. pCI->rLumPaint.left - 1,
  601. pCI->rLumPaint.top - 1,
  602. pCI->rLumPaint.right + 1,
  603. pCI->rLumPaint.bottom + 1 );
  604. SelectObject(hDC, hbrSwipe);
  605. }
  606. }
  607. //
  608. // Paint the Luminosity Arrow.
  609. //
  610. if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&pCI->rLumScroll))
  611. {
  612. LumArrowPaint(hDC, pCI->nLumPos, pCI);
  613. }
  614. if (IntersectRect((LPRECT)&Rect, lpPaintRect, (LPRECT)&pCI->rRainbow))
  615. {
  616. PaintRainbow(hDC, (LPRECT)&Rect, pCI);
  617. }
  618. }
  619. ////////////////////////////////////////////////////////////////////////////
  620. //
  621. // Color conversion routines --
  622. //
  623. // RGBtoHLS() takes a DWORD RGB value, translates it to HLS, and stores the
  624. // results in the global vars H, L, and S. HLStoRGB takes the current values
  625. // of H, L, and S and returns the equivalent value in an RGB DWORD. The vars
  626. // H, L and S are written to only by 1) RGBtoHLS (initialization) or 2) the
  627. // scrollbar handlers.
  628. //
  629. // A point of reference for the algorithms is Foley and Van Dam, pp. 618-19.
  630. // Their algorithm is in floating point.
  631. //
  632. // There are potential roundoff errors lurking throughout here.
  633. // (0.5 + x/y) without floating point,
  634. // (x / y) phrased ((x + (y / 2)) / y) yields very small roundoff error.
  635. // This makes many of the following divisions look funny.
  636. //
  637. //
  638. // H,L, and S vary over 0 - HLSMAX.
  639. // R,G, and B vary over 0 - RGBMAX.
  640. // HLSMAX BEST IF DIVISIBLE BY 6.
  641. // RGBMAX, HLSMAX must each fit in a byte.
  642. //
  643. // Hue is undefined if Saturation is 0 (grey-scale).
  644. // This value determines where the Hue scrollbar is initially set for
  645. // achromatic colors.
  646. //
  647. ////////////////////////////////////////////////////////////////////////////
  648. #define UNDEFINED (HLSMAX * 2 / 3)
  649. ////////////////////////////////////////////////////////////////////////////
  650. //
  651. // RGBtoHLS
  652. //
  653. ////////////////////////////////////////////////////////////////////////////
  654. VOID RGBtoHLS(
  655. DWORD lRGBColor)
  656. {
  657. WORD R, G, B; // input RGB values
  658. WORD cMax,cMin; // max and min RGB values
  659. WORD cSum,cDif;
  660. SHORT Rdelta, Gdelta, Bdelta; // intermediate value: % of spread from max
  661. //
  662. // get R, G, and B out of DWORD.
  663. //
  664. R = GetRValue(lRGBColor);
  665. G = GetGValue(lRGBColor);
  666. B = GetBValue(lRGBColor);
  667. //
  668. // Calculate lightness.
  669. //
  670. cMax = max(max(R, G), B);
  671. cMin = min(min(R, G), B);
  672. cSum = cMax + cMin;
  673. gLum = (WORD)(((cSum * (DWORD)HLSMAX) + RGBMAX) / (2 * RGBMAX));
  674. cDif = cMax - cMin;
  675. if (!cDif)
  676. {
  677. //
  678. // r = g = b --> Achromatic case.
  679. //
  680. gSat = 0; // saturation
  681. gHue = UNDEFINED; // hue
  682. }
  683. else
  684. {
  685. //
  686. // Chromatic case.
  687. //
  688. //
  689. // Saturation.
  690. //
  691. // Note: Division by cSum is not a problem, as cSum can only
  692. // be 0 if the RGB value is 0L, and that is achromatic.
  693. //
  694. if (gLum <= (HLSMAX / 2))
  695. {
  696. gSat = (WORD)(((cDif * (DWORD) HLSMAX) + (cSum / 2) ) / cSum);
  697. }
  698. else
  699. {
  700. gSat = (WORD)((DWORD)((cDif * (DWORD)HLSMAX) +
  701. (DWORD)((2 * RGBMAX - cSum) / 2)) /
  702. (2 * RGBMAX - cSum));
  703. }
  704. //
  705. // Hue.
  706. //
  707. Rdelta = (SHORT)((((cMax - R) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
  708. Gdelta = (SHORT)((((cMax - G) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
  709. Bdelta = (SHORT)((((cMax - B) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
  710. if (R == cMax)
  711. {
  712. gHue = Bdelta - Gdelta;
  713. }
  714. else if (G == cMax)
  715. {
  716. gHue = (WORD)((HLSMAX / 3) + Rdelta - Bdelta);
  717. }
  718. else // (B == cMax)
  719. {
  720. gHue = (WORD)(((2 * HLSMAX) / 3) + Gdelta - Rdelta);
  721. }
  722. if ((short)gHue < 0)
  723. {
  724. //
  725. // This can occur when R == cMax and G is > B.
  726. //
  727. gHue += HLSMAX;
  728. }
  729. if (gHue >= HLSMAX)
  730. {
  731. gHue -= HLSMAX;
  732. }
  733. }
  734. }
  735. ////////////////////////////////////////////////////////////////////////////
  736. //
  737. // HueToRGB
  738. //
  739. // Utility routine for HLStoRGB.
  740. //
  741. ////////////////////////////////////////////////////////////////////////////
  742. WORD HueToRGB(
  743. WORD n1,
  744. WORD n2,
  745. WORD hue)
  746. {
  747. if (hue >= HLSMAX)
  748. {
  749. hue -= HLSMAX;
  750. }
  751. //
  752. // Return r, g, or b value from this tridrant.
  753. //
  754. if (hue < (HLSMAX / 6))
  755. {
  756. return ((WORD)(n1 + (((n2 - n1) * hue + (HLSMAX / 12)) / (HLSMAX / 6))));
  757. }
  758. if (hue < (HLSMAX/2))
  759. {
  760. return (n2);
  761. }
  762. if (hue < ((HLSMAX*2)/3))
  763. {
  764. return ((WORD)(n1 + (((n2 - n1) * (((HLSMAX * 2) / 3) - hue) +
  765. (HLSMAX / 12)) / (HLSMAX / 6))));
  766. }
  767. else
  768. {
  769. return (n1);
  770. }
  771. }
  772. ////////////////////////////////////////////////////////////////////////////
  773. //
  774. // HLStoRGB
  775. //
  776. ////////////////////////////////////////////////////////////////////////////
  777. DWORD HLStoRGB(
  778. WORD hue,
  779. WORD lum,
  780. WORD sat)
  781. {
  782. WORD R, G, B; // RGB component values
  783. WORD Magic1, Magic2; // calculated magic numbers
  784. if (sat == 0)
  785. {
  786. //
  787. // Achromatic case.
  788. //
  789. R = G = B = (WORD)((lum * RGBMAX) / HLSMAX);
  790. }
  791. else
  792. {
  793. //
  794. // Chromatic case
  795. //
  796. //
  797. // Set up magic numbers.
  798. //
  799. if (lum <= (HLSMAX / 2))
  800. {
  801. Magic2 = (WORD)((lum * ((DWORD)HLSMAX + sat) + (HLSMAX / 2)) / HLSMAX);
  802. }
  803. else
  804. {
  805. Magic2 = lum + sat -
  806. (WORD)(((lum * sat) + (DWORD)(HLSMAX / 2)) / HLSMAX);
  807. }
  808. Magic1 = (WORD)(2 * lum - Magic2);
  809. //
  810. // Get RGB, change units from HLSMAX to RGBMAX.
  811. //
  812. R = (WORD)(((HueToRGB(Magic1, Magic2, (WORD)(hue + (HLSMAX / 3))) *
  813. (DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
  814. G = (WORD)(((HueToRGB(Magic1, Magic2, hue) *
  815. (DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
  816. B = (WORD)(((HueToRGB(Magic1, Magic2, (WORD)(hue - (HLSMAX / 3))) *
  817. (DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
  818. }
  819. return (RGB(R, G, B));
  820. }
  821. ////////////////////////////////////////////////////////////////////////////
  822. //
  823. // RGBEditChange
  824. //
  825. // Checks the edit box for a valid entry and updates the Hue, Sat, and Lum
  826. // edit controls if appropriate. Also updates Lum picture and current
  827. // color sample.
  828. //
  829. // nDlgID - Dialog ID of Red, Green or Blue edit control.
  830. //
  831. ////////////////////////////////////////////////////////////////////////////
  832. SHORT RGBEditChange(
  833. SHORT nDlgID,
  834. PCOLORINFO pCI)
  835. {
  836. BOOL bOK; // check that value in edit control is uint
  837. BYTE *currentValue; // pointer to byte in RGB to change (or reset)
  838. SHORT nVal;
  839. TCHAR cEdit[3];
  840. register HWND hDlg = pCI->hDialog;
  841. currentValue = (BYTE *)&pCI->currentRGB;
  842. switch (nDlgID)
  843. {
  844. case ( COLOR_GREEN ) :
  845. {
  846. currentValue++;
  847. break;
  848. }
  849. case ( COLOR_BLUE ) :
  850. {
  851. currentValue += 2;
  852. break;
  853. }
  854. }
  855. nVal = (SHORT)GetDlgItemInt(hDlg, nDlgID, (BOOL FAR *)&bOK, FALSE);
  856. if (bOK)
  857. {
  858. if (nVal > RGBMAX)
  859. {
  860. nVal = RGBMAX;
  861. SetDlgItemInt(hDlg, nDlgID, nVal, FALSE);
  862. }
  863. if (nVal != (SHORT) *currentValue)
  864. {
  865. *currentValue = LOBYTE(nVal);
  866. ChangeColorSettings(pCI);
  867. SetHLSEdit(nDlgID, pCI);
  868. }
  869. }
  870. else if (GetDlgItemText(hDlg, nDlgID, (LPTSTR)cEdit, 2))
  871. {
  872. SetRGBEdit(nDlgID, pCI);
  873. SendDlgItemMessage(hDlg, nDlgID, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  874. }
  875. return (SHORT)(bOK ? TRUE : FALSE);
  876. }