GME
13
|
00001 // ColorBtn.cpp : implementation file 00002 00003 #include "stdafx.h" 00004 #include "ColorBtn.h" 00005 00006 #ifdef _DEBUG 00007 #define new DEBUG_NEW 00008 #undef THIS_FILE 00009 static char THIS_FILE[] = __FILE__; 00010 #endif 00011 00012 // The color table, initialized to windows' 20 static colors 00013 00014 COLORREF CColorBtnDlg::colors[20] = 00015 { 00016 RGB(0,0,0), 00017 RGB(128,0,0), 00018 RGB(0,128,0), 00019 RGB(128,128,0), 00020 RGB(0,0,128), 00021 RGB(128,0,128), 00022 RGB(0,128,128), 00023 RGB(192,192,192), 00024 RGB(192,220,192), 00025 RGB(166,202,240), 00026 RGB(255,251,240), 00027 RGB(160,160,164), 00028 RGB(128,128,128), 00029 RGB(255,0,0), 00030 RGB(0,255,0), 00031 RGB(255,255,0), 00032 RGB(0,0,255), 00033 RGB(255,0,255), 00034 RGB(0,255,255), 00035 RGB(255,255,255) 00036 }; 00037 00038 // MRU table. See notes for Reset() 00039 00040 BYTE CColorBtnDlg::used[20] = 00041 { 00042 1,3,5,7,9,11,13,15,17,19,20,18,16,14,12,10,8,6,4,2 00043 }; 00044 00046 // CColorBtn 00047 00048 CColorBtn::CColorBtn() 00049 { 00050 currentcolor = RGB(255,255,255); 00051 00052 dlg.parent = this; // This will allow the dialog to position itself 00053 00054 // Create the pens and brushes that we'll need to draw the button 00055 00056 nullpen.CreateStockObject(NULL_PEN); 00057 blackpen.CreateStockObject(BLACK_PEN); 00058 whitepen.CreateStockObject(WHITE_PEN); 00059 00060 nullbrush.CreateStockObject(NULL_BRUSH); 00061 backbrush.CreateSolidBrush(GetSysColor(COLOR_3DFACE)); 00062 dkgray.CreatePen(PS_SOLID,1,RGB(128,128,128)); 00063 } 00064 00065 00066 CColorBtn::~CColorBtn() 00067 { 00068 } 00069 00070 00071 BEGIN_MESSAGE_MAP(CColorBtn, CButton) 00072 //{{AFX_MSG_MAP(CColorBtn) 00073 ON_CONTROL_REFLECT(BN_CLICKED, OnClicked) 00074 //}}AFX_MSG_MAP 00075 END_MESSAGE_MAP() 00076 00078 // CColorBtn message handlers 00079 00080 00081 void CColorBtn::DrawItem(LPDRAWITEMSTRUCT lpd) 00082 { 00083 // Draw the button 00084 00085 CBrush colorbrush; 00086 00087 CDC DC; 00088 00089 DC.Attach(lpd->hDC); 00090 00091 int top,left,bottom,right; 00092 00093 // Store this for convinience 00094 00095 top = lpd->rcItem.top; 00096 left = lpd->rcItem.left; 00097 bottom = lpd->rcItem.bottom; 00098 right = lpd->rcItem.right; 00099 00100 colorbrush.CreateSolidBrush(currentcolor); 00101 00102 oldpen = DC.SelectObject(&nullpen); 00103 oldbrush = DC.SelectObject(&backbrush); 00104 00105 // Clear the background using the 3DFACE color. 00106 00107 DC.Rectangle(&lpd->rcItem); 00108 00109 // Draw the border 00110 00111 if (!(lpd->itemState & ODS_SELECTED)) 00112 { 00113 // Button is up 00114 00115 DC.SelectObject(&blackpen); 00116 00117 DC.MoveTo(left,bottom-1); 00118 DC.LineTo(right-1,bottom-1); 00119 DC.LineTo(right-1,top); 00120 00121 DC.SelectObject(&dkgray); 00122 00123 DC.MoveTo(left+1,bottom-2); 00124 DC.LineTo(right-2,bottom-2); 00125 DC.LineTo(right-2,top+1); 00126 00127 DC.SelectObject(&whitepen); 00128 00129 DC.LineTo(left+1,top+1); 00130 DC.LineTo(left+1,bottom-2); 00131 00132 } 00133 else 00134 { 00135 // Button is down 00136 00137 DC.SelectObject(&dkgray); 00138 00139 DC.MoveTo(left,bottom-1); 00140 00141 DC.LineTo(left,top); 00142 DC.LineTo(right-1,top); 00143 00144 DC.SelectObject(&whitepen); 00145 00146 DC.MoveTo(right-1,top-1); 00147 00148 DC.LineTo(right-1,bottom-1); 00149 DC.LineTo(left+1,bottom-1); 00150 00151 DC.SelectObject(&blackpen); 00152 00153 DC.MoveTo(left+1,bottom-2); 00154 DC.LineTo(left+1,top+1); 00155 DC.LineTo(right-2,top+1); 00156 00157 // by moving this, we get the things inside the button 00158 // to draw themselves one pixel down and one to the right. 00159 // This completes the "pushed" effect 00160 00161 left++; 00162 right++; 00163 bottom++; 00164 top++; 00165 00166 } 00167 00168 // The division 00169 00170 DC.SelectObject(&whitepen); 00171 00172 DC.MoveTo(right-10,top+4); 00173 DC.LineTo(right-10,bottom-4); 00174 00175 DC.SelectObject(dkgray); 00176 00177 DC.MoveTo(right-11,top+4); 00178 DC.LineTo(right-11,bottom-4); 00179 00180 // The triangle 00181 00182 if (lpd->itemState & ODS_DISABLED) 00183 DC.SelectObject(dkgray); 00184 else 00185 DC.SelectObject(blackpen); 00186 00187 DC.MoveTo(right-4,(bottom/2)-1); 00188 DC.LineTo(right-9,(bottom/2)-1); 00189 00190 DC.MoveTo(right-5,(bottom/2)); 00191 DC.LineTo(right-8,(bottom/2)); 00192 00193 if (lpd->itemState & ODS_DISABLED) 00194 { 00195 DC.SetPixel(right-4,(bottom/2)-1,RGB(255,255,255)); 00196 DC.SetPixel(right-5,(bottom/2),RGB(255,255,255)); 00197 DC.SetPixel(right-6,(bottom/2)+1,RGB(255,255,255)); 00198 } 00199 else 00200 { 00201 DC.SetPixel(right-6,(bottom/2)+1,RGB(0,0,0)); 00202 } 00203 00204 if (!(lpd->itemState & ODS_DISABLED)) 00205 { 00206 // The color rectangle, only if enabled 00207 00208 DC.SelectObject(&colorbrush); 00209 00210 DC.Rectangle(left+5,top+4,right-15,bottom-4); 00211 } 00212 00213 if (lpd->itemState & ODS_FOCUS) 00214 { 00215 // Draw the focus 00216 // 00217 // It would have been nice just to 00218 // draw a rectangle using a pen created 00219 // with the PS_ALTERNATE style, but 00220 // this is not supported by WIN95 00221 00222 int i; 00223 00224 for (i=left+3;i<right-4;i+=2) 00225 { 00226 DC.SetPixel(i,top+3,RGB(0,0,0)); 00227 DC.SetPixel(i,bottom-4,RGB(0,0,0)); 00228 } 00229 00230 for (i=top+3;i<bottom-4;i+=2) 00231 { 00232 DC.SetPixel(left+3,i,RGB(0,0,0)); 00233 DC.SetPixel(right-4,i,RGB(0,0,0)); 00234 } 00235 } 00236 00237 DC.SelectObject(oldpen); 00238 DC.SelectObject(oldbrush); 00239 00240 00241 DC.Detach(); 00242 } 00243 00244 00245 void CColorBtn::OnClicked() 00246 { 00247 // When the button is clicked, show the dialog. 00248 00249 if (dlg.DoModal() == IDOK) 00250 { 00251 currentcolor = CColorBtnDlg::colors[dlg.colorindex]; 00252 InvalidateRect(NULL); 00253 } 00254 } 00255 00256 // Store and Load use an undocumented CWinApp function 00257 00258 BOOL CColorBtn::Store() 00259 { 00260 return (AfxGetApp()->WriteProfileBinary(_T("ColorData"), _T("ColorTable"),(LPBYTE)CColorBtnDlg::colors,sizeof(COLORREF)*20) && 00261 AfxGetApp()->WriteProfileBinary(_T("ColorData"), _T("MRU"),CColorBtnDlg::used,sizeof(CColorBtnDlg::used))); 00262 00263 } 00264 00265 BOOL CColorBtn::Load() 00266 { 00267 BYTE *data = NULL; 00268 UINT size; 00269 00270 // This function allocates the memory it needs 00271 00272 AfxGetApp()->GetProfileBinary(_T("ColorData"), _T("ColorTable"),&data,&size); 00273 00274 if (data) 00275 { 00276 // Copy the data into our table and get rid of the buffer 00277 00278 memcpy((void *)CColorBtnDlg::colors,(void *)data,size); 00279 free((void *)data); 00280 00281 AfxGetApp()->GetProfileBinary(_T("ColorData"), _T("MRU"),&data,&size); 00282 00283 if (data) 00284 { 00285 memcpy((void *)CColorBtnDlg::used,(void *)data,size); 00286 free((void *)data); 00287 return TRUE; 00288 } 00289 00290 } 00291 00292 // If the loading fails, back to the defaults 00293 00294 Reset(); 00295 00296 return FALSE; 00297 } 00298 00299 00300 void CColorBtn::Reset() 00301 { 00302 CColorBtnDlg::colors[0] = RGB(0,0,0); 00303 CColorBtnDlg::colors[1] = RGB(128,0,0); 00304 CColorBtnDlg::colors[2] = RGB(0,128,0); 00305 CColorBtnDlg::colors[3] = RGB(128,128,0); 00306 CColorBtnDlg::colors[4] = RGB(0,0,128); 00307 CColorBtnDlg::colors[5] = RGB(128,0,128); 00308 CColorBtnDlg::colors[6] = RGB(0,128,128); 00309 CColorBtnDlg::colors[7] = RGB(192,192,192); 00310 CColorBtnDlg::colors[8] = RGB(192,220,192); 00311 CColorBtnDlg::colors[9] = RGB(166,202,240); 00312 CColorBtnDlg::colors[10] = RGB(255,251,240); 00313 CColorBtnDlg::colors[11] = RGB(160,160,164); 00314 CColorBtnDlg::colors[12] = RGB(128,128,128); 00315 CColorBtnDlg::colors[13] = RGB(255,0,0); 00316 CColorBtnDlg::colors[14] = RGB(0,255,0); 00317 CColorBtnDlg::colors[15] = RGB(255,255,0); 00318 CColorBtnDlg::colors[16] = RGB(0,0,255); 00319 CColorBtnDlg::colors[17] = RGB(255,0,255); 00320 CColorBtnDlg::colors[18] = RGB(0,255,255); 00321 CColorBtnDlg::colors[19] = RGB(255,255,255); 00322 00323 // This "colorful" (no pun intended) order ensures 00324 // that the colors at the center of the color table 00325 // will get replaced first. This preserves the white 00326 // and black colors even if they're not used (They'll 00327 // get replaced last). 00328 00329 CColorBtnDlg::used[0]= 1; 00330 CColorBtnDlg::used[1]= 3; 00331 CColorBtnDlg::used[2]= 5; 00332 CColorBtnDlg::used[3]= 7; 00333 CColorBtnDlg::used[4]= 9; 00334 CColorBtnDlg::used[5]= 11; 00335 CColorBtnDlg::used[6]= 13; 00336 CColorBtnDlg::used[7]= 15; 00337 CColorBtnDlg::used[8]= 17; 00338 CColorBtnDlg::used[9]= 19; 00339 CColorBtnDlg::used[10]= 20; 00340 CColorBtnDlg::used[11]= 18; 00341 CColorBtnDlg::used[12]= 16; 00342 CColorBtnDlg::used[13]= 14; 00343 CColorBtnDlg::used[14]= 12; 00344 CColorBtnDlg::used[15]= 10; 00345 CColorBtnDlg::used[16]= 8; 00346 CColorBtnDlg::used[17]= 6; 00347 CColorBtnDlg::used[18]= 4; 00348 CColorBtnDlg::used[19]= 2; 00349 } 00350 00351 00352 void CColorBtn::Serialize( CArchive& ar ) 00353 { 00354 if (ar.IsStoring()) 00355 { 00356 ar.Write((void *)CColorBtnDlg::colors,sizeof(COLORREF)*20); 00357 ar.Write((void *)CColorBtnDlg::used,sizeof(BYTE)*20); 00358 } 00359 else 00360 { 00361 ar.Read((void *)CColorBtnDlg::colors,sizeof(COLORREF)*20); 00362 ar.Read((void *)CColorBtnDlg::used,sizeof(BYTE)*20); 00363 } 00364 } 00365 00366 00367 00368 00370 // CColorBtnDlg dialog 00371 00372 00373 CColorBtnDlg::CColorBtnDlg(CWnd* pParent /*=NULL*/) 00374 : CDialog(CColorBtnDlg::IDD, pParent) 00375 { 00376 //{{AFX_DATA_INIT(CColorBtnDlg) 00377 // NOTE: the ClassWizard will add member initialization here 00378 //}}AFX_DATA_INIT 00379 } 00380 00381 00382 void CColorBtnDlg::DoDataExchange(CDataExchange* pDX) 00383 { 00384 CDialog::DoDataExchange(pDX); 00385 //{{AFX_DATA_MAP(CColorBtnDlg) 00386 // NOTE: the ClassWizard will add DDX and DDV calls here 00387 //}}AFX_DATA_MAP 00388 } 00389 00390 00391 BEGIN_MESSAGE_MAP(CColorBtnDlg, CDialog) 00392 //{{AFX_MSG_MAP(CColorBtnDlg) 00393 ON_BN_CLICKED(IDC_OTHER, OnOther) 00394 ON_WM_LBUTTONDOWN() 00395 ON_WM_LBUTTONUP() 00396 ON_WM_DRAWITEM() 00397 //}}AFX_MSG_MAP 00398 ON_COMMAND_RANGE(IDC_COLOR1,IDC_COLOR20,OnColor) 00399 END_MESSAGE_MAP() 00400 00401 00403 // CColorBtnDlg message handlers 00404 00405 BOOL CColorBtnDlg::OnInitDialog() 00406 { 00407 CDialog::OnInitDialog(); 00408 00409 RECT r, r2; 00410 00411 parent->GetWindowRect(&r); 00412 00413 // Move the dialog to be below the button 00414 00415 SetWindowPos(NULL, r.left, r.bottom, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 00416 00417 GetWindowRect(&r2); 00418 00419 // Check to see if the dialog has a portion outside the screen, if so, adjust. 00420 // 00421 // Beware of multi monitor systems! GetSystemMetrics(SM_CYSCREEN) and GetSystemMetrics(SM_CXSCREEN) is just for the primary screen! 00422 // We will use the dimensions of the virtual screen area (composed by the multiple monitors), 00423 // but we assume rectangular area, so if the area is composed by different resolution monitors this safety code 00424 // can be also misleading, but 99% it will be good. For more info see MSDN chapters about multiple monitor displays: 00425 // http://msdn.microsoft.com/en-us/library/ms534611(VS.85).aspx 00426 00427 int virtualScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN); 00428 int virtualScreenTop = GetSystemMetrics(SM_YVIRTUALSCREEN); 00429 int virtualScreenRight = virtualScreenLeft + GetSystemMetrics(SM_CXVIRTUALSCREEN); 00430 int virtualScreenBottom = virtualScreenTop + GetSystemMetrics(SM_CYVIRTUALSCREEN); 00431 if (r2.bottom > virtualScreenBottom) { 00432 r2.top = virtualScreenBottom - (r2.bottom - r2.top); 00433 } 00434 if (r2.top < virtualScreenTop) 00435 r2.top = virtualScreenTop; 00436 00437 if (r2.right > virtualScreenRight) { 00438 r2.left = virtualScreenRight - (r2.right - r2.left); 00439 } 00440 if (r2.left < virtualScreenLeft) 00441 r2.left = virtualScreenLeft; 00442 00443 SetWindowPos(NULL, r2.left, r2.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 00444 00445 // Capture the mouse, this allows the dialog to close when 00446 // the user clicks outside. 00447 00448 // Remember that the dialog has no "close" button. 00449 00450 SetCapture(); 00451 00452 return TRUE; 00453 } 00454 00455 00456 00457 void CColorBtnDlg::EndDialog( int nResult ) 00458 { 00459 ReleaseCapture(); 00460 00461 CDialog::EndDialog(nResult); 00462 } 00463 00464 00465 void CColorBtnDlg::OnLButtonDown(UINT nFlags, CPoint point) 00466 { 00467 RECT r; 00468 00469 POINT p; 00470 p.x = point.x; 00471 p.y = point.y; 00472 00473 ClientToScreen(&p); 00474 00475 GetWindowRect(&r); 00476 00477 // The user clicked... 00478 00479 if (!PtInRect(&r,p)) 00480 { 00481 // ...outside the dialog, close. 00482 00483 EndDialog(IDCANCEL); 00484 } 00485 else 00486 { 00487 // ...inside the dialog. Since this window 00488 // has the mouse captured, its children 00489 // get no messages. So, check to see 00490 // if the click was in one of its children 00491 // and tell him. 00492 00493 // If the user clicks inside the dialog 00494 // but not on any of the controls, 00495 // ChildWindowFromPoint returns a 00496 // pointer to the dialog. In this 00497 // case we do not resend the message 00498 // (obviously) because it would cause 00499 // a stack overflow. 00500 00501 CWnd *child = ChildWindowFromPoint(point); 00502 00503 if (child && child != this) 00504 child->SendMessage(WM_LBUTTONDOWN,0,0l); 00505 } 00506 00507 CDialog::OnLButtonDown(nFlags, point); 00508 } 00509 00510 00511 void CColorBtnDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpd) 00512 { 00513 CDC dc; 00514 CPen nullpen; 00515 CBrush brush; 00516 CPen *oldpen; 00517 CBrush *oldbrush; 00518 00519 // Draw the wells using the current color table 00520 00521 nullpen.CreateStockObject(NULL_PEN); 00522 brush.CreateSolidBrush(colors[nIDCtl-IDC_COLOR1]); 00523 00524 dc.Attach(lpd->hDC); 00525 00526 oldpen = dc.SelectObject(&nullpen); 00527 oldbrush = dc.SelectObject(&brush); 00528 00529 lpd->rcItem.right++; 00530 lpd->rcItem.bottom++; 00531 00532 dc.Rectangle(&lpd->rcItem); 00533 00534 dc.SelectObject(oldpen); 00535 dc.SelectObject(oldbrush); 00536 00537 dc.Detach(); 00538 00539 CDialog::OnDrawItem(nIDCtl, lpd); 00540 } 00541 00542 00543 void CColorBtnDlg::OnColor(UINT id) 00544 { 00545 00546 // A well has been clicked, set the color index 00547 // and close. 00548 00549 colorindex = id-IDC_COLOR1; 00550 00551 int i; 00552 00553 // This color is now the MRU 00554 00555 for (i=0;i<20;i++) 00556 { 00557 if (used[colorindex] > used[i]) 00558 { 00559 used[i]++; 00560 } 00561 } 00562 00563 used[colorindex] = 1; 00564 00565 EndDialog(IDOK); 00566 00567 } 00568 00569 void CColorBtnDlg::OnOther() 00570 { 00571 int i; 00572 COLORREF newcolor; 00573 00574 // The "Other" button. 00575 00576 ReleaseCapture(); 00577 00578 CColorDialog dlg; 00579 00580 dlg.m_cc.Flags |= CC_FULLOPEN; 00581 00582 00583 if (dlg.DoModal() == IDOK) 00584 { 00585 // The user clicked OK. 00586 // set the color and close 00587 00588 newcolor = dlg.GetColor(); 00589 00590 // Check to see if the selected color is 00591 // already in the table. 00592 00593 colorindex = -1; 00594 00595 for (i=0;i<20;i++) 00596 { 00597 if (colors[i] == newcolor) 00598 { 00599 colorindex = i; 00600 break; 00601 } 00602 } 00603 00604 // If the color was not found, 00605 // replace the LRU with this color 00606 00607 if (colorindex == -1) 00608 { 00609 for (i=0;i<20;i++) 00610 { 00611 if (used[i] == 20) 00612 { 00613 colors[i] = newcolor; 00614 colorindex = i; 00615 break; 00616 } 00617 } 00618 } 00619 00620 // This is the new MRU 00621 00622 for (i=0;i<20;i++) 00623 { 00624 if (used[colorindex] > used[i]) 00625 { 00626 used[i]++; 00627 } 00628 } 00629 00630 used[colorindex] = 1; 00631 00632 EndDialog(IDOK); 00633 00634 return; 00635 } 00636 00637 // If the user clicked "Cancel" reclaim the mouse capture. 00638 00639 SetCapture(); 00640 } 00641 00642 00643 void CColorBtnDlg::OnLButtonUp(UINT nFlags, CPoint point) 00644 { 00645 00646 // See notes for OnLButtonDown. 00647 00648 CWnd *child = ChildWindowFromPoint(point,CWP_ALL); 00649 00650 if (child && child != this) 00651 child->SendMessage(WM_LBUTTONDOWN,0,0l); 00652 00653 CDialog::OnLButtonUp(nFlags, point); 00654 } 00655 00656