ColorPicker.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /////////////////////////////////////////////////////////////////////////////////
  19. //
  20. // ColorPicker.cpp : implementation file
  21. //
  22. //
  23. #include "StdAfx.H"
  24. #include "ColorPicker.H"
  25. #include "ColorPickerDialogClass.H"
  26. #include <Math.H>
  27. #include "Utils.H"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. extern HINSTANCE _hinstance;
  34. /////////////////////////////////////////////////////////////////////////////
  35. //
  36. // ColorPickerClass
  37. //
  38. ColorPickerClass::ColorPickerClass (void)
  39. : m_hBitmap (NULL),
  40. m_iWidth (0),
  41. m_iHeight (0),
  42. m_CurrentPoint (0, 0),
  43. m_CurrentColor (0),
  44. m_bSelecting (false),
  45. m_pBits (NULL),
  46. m_hMemDC (NULL),
  47. m_CurrentHue (0),
  48. CWnd ()
  49. {
  50. return ;
  51. }
  52. /////////////////////////////////////////////////////////////////////////////
  53. //
  54. // ~ColorPickerClass
  55. //
  56. ColorPickerClass::~ColorPickerClass (void)
  57. {
  58. if (m_hMemDC != NULL) {
  59. ::DeleteObject (m_hMemDC);
  60. m_hMemDC = NULL;
  61. }
  62. Free_Bitmap ();
  63. return ;
  64. }
  65. BEGIN_MESSAGE_MAP(ColorPickerClass, CWnd)
  66. //{{AFX_MSG_MAP(ColorPickerClass)
  67. ON_WM_PAINT()
  68. ON_WM_CREATE()
  69. ON_WM_SIZE()
  70. ON_WM_ERASEBKGND()
  71. ON_WM_LBUTTONDOWN()
  72. ON_WM_LBUTTONUP()
  73. ON_WM_MOUSEMOVE()
  74. //}}AFX_MSG_MAP
  75. END_MESSAGE_MAP()
  76. /////////////////////////////////////////////////////////////////////////////
  77. //
  78. // OnPaint
  79. //
  80. void
  81. ColorPickerClass::OnPaint (void)
  82. {
  83. CPaintDC dc (this);
  84. if (m_hMemDC != NULL) {
  85. HBITMAP hold_bmp = (HBITMAP)::SelectObject (m_hMemDC, m_hBitmap);
  86. CRect rect;
  87. GetClientRect (&rect);
  88. ::BitBlt (dc, 0, 0, rect.Width (), rect.Height (), m_hMemDC, 0, 0, SRCCOPY);
  89. ::SelectObject (m_hMemDC, hold_bmp);
  90. Paint_Marker ();
  91. }
  92. return ;
  93. }
  94. /////////////////////////////////////////////////////////////////////////////
  95. //
  96. // RegisterColorPicker
  97. //
  98. void
  99. RegisterColorPicker (HINSTANCE hinst)
  100. {
  101. // Has the class already been registered?
  102. WNDCLASS wndclass = { 0 };
  103. if (::GetClassInfo (hinst, "WWCOLORPICKER", &wndclass) == FALSE) {
  104. wndclass.style = CS_GLOBALCLASS | CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
  105. wndclass.lpfnWndProc = fnColorPickerProc;
  106. wndclass.hInstance = hinst;
  107. wndclass.hbrBackground = (HBRUSH)COLOR_3DFACE + 1;
  108. wndclass.hCursor = ::LoadCursor (NULL, IDC_ARROW);
  109. wndclass.lpszClassName = "WWCOLORPICKER";
  110. // Let the windows manager know about this global class
  111. ::RegisterClass (&wndclass);
  112. }
  113. return ;
  114. }
  115. /////////////////////////////////////////////////////////////////////////////
  116. //
  117. // fnColorPickerProc
  118. //
  119. LRESULT WINAPI
  120. fnColorPickerProc
  121. (
  122. HWND hwnd,
  123. UINT message,
  124. WPARAM wparam,
  125. LPARAM lparam
  126. )
  127. {
  128. //static ColorPickerClass *pwnd = NULL;
  129. //static bool bcreated = false;
  130. switch (message)
  131. {
  132. case WM_CREATE:
  133. {
  134. LPCREATESTRUCT pcreate_info = (LPCREATESTRUCT)lparam;
  135. if (pcreate_info != NULL) {
  136. // Should we create a new class manager for this window?
  137. ColorPickerClass *pwnd = (ColorPickerClass *)pcreate_info->lpCreateParams;
  138. BOOL created = FALSE;
  139. if (pwnd == NULL) {
  140. pwnd = new ColorPickerClass;
  141. created = TRUE;
  142. }
  143. // Pull some hacks to get MFC to use the message map
  144. pwnd->Attach (hwnd);
  145. // Let the window know its being created
  146. pwnd->OnCreate (pcreate_info);
  147. WNDPROC *pOldWndProc = pwnd->GetSuperWndProcAddr ();
  148. if (pOldWndProc) {
  149. WNDPROC pold_proc = (WNDPROC)::SetWindowLong (hwnd, GWL_WNDPROC, (DWORD)::AfxGetAfxWndProc ());
  150. ASSERT (pold_proc != NULL);
  151. (*pOldWndProc) = pold_proc;
  152. }
  153. // Store some information in the window handle
  154. ::SetProp (hwnd, "CLASSPOINTER", (HANDLE)pwnd);
  155. ::SetProp (hwnd, "CREATED", (HANDLE)created);
  156. }
  157. }
  158. break;
  159. case WM_DESTROY:
  160. {
  161. /*pwnd->Detach ();
  162. WNDPROC *pOldWndProc = pwnd->GetSuperWndProcAddr ();
  163. if (pOldWndProc) {
  164. ::SetWindowLong (hwnd, GWL_WNDPROC, (DWORD)(*pOldWndProc));
  165. (*pOldWndProc) = NULL;
  166. }
  167. if (bcreated) {
  168. delete pwnd;
  169. pwnd = NULL;
  170. }*/
  171. // Get the creation information from the window handle
  172. ColorPickerClass *pwnd = (ColorPickerClass *)::GetProp (hwnd, "CLASSPOINTER");
  173. BOOL created = (BOOL)::GetProp (hwnd, "CREATED");
  174. if (pwnd != NULL) {
  175. pwnd->Detach ();
  176. WNDPROC *pOldWndProc = pwnd->GetSuperWndProcAddr ();
  177. if (pOldWndProc) {
  178. ::SetWindowLong (hwnd, GWL_WNDPROC, (DWORD)(*pOldWndProc));
  179. (*pOldWndProc) = NULL;
  180. }
  181. if (created) {
  182. delete pwnd;
  183. pwnd = NULL;
  184. }
  185. }
  186. }
  187. break;
  188. }
  189. // Allow default processing to occur
  190. return ::DefWindowProc (hwnd, message, wparam, lparam);
  191. }
  192. /////////////////////////////////////////////////////////////////////////////
  193. //
  194. // OnCreate
  195. //
  196. /////////////////////////////////////////////////////////////////////////////
  197. int
  198. ColorPickerClass::OnCreate (LPCREATESTRUCT lpCreateStruct)
  199. {
  200. if (CWnd::OnCreate(lpCreateStruct) == -1)
  201. return -1;
  202. m_hMemDC = ::CreateCompatibleDC (NULL);
  203. Create_Bitmap ();
  204. return 0;
  205. }
  206. /////////////////////////////////////////////////////////////////////////////
  207. //
  208. // Create
  209. //
  210. /////////////////////////////////////////////////////////////////////////////
  211. BOOL
  212. ColorPickerClass::Create
  213. (
  214. LPCTSTR /*lpszClassName*/,
  215. LPCTSTR lpszWindowName,
  216. DWORD dwStyle,
  217. const RECT &rect,
  218. CWnd *pparent_wnd,
  219. UINT nID,
  220. CCreateContext * /*pContext*/
  221. )
  222. {
  223. // Create the window (it will force the message map and everthing)
  224. HWND hparent_wnd = (pparent_wnd != NULL) ? pparent_wnd->m_hWnd : NULL;
  225. HWND hwnd = ::CreateWindow ("WWCOLORPICKER",
  226. lpszWindowName,
  227. dwStyle,
  228. rect.left,
  229. rect.top,
  230. rect.right - rect.left,
  231. rect.bottom - rect.top,
  232. hparent_wnd,
  233. (HMENU)nID,
  234. _hinstance,//::AfxGetInstanceHandle (),
  235. this);
  236. // Return the true/false result code
  237. return (hwnd != NULL);
  238. }
  239. /////////////////////////////////////////////////////////////////////////////
  240. //
  241. // Create_Bitmap
  242. //
  243. /////////////////////////////////////////////////////////////////////////////
  244. void
  245. ColorPickerClass::Create_Bitmap (void)
  246. {
  247. // Start fresh
  248. Free_Bitmap ();
  249. CRect rect;
  250. GetClientRect (&rect);
  251. m_iWidth = rect.Width ();
  252. m_iHeight = rect.Height ();
  253. // Set-up the fields of the BITMAPINFOHEADER
  254. BITMAPINFOHEADER bitmap_info;
  255. bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
  256. bitmap_info.biWidth = m_iWidth;
  257. bitmap_info.biHeight = -m_iHeight; // Top-down DIB uses negative height
  258. bitmap_info.biPlanes = 1;
  259. bitmap_info.biBitCount = 24;
  260. bitmap_info.biCompression = BI_RGB;
  261. bitmap_info.biSizeImage = ((m_iWidth * m_iHeight) * 3);
  262. bitmap_info.biXPelsPerMeter = 0;
  263. bitmap_info.biYPelsPerMeter = 0;
  264. bitmap_info.biClrUsed = 0;
  265. bitmap_info.biClrImportant = 0;
  266. // Get a temporary screen DC
  267. HDC hscreen_dc = ::GetDC (NULL);
  268. // Create a bitmap that we can access the bits directly of
  269. m_hBitmap = ::CreateDIBSection (hscreen_dc,
  270. (const BITMAPINFO *)&bitmap_info,
  271. DIB_RGB_COLORS,
  272. (void **)&m_pBits,
  273. NULL,
  274. 0L);
  275. // Release our temporary screen DC
  276. ::ReleaseDC (NULL, hscreen_dc);
  277. // Paint the color range into this bitmap
  278. Paint_DIB (m_iWidth, m_iHeight, m_pBits);
  279. return ;
  280. }
  281. /////////////////////////////////////////////////////////////////////////////
  282. //
  283. // Fill_Rect
  284. //
  285. /////////////////////////////////////////////////////////////////////////////
  286. void
  287. ColorPickerClass::Fill_Rect
  288. (
  289. UCHAR *pbits,
  290. const RECT &rect,
  291. COLORREF color,
  292. int scanline_size
  293. )
  294. {
  295. UCHAR red = GetRValue (color);
  296. UCHAR green = GetRValue (color);
  297. UCHAR blue = GetRValue (color);
  298. for (int irow = rect.top; irow < rect.bottom; irow ++) {
  299. int index = irow * scanline_size;
  300. index += (rect.left * 3);
  301. for (int col = rect.left; col < rect.right; col ++) {
  302. pbits[index++] = blue;
  303. pbits[index++] = green;
  304. pbits[index++] = red;
  305. }
  306. }
  307. return ;
  308. }
  309. /////////////////////////////////////////////////////////////////////////////
  310. //
  311. // Color_From_Point
  312. //
  313. /////////////////////////////////////////////////////////////////////////////
  314. COLORREF
  315. ColorPickerClass::Color_From_Point
  316. (
  317. int x,
  318. int y
  319. )
  320. {
  321. COLORREF color = RGB (0,0,0);
  322. // x,y location inside boundaries?
  323. if ((x >= 0) && (x < m_iWidth) &&
  324. (y >= 0) && (y < m_iHeight)) {
  325. // Window's bitmaps are DWORD aligned, so make sure
  326. // we take that into account.
  327. int alignment_offset = (m_iWidth * 3) % 4;
  328. alignment_offset = (alignment_offset != 0) ? (4 - alignment_offset) : 0;
  329. int scanline_size = (m_iWidth * 3) + alignment_offset;
  330. // Read the color value straight from the BMP
  331. int index = (scanline_size * y) + (x * 3);
  332. int blue = m_pBits[index];
  333. int green = m_pBits[index + 1];
  334. int red = m_pBits[index + 2];
  335. // Turn the individual compenents into a color
  336. color = RGB (red, green, blue);
  337. RECT rect;
  338. Calc_Display_Rect (rect);
  339. int width = rect.right-rect.left;
  340. m_CurrentHue = ((float)x) / ((float)width);
  341. }
  342. // Return the color
  343. return color;
  344. }
  345. /////////////////////////////////////////////////////////////////////////////
  346. //
  347. // Polar_To_Rect
  348. //
  349. /////////////////////////////////////////////////////////////////////////////
  350. void
  351. Polar_To_Rect (float radius, float angle, float &x, float &y)
  352. {
  353. x = radius * float(cos(angle));
  354. y = radius * float(sin(angle));
  355. return ;
  356. }
  357. /////////////////////////////////////////////////////////////////////////////
  358. //
  359. // Rect_To_Polar
  360. //
  361. /////////////////////////////////////////////////////////////////////////////
  362. void
  363. Rect_To_Polar (float x, float y, float &radius, float &angle)
  364. {
  365. if (x == 0 && y == 0) {
  366. radius = 0;
  367. angle = 0;
  368. } else {
  369. radius = (float)::sqrt ((x * x) + (y * y));
  370. angle = (float)::atan2 (y, x);
  371. }
  372. return ;
  373. }
  374. /////////////////////////////////////////////////////////////////////////////
  375. //
  376. // RGB_to_Hue
  377. //
  378. /////////////////////////////////////////////////////////////////////////////
  379. void
  380. RGB_to_Hue (int red_val, int green_val, int blue_val, float &hue, float &value)
  381. {
  382. float red_radius = (float)red_val;
  383. float green_radius = (float)green_val;
  384. float blue_radius = (float)blue_val;
  385. float red_angle = 0;
  386. float green_angle = (3.1415926535F * 2.0F) / 3.0F;
  387. float blue_angle = (3.1415926535F * 4.0F) / 3.0F;
  388. struct Color2D
  389. {
  390. float x;
  391. float y;
  392. };
  393. Color2D red = { 0 };
  394. Color2D green = { 0 };
  395. Color2D blue = { 0 };
  396. Color2D result = { 0 };
  397. ::Polar_To_Rect (red_radius, red_angle, red.x, red.y);
  398. ::Polar_To_Rect (green_radius, green_angle, green.x, green.y);
  399. ::Polar_To_Rect (blue_radius, blue_angle, blue.x, blue.y);
  400. result.x = red.x + green.x + blue.x;
  401. result.y = red.y + green.y + blue.y;
  402. float hue_angle = 0;
  403. float hue_radius = 0;
  404. ::Rect_To_Polar (result.x, result.y, hue_radius, hue_angle);
  405. hue = hue_angle / (3.14159265359F * 2.0F);
  406. if (hue < 0) {
  407. hue += 1;
  408. } else if (hue > 1) {
  409. hue -= 1;
  410. }
  411. value = (float)::fabs (hue_radius / 255);
  412. return ;
  413. }
  414. /////////////////////////////////////////////////////////////////////////////
  415. //
  416. // Point_From_Color
  417. //
  418. /////////////////////////////////////////////////////////////////////////////
  419. CPoint
  420. ColorPickerClass::Point_From_Color (COLORREF color)
  421. {
  422. // Window's bitmaps are DWORD aligned, so make sure
  423. // we take that into account.
  424. int alignment_offset = (m_iWidth * 3) % 4;
  425. alignment_offset = (alignment_offset != 0) ? (4 - alignment_offset) : 0;
  426. int scanline_size = (m_iWidth * 3) + alignment_offset;
  427. int red = GetRValue (color);
  428. int green = GetGValue (color);
  429. int blue = GetBValue (color);
  430. float hue = 0;
  431. float value = 0;
  432. RGB_to_Hue (red, green, blue, hue, value);
  433. RECT rect;
  434. Calc_Display_Rect (rect);
  435. int width = rect.right-rect.left;
  436. int height = rect.bottom-rect.top;
  437. float whiteness = (float)min (min (red, green), blue);
  438. float percent = whiteness / 255;
  439. float darkness = 0;
  440. //
  441. // Determine what the 'darkness' of the hue should be
  442. //
  443. if (percent != 1) {
  444. float start_red = (red - whiteness) / (1 - percent);
  445. float start_green = (green - whiteness) / (1 - percent);
  446. float start_blue = (blue - whiteness) / (1 - percent);
  447. darkness = max (max (start_red, start_green), start_blue);
  448. }
  449. int x = int(width * hue);
  450. int y = ((255 - (int)darkness) * height) / 255;
  451. // Return the point
  452. return CPoint (x, y);
  453. }
  454. /////////////////////////////////////////////////////////////////////////////
  455. //
  456. // Paint_DIB
  457. //
  458. /////////////////////////////////////////////////////////////////////////////
  459. void
  460. ColorPickerClass::Paint_DIB
  461. (
  462. int width,
  463. int height,
  464. UCHAR *pbits
  465. )
  466. {
  467. // Window's bitmaps are DWORD aligned, so make sure
  468. // we take that into account.
  469. int alignment_offset = (width * 3) % 4;
  470. alignment_offset = (alignment_offset != 0) ? (4 - alignment_offset) : 0;
  471. int scanline_size = (width * 3) + alignment_offset;
  472. //
  473. // Paint the border (if any)
  474. //
  475. CRect rect (0, 0, width, height);
  476. LONG lstyle = ::GetWindowLong (m_hWnd, GWL_STYLE);
  477. if (lstyle & CPS_SUNKEN) {
  478. ::Draw_Sunken_Rect (pbits, rect, scanline_size);
  479. rect.DeflateRect (1, 1);
  480. } else if (lstyle & CPS_RAISED) {
  481. ::Draw_Raised_Rect (pbits, rect, scanline_size);
  482. rect.DeflateRect (1, 1);
  483. } else if (lstyle & WS_BORDER) {
  484. ::Frame_Rect (pbits, rect, RGB (255, 255, 255), scanline_size);
  485. rect.DeflateRect (1, 1);
  486. }
  487. // Recalc the width and height (it could of changed)
  488. width = rect.Width ();
  489. height = rect.Height ();
  490. // Build an array of column indicies where we will switch color
  491. // components...
  492. int col_remainder = (width % 6);
  493. int channel_switch_cols[6];
  494. for (int channel = 0; channel < 6; channel ++) {
  495. // Each column has at least X/6 pixels
  496. channel_switch_cols[channel] = width / 6;
  497. // Do we need to add a remainder to this col?
  498. // (Occurs when the width isn't evenly divisible by 6)
  499. if (col_remainder > 0) {
  500. channel_switch_cols[channel] += 1;
  501. col_remainder --;
  502. }
  503. // Add the previous column's switching index
  504. if (channel > 0) {
  505. channel_switch_cols[channel] += channel_switch_cols[channel - 1];
  506. }
  507. }
  508. // Start with max red
  509. float red = 255.0F;
  510. float green = 0;
  511. float blue = 0;
  512. // Calculate some starting channel variables
  513. int curr_channel = 0;
  514. float curr_inc = (255.0F / ((float)channel_switch_cols[0]));
  515. float *pcurr_component = &green;
  516. //
  517. // Paint the image
  518. //
  519. for (int icol = rect.left; icol < rect.right; icol ++) {
  520. // Determine how much to 'darken' the current hue by for each row (goes to black)
  521. float red_dec = -((float)(red) / (float)(height-1));
  522. float green_dec = -((float)(green) / (float)(height-1));
  523. float blue_dec = -((float)(blue) / (float)(height-1));
  524. // Start with the normal hue color
  525. float curr_red = red;
  526. float curr_green = green;
  527. float curr_blue = blue;
  528. // Paint all pixels in this row
  529. int bitmap_index = (icol * 3) + (rect.left * scanline_size);
  530. for (int irow = rect.top; irow < rect.bottom; irow ++) {
  531. // Put these values into the bitmap
  532. pbits[bitmap_index] = UCHAR(((int)curr_blue) & 0xFF);
  533. pbits[bitmap_index + 1] = UCHAR(((int)curr_green) & 0xFF);
  534. pbits[bitmap_index + 2] = UCHAR(((int)curr_red) & 0xFF);
  535. // Determine the current red, green, and blue values
  536. curr_red = curr_red + red_dec;
  537. curr_green = curr_green + green_dec;
  538. curr_blue = curr_blue + blue_dec;
  539. // Increment our offset into the bitmap
  540. bitmap_index += scanline_size;
  541. }
  542. // Is it time to switch to a new color channel?
  543. if ((icol - rect.left) == channel_switch_cols[curr_channel]) {
  544. // Recompute values for the new channel
  545. curr_channel ++;
  546. curr_inc = (255.0F / ((float)(channel_switch_cols[curr_channel] - channel_switch_cols[curr_channel-1])));
  547. // Which channel are we painting?
  548. if (curr_channel == 1) {
  549. pcurr_component = &red;
  550. curr_inc = -curr_inc;
  551. } else if (curr_channel == 2) {
  552. pcurr_component = &blue;
  553. } else if (curr_channel == 3) {
  554. pcurr_component = &green;
  555. curr_inc = -curr_inc;
  556. } else if (curr_channel == 4) {
  557. pcurr_component = &red;
  558. } else if (curr_channel == 5) {
  559. pcurr_component = &blue;
  560. curr_inc = -curr_inc;
  561. }
  562. }
  563. // Increment the current color component
  564. (*pcurr_component) = (*pcurr_component) + curr_inc;
  565. }
  566. return ;
  567. }
  568. /////////////////////////////////////////////////////////////////////////////
  569. //
  570. // Free_Bitmap
  571. //
  572. /////////////////////////////////////////////////////////////////////////////
  573. void
  574. ColorPickerClass::Free_Bitmap (void)
  575. {
  576. if (m_hBitmap != NULL) {
  577. ::DeleteObject (m_hBitmap);
  578. m_hBitmap = NULL;
  579. m_pBits = NULL;
  580. }
  581. m_iWidth = 0;
  582. m_iHeight = 0;
  583. return ;
  584. }
  585. /////////////////////////////////////////////////////////////////////////////
  586. //
  587. // OnSize
  588. //
  589. /////////////////////////////////////////////////////////////////////////////
  590. void
  591. ColorPickerClass::OnSize
  592. (
  593. UINT nType,
  594. int cx,
  595. int cy
  596. )
  597. {
  598. // Allow the base class to process this message
  599. CWnd::OnSize (nType, cx, cy);
  600. // Recreate the BMP to reflect the new window size
  601. Create_Bitmap ();
  602. // Determine the new point based on the current color
  603. //m_CurrentColor = RGB (128, 222, 199);
  604. //m_CurrentPoint = Point_From_Color (m_CurrentColor);
  605. return ;
  606. }
  607. /////////////////////////////////////////////////////////////////////////////
  608. //
  609. // OnEraseBkgnd
  610. //
  611. /////////////////////////////////////////////////////////////////////////////
  612. BOOL
  613. ColorPickerClass::OnEraseBkgnd (CDC * /*pDC*/)
  614. {
  615. return TRUE;
  616. }
  617. /////////////////////////////////////////////////////////////////////////////
  618. //
  619. // OnLButtonDown
  620. //
  621. /////////////////////////////////////////////////////////////////////////////
  622. void
  623. ColorPickerClass::OnLButtonDown
  624. (
  625. UINT nFlags,
  626. CPoint point
  627. )
  628. {
  629. SetCapture ();
  630. m_bSelecting = true;
  631. RECT rect;
  632. Calc_Display_Rect (rect);
  633. ClientToScreen (&rect);
  634. ::ClipCursor (&rect);
  635. Erase_Marker ();
  636. m_CurrentPoint = point;
  637. m_CurrentColor = Color_From_Point (point.x, point.y);
  638. //
  639. // Notify the parent window that the user double-clicked
  640. // one of the keyframes
  641. //
  642. LONG id = ::GetWindowLong (m_hWnd, GWL_ID);
  643. CP_NMHDR notify_hdr = { 0 };
  644. notify_hdr.hdr.hwndFrom = m_hWnd;
  645. notify_hdr.hdr.idFrom = id;
  646. notify_hdr.hdr.code = CPN_COLORCHANGE;
  647. notify_hdr.red = GetRValue (m_CurrentColor);
  648. notify_hdr.green = GetGValue (m_CurrentColor);
  649. notify_hdr.blue = GetBValue (m_CurrentColor);
  650. notify_hdr.hue = m_CurrentHue;
  651. ::SendMessage (::GetParent (m_hWnd),
  652. WM_NOTIFY,
  653. id,
  654. (LPARAM)&notify_hdr);
  655. Paint_Marker ();
  656. // Allow the base class to process this message
  657. CWnd::OnLButtonDown (nFlags, point);
  658. return ;
  659. }
  660. /////////////////////////////////////////////////////////////////////////////
  661. //
  662. // OnLButtonUp
  663. //
  664. /////////////////////////////////////////////////////////////////////////////
  665. void
  666. ColorPickerClass::OnLButtonUp
  667. (
  668. UINT nFlags,
  669. CPoint point
  670. )
  671. {
  672. if (m_bSelecting) {
  673. ::ClipCursor (NULL);
  674. ReleaseCapture ();
  675. m_bSelecting = false;
  676. }
  677. // Allow the base class to process this message
  678. CWnd::OnLButtonUp (nFlags, point);
  679. return ;
  680. }
  681. /////////////////////////////////////////////////////////////////////////////
  682. //
  683. // OnMouseMove
  684. //
  685. /////////////////////////////////////////////////////////////////////////////
  686. void
  687. ColorPickerClass::OnMouseMove
  688. (
  689. UINT nFlags,
  690. CPoint point
  691. )
  692. {
  693. if (m_bSelecting) {
  694. Erase_Marker ();
  695. m_CurrentPoint = point;
  696. m_CurrentColor = Color_From_Point (point.x, point.y);
  697. //
  698. // Notify the parent window that the user double-clicked
  699. // one of the keyframes
  700. //
  701. LONG id = ::GetWindowLong (m_hWnd, GWL_ID);
  702. CP_NMHDR notify_hdr = { 0 };
  703. notify_hdr.hdr.hwndFrom = m_hWnd;
  704. notify_hdr.hdr.idFrom = id;
  705. notify_hdr.hdr.code = CPN_COLORCHANGE;
  706. notify_hdr.red = GetRValue (m_CurrentColor);
  707. notify_hdr.green = GetGValue (m_CurrentColor);
  708. notify_hdr.blue = GetBValue (m_CurrentColor);
  709. notify_hdr.hue = m_CurrentHue;
  710. ::SendMessage (::GetParent (m_hWnd),
  711. WM_NOTIFY,
  712. id,
  713. (LPARAM)&notify_hdr);
  714. Paint_Marker ();
  715. }
  716. // Allow the base class to process this message
  717. CWnd::OnMouseMove (nFlags, point);
  718. return ;
  719. }
  720. /////////////////////////////////////////////////////////////////////////////
  721. //
  722. // Calc_Display_Rect
  723. //
  724. /////////////////////////////////////////////////////////////////////////////
  725. void
  726. ColorPickerClass::Calc_Display_Rect (RECT &rect)
  727. {
  728. GetClientRect (&rect);
  729. LONG lstyle = ::GetWindowLong (m_hWnd, GWL_STYLE);
  730. if ((lstyle & CPS_SUNKEN) || (lstyle & CPS_RAISED) || (lstyle & WS_BORDER)) {
  731. rect.left += 1;
  732. rect.right -= 1;
  733. rect.top += 1;
  734. rect.bottom -= 1;
  735. }
  736. return ;
  737. }
  738. /////////////////////////////////////////////////////////////////////////////
  739. //
  740. // Erase_Marker
  741. //
  742. /////////////////////////////////////////////////////////////////////////////
  743. void
  744. ColorPickerClass::Erase_Marker (void)
  745. {
  746. HDC hdc = ::GetDC (m_hWnd);
  747. if (m_hMemDC != NULL) {
  748. HBITMAP hold_bmp = (HBITMAP)::SelectObject (m_hMemDC, m_hBitmap);
  749. CRect rect;
  750. GetClientRect (&rect);
  751. ::BitBlt (hdc,
  752. m_CurrentPoint.x - 5,
  753. m_CurrentPoint.y - 5,
  754. 11,
  755. 11,
  756. m_hMemDC,
  757. m_CurrentPoint.x - 5,
  758. m_CurrentPoint.y - 5,
  759. SRCCOPY);
  760. ::SelectObject (m_hMemDC, hold_bmp);
  761. }
  762. ::ReleaseDC (m_hWnd, hdc);
  763. return ;
  764. }
  765. /////////////////////////////////////////////////////////////////////////////
  766. //
  767. // Paint_Marker
  768. //
  769. /////////////////////////////////////////////////////////////////////////////
  770. void
  771. ColorPickerClass::Paint_Marker (void)
  772. {
  773. HDC hdc = ::GetDC (m_hWnd);
  774. if (m_hMemDC != NULL) {
  775. HBITMAP hmarker_bmp = ::LoadBitmap (_hinstance, MAKEINTRESOURCE (IDB_MARKER));
  776. HBITMAP hold_bmp = (HBITMAP)::SelectObject (m_hMemDC, hmarker_bmp);
  777. CRect rect;
  778. GetClientRect (&rect);
  779. ::BitBlt (hdc,
  780. m_CurrentPoint.x - 5,
  781. m_CurrentPoint.y - 5,
  782. 11,
  783. 11,
  784. m_hMemDC,
  785. 0,
  786. 0,
  787. SRCINVERT);
  788. ::SelectObject (m_hMemDC, hold_bmp);
  789. ::DeleteObject (hmarker_bmp);
  790. }
  791. ::ReleaseDC (m_hWnd, hdc);
  792. return ;
  793. }
  794. /////////////////////////////////////////////////////////////////////////////
  795. //
  796. // Select_Color
  797. //
  798. /////////////////////////////////////////////////////////////////////////////
  799. void
  800. ColorPickerClass::Select_Color (int red, int green, int blue)
  801. {
  802. m_CurrentColor = RGB (red, green, blue);
  803. m_CurrentPoint = Point_From_Color (m_CurrentColor);
  804. m_CurrentColor = Color_From_Point (m_CurrentPoint.x, m_CurrentPoint.y);
  805. // Refresh the window
  806. InvalidateRect (NULL, FALSE);
  807. UpdateWindow ();
  808. return ;
  809. }
  810. /////////////////////////////////////////////////////////////////////////////
  811. //
  812. // Get_Current_Color
  813. //
  814. /////////////////////////////////////////////////////////////////////////////
  815. void
  816. ColorPickerClass::Get_Current_Color (int *red, int *green, int *blue)
  817. {
  818. (*red) = GetRValue (m_CurrentColor);
  819. (*green) = GetGValue (m_CurrentColor);
  820. (*blue) = GetBValue (m_CurrentColor);
  821. return ;
  822. }