GME  13
colorbtn.cpp
Go to the documentation of this file.
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