BCMenu.cpp
上传用户:aphuaqiang
上传日期:2007-01-02
资源大小:62k
文件大小:41k
源码类别:

菜单

开发平台:

Visual C++

  1. //*************************************************************************
  2. // BCMenu.cpp : implementation file
  3. // Version : 2.4
  4. // Date : Feb 11, 1999
  5. // Author : Brent Corkum
  6. // 
  7. // Portions of code supplied by:
  8. // Ben Ashley,Girish Bharadwaj,Jean-Edouard Lachand-Robert,
  9. // Robert Edward Caldecott,Kenny Goers,Leonardo Zide,
  10. // Stefan Kuhr
  11. //
  12. // Bug Fixes:
  13. // Stefan Kuhr,Martin Vladic,Kim Yoo Chul
  14. //
  15. // You are free to use/modify this code but leave this header intact.
  16. //
  17. #include "stdafx.h"        // Standard windows header file
  18. #include "BCMenu.h"        // BCMenu class declaration
  19. #include <afxpriv.h>       //SK: makes A2W and other spiffy AFX macros work
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. #define GAP 1
  26. #ifndef OBM_CHECK
  27. #define OBM_CHECK 32760 // from winuser.h
  28. #endif
  29. #if _MFC_VER <0x400
  30. #error This code does not work on Versions of MFC prior to 4.0
  31. #endif
  32. static CPINFO CPInfo;
  33. enum Win32Type{
  34. Win32s,
  35. Windoze95,
  36. WinNT3,
  37. WinNT4orHigher
  38. };
  39. Win32Type IsShellType()
  40. {
  41.   Win32Type  ShellType;
  42.   DWORD winVer;
  43.   OSVERSIONINFO *osvi;
  44.   winVer=GetVersion();
  45.   if(winVer<0x80000000){/*NT */
  46.     ShellType=WinNT3;
  47.     osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
  48.     if (osvi!=NULL){
  49.       memset(osvi,0,sizeof(OSVERSIONINFO));
  50.       osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
  51.       GetVersionEx(osvi);
  52.       if (osvi->dwMajorVersion>=4L)
  53.         ShellType=WinNT4orHigher;//yup, it is NT 4 or higher!
  54.       free(osvi);
  55.     }
  56.   }
  57.   else if  (LOBYTE(LOWORD(winVer))<4)
  58.     ShellType=Win32s;/*Win32s*/
  59.   else
  60.     ShellType=Windoze95;/*Windoze95*/
  61.   return ShellType;
  62. }
  63. static Win32Type g_Shell=IsShellType();
  64. void BCMenuData::SetAnsiString(LPCSTR szAnsiString)
  65. {
  66. ASSERT(szAnsiString);
  67. USES_CONVERSION;
  68. SetWideString(A2W(szAnsiString));  //SK:  see MFC Tech Note 059
  69. }
  70. CString BCMenuData::GetString(void)//returns the menu text in ANSI or UNICODE
  71. //depending on the MFC-Version we are using
  72. {
  73. CString strText;
  74. if (m_szMenuText)
  75.     {
  76. #ifdef UNICODE
  77.     strText = m_szMenuText;
  78. #else
  79. USES_CONVERSION;
  80.     strText=W2A(m_szMenuText);     //SK:  see MFC Tech Note 059
  81. #endif    
  82.     }
  83. return strText;
  84. }
  85. /*
  86.  
  87. ===============================================================================
  88.   BCMenu::BCMenu()
  89.   TCMeny::~BCMenu()
  90.   -----------------
  91.   Constructor and Destructor.
  92.  
  93. ===============================================================================
  94. */
  95. BCMenu::BCMenu()
  96. {
  97.   disable_old_style=FALSE;
  98.   m_iconX = 16;            // Icon sizes default to 16 x 16
  99.   m_iconY = 15;            // ...
  100.   m_selectcheck = -1;
  101.   m_unselectcheck = -1;
  102.   checkmaps=NULL;
  103.   checkmapsshare=FALSE;
  104.   // set the color used for the transparent background in all bitmaps
  105.   m_bitmapBackground=RGB(192,192,192); //gray
  106.   m_bitmapBackgroundFlag=FALSE;
  107.   GetCPInfo(CP_ACP,&CPInfo);
  108. }
  109. BCMenu::~BCMenu()
  110. {
  111.   DestroyMenu();
  112. }
  113. BOOL BCMenu::IsNewShell ()
  114. {
  115. return (Windoze95==g_Shell || WinNT4orHigher==g_Shell);
  116. }
  117. BCMenuData::~BCMenuData()
  118. {
  119.   if(bitmap)
  120.     delete(bitmap);
  121.   delete[] m_szMenuText; //Need not check for NULL because ANSI X3J16 allows "delete NULL"
  122. }
  123. void BCMenuData::SetWideString(const wchar_t *szWideString)
  124. {
  125. delete[] m_szMenuText;//Need not check for NULL because ANSI X3J16 allows "delete NULL"
  126. if (szWideString)
  127.     {
  128.     m_szMenuText = new wchar_t[sizeof(wchar_t)*(wcslen(szWideString)+1)];
  129.     if (m_szMenuText)
  130.         wcscpy(m_szMenuText,szWideString);
  131.     }
  132. else
  133.     m_szMenuText=NULL;//set to NULL so we need not bother about dangling non-NULL Ptrs
  134. }
  135. BOOL BCMenu::IsMenu(CMenu *submenu)
  136. {
  137.   int m;
  138.   int numSubMenus = m_SubMenus.GetUpperBound();
  139.   for(m=0;m<=numSubMenus;++m){
  140.     if(submenu==m_SubMenus[m])return(TRUE);
  141.   }
  142.   return(FALSE);
  143. }
  144. BOOL BCMenu::DestroyMenu()
  145. {
  146.   // Destroy Sub menus:
  147.   int m;
  148.   int numSubMenus = m_SubMenus.GetUpperBound();
  149.   for(m = numSubMenus; m >= 0; m--)delete(m_SubMenus[m]);
  150.   m_SubMenus.RemoveAll();
  151.   // Destroy menu data
  152.   int numItems = m_MenuList.GetUpperBound();
  153.   for(m = 0; m <= numItems; m++)delete(m_MenuList[m]);
  154.   m_MenuList.RemoveAll();
  155.   if(checkmaps&&!checkmapsshare){
  156.     delete checkmaps;
  157.     checkmaps=NULL;
  158.   }
  159.   // Call base-class implementation last:
  160.   return(CMenu::DestroyMenu());
  161. };
  162. ///////////////////////////////////////////////////////////////////////////
  163. //
  164. // BCMenu message handlers
  165. /*
  166. ==========================================================================
  167. void BCMenu::DrawItem(LPDRAWITEMSTRUCT)
  168. ---------------------------------------
  169. Called by the framework when a particular item needs to be drawn.  We
  170. overide this to draw the menu item in a custom-fashion, including icons
  171. and the 3D rectangle bar.
  172. ==========================================================================
  173. */
  174. void BCMenu::DrawItem (LPDRAWITEMSTRUCT lpDIS)
  175. {
  176.   ASSERT(lpDIS != NULL);
  177.   CDC* pDC = CDC::FromHandle(lpDIS->hDC);
  178.   CRect rect;
  179.   UINT state = (((BCMenuData*)(lpDIS->itemData))->nFlags);
  180.   if(state & MF_SEPARATOR){
  181.     rect.CopyRect(&lpDIS->rcItem);
  182.     rect.top+=rect.Height()>>1;
  183.     pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
  184.   }
  185.   else{
  186.     CRect rect2;
  187.     BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
  188.     BOOL checkflag=FALSE;
  189.     CBitmap bitmapstandard;
  190.     COLORREF crText = GetSysColor(COLOR_MENUTEXT);
  191.     COLORREF m_clrBack=GetSysColor(COLOR_MENU);
  192.     CBrush m_brBackground,m_brSelect;
  193.     CPen m_penBack;
  194.     int x0,y0,dy;
  195.     int nIconNormal=-1,xoffset=-1;
  196.     CImageList *bitmap=NULL;
  197.     CFont m_fontMenu;
  198.     LOGFONT m_lf;
  199.     // set some colors and the font
  200.     m_penBack.CreatePen (PS_SOLID,0,GetSysColor(COLOR_MENU));
  201.     m_brBackground.CreateSolidBrush(GetSysColor(COLOR_MENU));
  202.     m_brSelect.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
  203.     ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
  204.     NONCLIENTMETRICS nm;
  205.     nm.cbSize = sizeof (NONCLIENTMETRICS);
  206.     VERIFY (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); 
  207.     m_lf =  nm.lfMenuFont;
  208.     m_fontMenu.CreateFontIndirect (&m_lf);
  209.     // draw the colored rectangle portion
  210.   
  211.     rect.CopyRect(&lpDIS->rcItem);
  212.     rect2=rect;
  213.  
  214.     // draw the up/down/focused/disabled state
  215.     UINT action = lpDIS->itemAction;
  216.     UINT state = lpDIS->itemState;
  217.     CString strText;
  218.     LOGFONT lf;
  219.     lf = m_lf;
  220.     CFont dispFont;
  221.     CFont *pFont=NULL;
  222.       
  223.     if(lpDIS->itemData != NULL){
  224.       nIconNormal = (((BCMenuData*)(lpDIS->itemData))->menuIconNormal);
  225.       xoffset = (((BCMenuData*)(lpDIS->itemData))->xoffset);
  226.       bitmap = (((BCMenuData*)(lpDIS->itemData))->bitmap);
  227.       strText = ((BCMenuData*) (lpDIS->itemData))->GetString();
  228.     
  229.       if(state&ODS_CHECKED && nIconNormal<0){
  230.         if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
  231.         else if(m_unselectcheck>0) checkflag=TRUE;
  232.       }
  233.       else if(nIconNormal != -1){
  234.         standardflag=TRUE;
  235.         if(state&ODS_SELECTED && !(state&ODS_GRAYED))selectedflag=TRUE;
  236.         else if(state&ODS_GRAYED) disableflag=TRUE;
  237.       }
  238.     }
  239.     else{
  240.       strText.Empty();
  241.     }
  242.     if(state&ODS_SELECTED){ // draw the down edges
  243.       CPen *pOldPen = pDC->SelectObject (&m_penBack);
  244.       // You need only Text highlight and thats what you get
  245.      
  246.       if(checkflag||standardflag||selectedflag||disableflag||state&ODS_CHECKED)
  247.         rect2.SetRect(rect.left+m_iconX+4+GAP,rect.top,rect.right,rect.bottom);
  248.       pDC->FillRect (rect2,&m_brSelect);
  249.       pDC->SelectObject (pOldPen);
  250.       if((HFONT)dispFont != NULL)dispFont.DeleteObject ();
  251.       dispFont.CreateFontIndirect (&lf);
  252.       crText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  253.     }
  254.     else {
  255.       CPen *pOldPen = pDC->SelectObject (&m_penBack);
  256.       pDC->FillRect (rect,&m_brBackground);
  257.       pDC->SelectObject (pOldPen);
  258.       // draw the up edges
  259.       pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
  260.       if ((HFONT)dispFont != NULL) dispFont.DeleteObject ();
  261.       dispFont.CreateFontIndirect (&lf); //Normal
  262.     }
  263.     // draw the text if there is any
  264.     //We have to paint the text only if the image is nonexistant
  265.     dy = (rect.Height()-4-m_iconY)/2;
  266.     dy = dy<0 ? 0 : dy;
  267.     if(checkflag||standardflag||selectedflag||disableflag){
  268.       rect2.SetRect(rect.left+1,rect.top+1+dy,rect.left+m_iconX+3,
  269.                     rect.top+m_iconY+3+dy);
  270.       pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
  271.       if(checkflag && checkmaps){
  272.         pDC->FillRect (rect2,&m_brBackground);
  273.         rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
  274.                       rect.top+m_iconY+4+dy);
  275.         
  276. pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
  277.         CPoint ptImage(rect.left+2,rect.top+2+dy);
  278.        
  279.         if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
  280.         else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
  281.       }
  282.       else if(disableflag){
  283.         if(!selectedflag){
  284.           HBITMAP hbmp=LoadSysColorBitmap(nIconNormal);
  285.           if(hbmp){
  286.             bitmapstandard.Attach(hbmp);
  287.             rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
  288.                           rect.top+m_iconY+4+dy);
  289.             pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
  290.             if(disable_old_style)
  291.               DitherBlt(lpDIS->hDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
  292.                        (HBITMAP)(bitmapstandard),xoffset*m_iconX,0);
  293.             else
  294.               DitherBlt2(pDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
  295.                          bitmapstandard,xoffset*m_iconX,0);
  296.             bitmapstandard.DeleteObject();
  297.           }
  298.         }
  299.       }
  300.       else if(selectedflag){
  301.         pDC->FillRect (rect2,&m_brBackground);
  302.         rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
  303.                       rect.top+m_iconY+4+dy);
  304.         if (IsNewShell()){
  305.           if(state&ODS_CHECKED)
  306.             pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
  307.                             GetSysColor(COLOR_3DHILIGHT));
  308.           else
  309.             pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DHILIGHT),
  310.                             GetSysColor(COLOR_3DSHADOW));
  311.         }
  312.         CPoint ptImage(rect.left+2,rect.top+2+dy);
  313.         if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
  314.       }
  315.       else{
  316.         if(state&ODS_CHECKED){
  317.           CBrush brush;
  318.           COLORREF col =GetSysColor(COLOR_3DLIGHT);
  319.           brush.CreateSolidBrush(col);
  320.           pDC->FillRect(rect2,&brush);
  321.           brush.DeleteObject();
  322.           rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
  323.                         rect.top+m_iconY+4+dy);
  324.           if (IsNewShell())
  325.             pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
  326.                             GetSysColor(COLOR_3DHILIGHT));
  327.         }
  328.         else{
  329.           pDC->FillRect (rect2,&m_brBackground);
  330.           rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
  331.                         rect.top+m_iconY+4+dy);
  332.           pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
  333.         }
  334.         CPoint ptImage(rect.left+2,rect.top+2+dy);
  335.         if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
  336.       }
  337.     }
  338.     if(nIconNormal<0 && state&ODS_CHECKED && !checkflag){
  339.       rect2.SetRect(rect.left+1,rect.top+2+dy,rect.left+m_iconX+1,
  340.                     rect.top+m_iconY+2+dy);
  341.       CMenuItemInfo info;
  342.       info.fMask = MIIM_CHECKMARKS;
  343.       ::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
  344.                       MF_BYCOMMAND, &info);
  345.       if(state&ODS_CHECKED || info.hbmpUnchecked) {
  346.         Draw3DCheckmark(pDC, rect2, state&ODS_SELECTED,
  347.                         state&ODS_CHECKED ? info.hbmpChecked :
  348.                         info.hbmpUnchecked);
  349.       }
  350.     }
  351.     //This is needed always so that we can have the space for check marks
  352.     x0=rect.left;y0=rect.top;
  353.     rect.left = rect.left + m_iconX + 8 + GAP; 
  354.     if(!strText.IsEmpty()){
  355.       CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);
  356.       //   Find tabs
  357.       CString leftStr,rightStr;
  358.       leftStr.Empty();rightStr.Empty();
  359.       int tablocr=strText.ReverseFind(_T('t'));
  360.       if(tablocr!=-1){
  361.         rightStr=strText.Mid(tablocr+1);
  362.         leftStr=strText.Left(strText.Find(_T('t')));
  363.         rectt.right-=m_iconX;
  364.       }
  365.       else leftStr=strText;
  366.       int iOldMode = pDC->GetBkMode();
  367.       pDC->SetBkMode( TRANSPARENT);
  368.       // Draw the text in the correct colour:
  369.       UINT nFormat  = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
  370.       UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
  371.       if(!(lpDIS->itemState & ODS_GRAYED)){
  372.         pDC->SetTextColor(crText);
  373.         pDC->DrawText (leftStr,rectt,nFormat);
  374.         if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
  375.       }
  376.       else{
  377.         // Draw the disabled text
  378.         if(!(state & ODS_SELECTED)){
  379.           RECT offset = *rectt;
  380.           offset.left+=1;
  381.           offset.right+=1;
  382.           offset.top+=1;
  383.           offset.bottom+=1;
  384.           pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));
  385.           pDC->DrawText(leftStr,&offset, nFormat);
  386.           if(tablocr!=-1) pDC->DrawText (rightStr,&offset,nFormatr);
  387.           pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
  388.           pDC->DrawText(leftStr,rectt, nFormat);
  389.           if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
  390.         }
  391.         else{
  392.         // And the standard Grey text:
  393.           pDC->SetTextColor(m_clrBack);
  394.           pDC->DrawText(leftStr,rectt, nFormat);
  395.           if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
  396.         }
  397.       }
  398.       pFont = pDC->SelectObject (&dispFont);
  399.       pDC->SetBkMode( iOldMode );
  400.       pDC->SelectObject (pFont); //set it to the old font
  401.     }
  402.     m_penBack.DeleteObject();
  403.     m_brBackground.DeleteObject();
  404.     m_fontMenu.DeleteObject();
  405.     m_brSelect.DeleteObject();
  406.     dispFont.DeleteObject ();
  407.   }
  408. }
  409. /*
  410. ==========================================================================
  411. void BCMenu::MeasureItem(LPMEASUREITEMSTRUCT)
  412. ---------------------------------------------
  413. Called by the framework when it wants to know what the width and height
  414. of our item will be.  To accomplish this we provide the width of the
  415. icon plus the width of the menu text, and then the height of the icon.
  416.  
  417. ==========================================================================
  418. */
  419. void BCMenu::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
  420. {
  421.   UINT state = (((BCMenuData*)(lpMIS->itemData))->nFlags);
  422.   if(state & MF_SEPARATOR){
  423.     lpMIS->itemWidth = 0;
  424.     lpMIS->itemHeight = GetSystemMetrics(SM_CYMENU)>>1;
  425.   }
  426.   else{
  427.     CFont m_fontMenu;
  428.     LOGFONT m_lf;
  429.     ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
  430.     NONCLIENTMETRICS nm;
  431.     nm.cbSize = sizeof (NONCLIENTMETRICS);
  432.     VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
  433.            nm.cbSize,&nm,0)); 
  434.     m_lf =  nm.lfMenuFont;
  435.     m_fontMenu.CreateFontIndirect (&m_lf);
  436.     // Obtain the width of the text:
  437.     CWnd *pWnd = AfxGetMainWnd();            // Get main window
  438.     CDC *pDC = pWnd->GetDC();              // Get device context
  439.     CFont* pFont=NULL;    // Select menu font in...
  440.     
  441.     if (IsNewShell())
  442.         pFont = pDC->SelectObject (&m_fontMenu);// Select menu font in...
  443.         
  444.     //Get pointer to text SK
  445.     const wchar_t *lpstrText = ((BCMenuData*)(lpMIS->itemData))->GetWideString();//SK: we use const to prevent misuse
  446.     
  447.         
  448.     SIZE size;
  449.     if (Win32s!=g_Shell)
  450.       VERIFY(::GetTextExtentPoint32W(pDC->m_hDC,lpstrText,
  451.              wcslen(lpstrText),&size)); //SK should also work on 95
  452. #ifndef UNICODE //can't be UNICODE for Win32s
  453.     else{//it's Win32suckx
  454.       RECT rect;
  455.       rect.left=rect.top=0;
  456.       size.cy=DrawText(pDC->m_hDC,(LPCTSTR)lpstrText,
  457.                        wcslen(lpstrText),&rect,
  458.                        DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CALCRECT);
  459.       //+3 makes at least three pixels space to the menu border
  460.       size.cx=rect.right-rect.left+3;
  461.       size.cx += 3*(size.cx/wcslen(lpstrText));
  462.     }
  463. #endif    
  464.     CSize t = CSize(size);
  465.     if(IsNewShell())
  466.       pDC->SelectObject (pFont);  // Select old font in
  467.     AfxGetMainWnd()->ReleaseDC(pDC);  // Release the DC
  468.     // Set width and height:
  469.     lpMIS->itemWidth = m_iconX + t.cx + m_iconX + GAP;
  470.     int temp = GetSystemMetrics(SM_CYMENU);
  471.     lpMIS->itemHeight = temp>m_iconY+4 ? temp : m_iconY+4;
  472.     m_fontMenu.DeleteObject();
  473.   }
  474. }
  475. void BCMenu::SetIconSize (int width, int height)
  476. {
  477.   m_iconX = width;
  478.   m_iconY = height;
  479. }
  480. BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
  481.                            int nIconNormal)
  482. {
  483. ASSERT(lpstrText);
  484. USES_CONVERSION;
  485. return AppendODMenuW(A2W(lpstrText),nFlags,nID,nIconNormal);//SK: See MFC Tech Note 059
  486. }
  487. BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
  488.                            int nIconNormal)
  489. {
  490.   // Add the MF_OWNERDRAW flag if not specified:
  491.   ASSERT(lpstrText);
  492.   if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW;
  493.   else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
  494.   BCMenuData *mdata = new BCMenuData;
  495.   m_MenuList.Add(mdata);
  496.   mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation
  497.   
  498.   mdata->menuIconNormal = nIconNormal;
  499.   mdata->xoffset=-1;
  500.   if(nIconNormal>=0){
  501.     mdata->xoffset=0;
  502.     LoadFromToolBar(nID,nIconNormal,mdata->xoffset);
  503.     if(mdata->bitmap)mdata->bitmap->DeleteImageList();
  504.     else mdata->bitmap=new(CImageList);
  505.     mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
  506.     AddBitmapToImageList(mdata->bitmap,nIconNormal);
  507.   }
  508.   mdata->nFlags = nFlags;
  509.   mdata->nID = nID;
  510.   return(CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata));
  511. }
  512. BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,int nIconNormal)
  513. {
  514. USES_CONVERSION;
  515. return ModifyODMenuW(A2W(lpstrText),nID,nIconNormal);//SK: see MFC Tech Note 059
  516. }
  517. BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,int nIconNormal)
  518. {
  519.   int nLoc;
  520.   BCMenuData *mdata;
  521.   // Find the old BCMenuData structure:
  522.   BCMenu *psubmenu = FindMenuOption(nID,nLoc);
  523.   if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
  524.   else{
  525.   // Create a new BCMenuData structure:
  526.     mdata = new BCMenuData;
  527.     m_MenuList.Add(mdata);
  528.   }
  529.   ASSERT(mdata);
  530.   if(lpstrText)
  531.      mdata->SetWideString(lpstrText);  //SK: modified for dynamic allocation
  532.   mdata->menuIconNormal = nIconNormal;
  533.   mdata->xoffset=-1;
  534.   if(nIconNormal>=0){
  535.     mdata->xoffset=0;
  536.     LoadFromToolBar(nID,nIconNormal,mdata->xoffset);
  537.     if(mdata->bitmap)mdata->bitmap->DeleteImageList();
  538.     else mdata->bitmap=new(CImageList);
  539.     mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
  540.     AddBitmapToImageList(mdata->bitmap,nIconNormal);
  541.   }
  542.   mdata->nFlags = MF_BYCOMMAND | MF_OWNERDRAW;
  543.   mdata->nID = nID;
  544.   return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
  545. }
  546. BOOL BCMenu::ModifyODMenuA(const char *lpstrText,const char *OptionText,
  547.                            int nIconNormal)
  548. {
  549. USES_CONVERSION;
  550. return ModifyODMenuW(A2W(lpstrText),A2W(OptionText),nIconNormal);//SK: see MFC  Tech Note 059
  551. }
  552. BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,wchar_t *OptionText,
  553.                            int nIconNormal)
  554. {
  555.   BCMenuData *mdata;
  556.   // Find the old BCMenuData structure:
  557.   CString junk=OptionText;
  558.   mdata=FindMenuOption(OptionText);
  559.   if(mdata){
  560.     if(lpstrText)
  561.         mdata->SetWideString(lpstrText);//SK: modified for dynamic allocation
  562.     mdata->menuIconNormal = nIconNormal;
  563.     mdata->xoffset=-1;
  564.     if(nIconNormal>=0){
  565.       mdata->xoffset=0;
  566.       if(mdata->bitmap)mdata->bitmap->DeleteImageList();
  567.       else mdata->bitmap=new(CImageList);
  568.       mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
  569.       AddBitmapToImageList(mdata->bitmap,nIconNormal);
  570.     }
  571.     return(TRUE);
  572.   }
  573.   return(FALSE);
  574. }
  575. BCMenuData *BCMenu::NewODMenu(UINT pos,UINT nFlags,UINT nID,CString string)
  576. {
  577.   BCMenuData *mdata;
  578.   mdata = new BCMenuData;
  579.   mdata->menuIconNormal = -1;
  580.   mdata->xoffset=-1;
  581.   #ifdef UNICODE
  582.   mdata->SetWideString((LPCTSTR)string);//SK: modified for dynamic allocation
  583.   #else
  584.   mdata->SetAnsiString(string);
  585.   #endif
  586.   mdata->nFlags = nFlags;
  587.   mdata->nID = nID;
  588.   
  589.   
  590.   if (nFlags&MF_OWNERDRAW){
  591.     ASSERT(!(nFlags&MF_STRING));
  592.     ModifyMenu(pos,nFlags,nID,(LPCTSTR)mdata);
  593.   }
  594.   else if (nFlags&MF_STRING){
  595.     ASSERT(!(nFlags&MF_OWNERDRAW));
  596.     ModifyMenu(pos,nFlags,nID,mdata->GetString());
  597.   }
  598.   else{
  599.     ASSERT(nFlags&MF_SEPARATOR);
  600.     ModifyMenu(pos,nFlags,nID);
  601.   }
  602.   return(mdata);
  603. };
  604. BOOL BCMenu::LoadToolbars(const UINT *arID,int n)
  605. {
  606.   ASSERT(arID);
  607.   BOOL returnflag=TRUE;
  608.   for(int i=0;i<n;++i){
  609.     if(!LoadToolbar(arID[i]))returnflag=FALSE;
  610.   }
  611.   return(returnflag);
  612. }
  613. BOOL BCMenu::LoadToolbar(UINT nToolBar)
  614. {
  615.   UINT nID;
  616.   BOOL returnflag=FALSE;
  617.   CToolBar bar;
  618.   bar.Create(AfxGetMainWnd());
  619.   if(bar.LoadToolBar(nToolBar)){
  620.     for(int i=0;i<bar.GetCount();++i){
  621.       nID = bar.GetItemID(i); 
  622.       if(nID && GetMenuState(nID, MF_BYCOMMAND)
  623.         !=0xFFFFFFFF)ModifyODMenu(NULL,nID,nToolBar);
  624.     }
  625.     returnflag=TRUE;
  626.   }
  627.   return(returnflag);
  628. }
  629. BOOL BCMenu::LoadFromToolBar(UINT nID,UINT nToolBar,int& xoffset)
  630. {
  631.   int xset,offset;
  632.   UINT nStyle;
  633.   BOOL returnflag=FALSE;
  634.   CToolBar bar;
  635.   bar.Create(AfxGetMainWnd());
  636.   if(bar.LoadToolBar(nToolBar)){
  637.     offset=bar.CommandToIndex(nID);
  638.     if(offset>=0){
  639.       bar.GetButtonInfo(offset,nID,nStyle,xset);
  640.       if(xset>0)xoffset=xset;
  641.       returnflag=TRUE;
  642.     }
  643.   }
  644.   return(returnflag);
  645. }
  646. BCMenu *BCMenu::FindMenuOption(int nId,int& nLoc)
  647. {
  648.   int i;
  649.   BCMenu *psubmenu,*pgoodmenu;
  650.   for(i=0;i<(int)(GetMenuItemCount());++i){
  651. #ifdef _CPPRTTI 
  652.     psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
  653. #else
  654.     psubmenu=(BCMenu *)GetSubMenu(i);
  655. #endif
  656.     if(psubmenu){
  657.       pgoodmenu=psubmenu->FindMenuOption(nId,nLoc);
  658.       if(pgoodmenu)return(pgoodmenu);
  659.     }
  660.     else if(nId==(int)GetMenuItemID(i)){
  661.       nLoc=i;
  662.       return(this);
  663.     }
  664.   }
  665.   nLoc = -1;
  666.   return(NULL);
  667. }
  668. BCMenuData *BCMenu::FindMenuOption(wchar_t *lpstrText)
  669. {
  670.   int i,j;
  671.   BCMenu *psubmenu;
  672.   BCMenuData *pmenulist;
  673.   for(i=0;i<(int)(GetMenuItemCount());++i){
  674. #ifdef _CPPRTTI 
  675.     psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
  676. #else
  677.     psubmenu=(BCMenu *)GetSubMenu(i);
  678. #endif
  679.     if(psubmenu){
  680.       pmenulist=psubmenu->FindMenuOption(lpstrText);
  681.       if(pmenulist)return(pmenulist);
  682.     }
  683.     else{
  684.       const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
  685.       for(j=0;j<=m_MenuList.GetUpperBound();++j){     
  686.         szWide = m_MenuList[j]->GetWideString ();
  687.         if(szWide && !wcscmp(lpstrText,szWide))//SK: modified for dynamic allocation
  688.           return(m_MenuList[j]);
  689.       }
  690.     }
  691.   }
  692.   return(NULL);
  693. }
  694. BOOL BCMenu::LoadMenu(int nResource)
  695. {
  696.   return(BCMenu::LoadMenu(MAKEINTRESOURCE(nResource)));
  697. };
  698. BOOL BCMenu::LoadMenu(LPCTSTR lpszResourceName)
  699. {
  700.   TRACE(_T(
  701.     "IMPORTANT:Use BCMenu::DestroyMenu to destroy Loaded Menu'sn"));
  702.   ASSERT_VALID(this);
  703.   ASSERT(lpszResourceName != NULL);
  704.   // Find the Menu Resource:
  705.   HINSTANCE m_hInst = AfxFindResourceHandle(lpszResourceName,RT_MENU);
  706.   HRSRC hRsrc = ::FindResource(m_hInst,lpszResourceName,RT_MENU);
  707.   if(hRsrc == NULL)return FALSE;
  708.   // Get size of resource:
  709.   DWORD dwSize = SizeofResource(NULL, hRsrc);
  710.   // Load the Menu Resource:
  711.   HGLOBAL hGlobal = LoadResource(m_hInst, hRsrc);
  712.   if(hGlobal == NULL)return FALSE;
  713.   // Attempt to create us as a menu...
  714.   if(!CMenu::CreateMenu())return FALSE;
  715.   // Get Item template Header, and calculate offset of MENUITEMTEMPLATES
  716.   MENUITEMTEMPLATEHEADER *pTpHdr=
  717.     (MENUITEMTEMPLATEHEADER*)LockResource(hGlobal);
  718.   BYTE* pTp=(BYTE*)pTpHdr + 
  719.     (sizeof(MENUITEMTEMPLATEHEADER) + pTpHdr->offset);
  720.   // Variables needed during processing of Menu Item Templates:
  721.   int j=0;
  722.   BCMenuData*  pData = NULL;              // New OD Menu Item Data
  723.   WORD    dwFlags = 0;              // Flags of the Menu Item
  724.   WORD    dwID  = 0;              // ID of the Menu Item
  725.   UINT    uFlags;                  // Actual Flags.
  726.   wchar_t *szCaption=NULL;
  727.   int      nLen   = 0;                // Length of caption
  728.   CTypedPtrArray<CPtrArray, BCMenu*>  m_Stack;    // Popup menu stack
  729.   CArray<BOOL,BOOL>  m_StackEnd;    // Popup menu stack
  730.   m_Stack.Add(this);                  // Add it to this...
  731.   m_StackEnd.Add(FALSE);
  732.   do{
  733.     // Obtain Flags and (if necessary), the ID...
  734.     memcpy(&dwFlags, pTp, sizeof(WORD));pTp+=sizeof(WORD);// Obtain Flags
  735.     if(!(dwFlags & MF_POPUP)){
  736.       memcpy(&dwID, pTp, sizeof(WORD)); // Obtain ID
  737.       pTp+=sizeof(WORD);
  738.     }
  739.     else dwID = 0;
  740.     uFlags = (UINT)dwFlags; // Remove MF_END from the flags that will
  741.     if(uFlags & MF_END) // be passed to the Append(OD)Menu functions.
  742.       uFlags -= MF_END;
  743.     // Obtain Caption (and length)
  744.     nLen = 0;
  745.     char *ch = (char*)pTp;
  746.     szCaption=new wchar_t[wcslen((wchar_t *)pTp)+1];
  747.     wcscpy(szCaption,(wchar_t *)pTp);
  748.     pTp=&pTp[(wcslen((wchar_t *)pTp)+1)*sizeof(wchar_t)];//modified SK
  749.     
  750.     // Handle popup menus first....
  751.     //WideCharToMultiByte
  752.     if(dwFlags & MF_POPUP){
  753.       if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
  754.       BCMenu* pSubMenu = new BCMenu;
  755.       pSubMenu->m_unselectcheck=m_unselectcheck;
  756.       pSubMenu->m_selectcheck=m_selectcheck;
  757.       pSubMenu->checkmaps=checkmaps;
  758.       pSubMenu->checkmapsshare=TRUE;
  759.       pSubMenu->CreatePopupMenu();
  760.       // Append it to the top of the stack:
  761.       m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption,uFlags,
  762.         (UINT)pSubMenu->m_hMenu, -1);
  763.       m_Stack.Add(pSubMenu);
  764.       m_StackEnd.Add(FALSE);
  765.       m_SubMenus.Add(pSubMenu);
  766.     }
  767.     else {
  768.       m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption, uFlags,
  769.         dwID, -1);
  770.       if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
  771.       j = m_Stack.GetUpperBound();
  772.       while(j>=0 && m_StackEnd.GetAt(j)){
  773.         m_Stack[m_Stack.GetUpperBound()]->InsertSpaces();
  774.         m_Stack.RemoveAt(j);
  775.         m_StackEnd.RemoveAt(j);
  776.         --j;
  777.       }
  778.     }
  779.     delete[] szCaption;
  780.   }while(m_Stack.GetUpperBound() != -1);
  781.   for(int i=0;i<(int)GetMenuItemCount();++i){
  782.     CString str=m_MenuList[i]->GetString();
  783.     if(GetSubMenu(i)){
  784.       m_MenuList[i]->nFlags=MF_POPUP|MF_BYPOSITION;
  785.       ModifyMenu(i,MF_POPUP|MF_BYPOSITION,
  786.         (UINT)GetSubMenu(i)->m_hMenu,str);
  787.     }
  788.     else{
  789.       m_MenuList[i]->nFlags=MF_STRING|MF_BYPOSITION;
  790.       ModifyMenu(i,MF_STRING|MF_BYPOSITION,m_MenuList[i]->nID,str);
  791.     }
  792.   }
  793.   
  794.   return(TRUE);
  795. }
  796. void BCMenu::InsertSpaces(void)
  797. {
  798.   int i,j,numitems,maxlength;
  799.   CString string,newstring;
  800.   CSize t;
  801.   CFont m_fontMenu;
  802.   LOGFONT m_lf;
  803.   ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
  804.   NONCLIENTMETRICS nm;
  805.   nm.cbSize = sizeof (NONCLIENTMETRICS);
  806.   VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); 
  807.   m_lf =  nm.lfMenuFont;
  808.   m_fontMenu.CreateFontIndirect (&m_lf);
  809.   CWnd *pWnd = AfxGetMainWnd();  
  810.   CDC *pDC = pWnd->GetDC();
  811.   CFont* pFont = pDC->SelectObject (&m_fontMenu);
  812.   
  813.   numitems=GetMenuItemCount();
  814.   maxlength = -1;
  815.   for(i=0;i<numitems;++i){
  816.     string=m_MenuList[i]->GetString();
  817.     j=string.Find((char)9);
  818.     newstring.Empty();
  819.     if(j!=-1)newstring=string.Left(j);
  820.     else newstring=string;
  821.     newstring+=_T(" ");//SK: modified for Unicode correctness. 
  822.     LPCTSTR lpstrText = (LPCTSTR)newstring;
  823.     t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
  824.     if(t.cx>maxlength)maxlength = t.cx;
  825.   }
  826.   for(i=0;i<numitems;++i){
  827.     string=m_MenuList[i]->GetString();
  828.     j=string.Find((char)9);
  829.     if(j!=-1){
  830.       newstring.Empty();
  831.       newstring=string.Left(j);
  832.       LPCTSTR lpstrText = (LPCTSTR)(newstring);
  833.       t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
  834.       while(t.cx<maxlength){
  835.         newstring+=_T(' ');//SK: modified for Unicode correctness
  836.         LPCTSTR lpstrText = (LPCTSTR)(newstring);
  837.         t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
  838.       }
  839.       newstring+=string.Mid(j);
  840. #ifdef UNICODE      
  841.       m_MenuList[i]->SetWideString(newstring);//SK: modified for dynamic allocation
  842. #else
  843.       m_MenuList[i]->SetAnsiString(newstring);
  844. #endif
  845.     }
  846.   }
  847.   pDC->SelectObject (pFont);              // Select old font in
  848.   AfxGetMainWnd()->ReleaseDC(pDC);       // Release the DC
  849.   m_fontMenu.DeleteObject();
  850. }
  851. void BCMenu::LoadCheckmarkBitmap(int unselect, int select)
  852. {
  853.   if(unselect>0 && select>0){
  854.     m_selectcheck=select;
  855.     m_unselectcheck=unselect;
  856.     if(checkmaps)checkmaps->DeleteImageList();
  857.     else checkmaps=new(CImageList);
  858.     checkmaps->Create(m_iconX,m_iconY,ILC_MASK,2,1);
  859.     AddBitmapToImageList(checkmaps,unselect);
  860.     AddBitmapToImageList(checkmaps,select);
  861.   }
  862. }
  863. BOOL BCMenu::GetMenuText(UINT id, CString& string)
  864. {
  865.   BOOL returnflag=FALSE;
  866.   UINT numMenuItems = m_MenuList.GetUpperBound();
  867.   if(id<=numMenuItems){
  868.     string=m_MenuList[id]->GetString();
  869.     returnflag=TRUE;
  870.   }
  871.   return(returnflag);
  872. }
  873. void BCMenu::DrawRadioDot(CDC *pDC,int x,int y,COLORREF color)
  874. {
  875.   CRect rcDot(x,y,x+6,y+6);
  876.   CBrush brush;
  877.   CPen pen;
  878.   brush.CreateSolidBrush(color);
  879.   pen.CreatePen(PS_SOLID,0,color);
  880.   pDC->SelectObject(&brush);
  881.   pDC->SelectObject(&pen);
  882.   pDC->Ellipse(&rcDot);
  883.   pen.DeleteObject();
  884.   brush.DeleteObject();
  885. }
  886. void BCMenu::DrawCheckMark(CDC* pDC,int x,int y,COLORREF color)
  887. {
  888.   pDC->SetPixel(x,y+2,color);
  889.   pDC->SetPixel(x,y+3,color);
  890.   pDC->SetPixel(x,y+4,color);
  891.   pDC->SetPixel(x+1,y+3,color);
  892.   pDC->SetPixel(x+1,y+4,color);
  893.   pDC->SetPixel(x+1,y+5,color);
  894.   pDC->SetPixel(x+2,y+4,color);
  895.   pDC->SetPixel(x+2,y+5,color);
  896.   pDC->SetPixel(x+2,y+6,color);
  897.   pDC->SetPixel(x+3,y+3,color);
  898.   pDC->SetPixel(x+3,y+4,color);
  899.   pDC->SetPixel(x+3,y+5,color);
  900.   pDC->SetPixel(x+4,y+2,color);
  901.   pDC->SetPixel(x+4,y+3,color);
  902.   pDC->SetPixel(x+4,y+4,color);
  903.   pDC->SetPixel(x+5,y+1,color);
  904.   pDC->SetPixel(x+5,y+2,color);
  905.   pDC->SetPixel(x+5,y+3,color);
  906.   pDC->SetPixel(x+6,y,color);
  907.   pDC->SetPixel(x+6,y+1,color);
  908.   pDC->SetPixel(x+6,y+2,color);
  909. }
  910. BCMenuData *BCMenu::FindMenuList(UINT nID)
  911. {
  912.   for(int i=0;i<=m_MenuList.GetUpperBound();++i){
  913.     if(m_MenuList[i]->nID==nID && !m_MenuList[i]->syncflag){
  914.       m_MenuList[i]->syncflag=1;
  915.       return(m_MenuList[i]);
  916.     }
  917.   }
  918.   return(NULL);
  919. }
  920. void BCMenu::InitializeMenuList(int value)
  921. {
  922.   for(int i=0;i<=m_MenuList.GetUpperBound();++i)
  923.     m_MenuList[i]->syncflag=value;
  924. }
  925. void BCMenu::DeleteMenuList(void)
  926. {
  927.   for(int i=0;i<=m_MenuList.GetUpperBound();++i){
  928.     if(!m_MenuList[i]->syncflag){
  929.       delete m_MenuList[i];
  930.     }
  931.   }
  932. }
  933. void BCMenu::SynchronizeMenu(void)
  934. {
  935.   CTypedPtrArray<CPtrArray, BCMenuData*> temp;
  936.   BCMenuData *mdata;
  937.   CString string;
  938.   UINT submenu,nID=0,state,j;
  939.   InitializeMenuList(0);
  940.   for(j=0;j<GetMenuItemCount();++j){
  941.     mdata=NULL;
  942.     state=GetMenuState(j,MF_BYPOSITION);
  943.     if(state&MF_POPUP){
  944.       submenu=(UINT)GetSubMenu(j)->m_hMenu;
  945.       mdata=FindMenuList(submenu);
  946.       GetMenuString(j,string,MF_BYPOSITION);
  947.       if(!mdata)mdata=NewODMenu(j,
  948.         (state&0xFF)|MF_BYPOSITION|MF_POPUP|MF_OWNERDRAW,submenu,string);
  949.       else if(string.GetLength()>0)
  950. #ifdef UNICODE
  951.         mdata->SetWideString(string);  //SK: modified for dynamic allocation
  952. #else
  953.         mdata->SetAnsiString(string);
  954. #endif
  955.     }
  956.     else if(state&MF_SEPARATOR){
  957.       mdata=FindMenuList(0);
  958.       if(!mdata)mdata=NewODMenu(j,
  959.         state|MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW,0,_T(""));//SK: modified for Unicode correctness
  960.       else ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
  961.     }
  962.     else{
  963.       nID=GetMenuItemID(j);
  964.       mdata=FindMenuList(nID);
  965.       GetMenuString(j,string,MF_BYPOSITION);
  966.       if(!mdata)mdata=NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,
  967.         nID,string);
  968.       else{
  969.         mdata->nFlags=state|MF_BYPOSITION|MF_OWNERDRAW;
  970.         if(string.GetLength()>0)
  971. #ifdef UNICODE
  972.     mdata->SetWideString(string);//SK: modified for dynamic allocation
  973. #else
  974.             mdata->SetAnsiString(string);
  975. #endif
  976.             
  977.         ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
  978.       }
  979.     }
  980.     if(mdata)temp.Add(mdata);
  981.   }
  982.   DeleteMenuList();
  983.   m_MenuList.RemoveAll();
  984.   m_MenuList.Append(temp);
  985.   temp.RemoveAll(); 
  986. }
  987. void BCMenu::UpdateMenu(CMenu *pmenu)
  988. {
  989. #ifdef _CPPRTTI 
  990.   BCMenu *psubmenu = dynamic_cast<BCMenu *>(pmenu);
  991. #else
  992.   BCMenu *psubmenu = (BCMenu *)pmenu;
  993. #endif
  994.   if(psubmenu)psubmenu->SynchronizeMenu();
  995. }
  996. LRESULT BCMenu::FindKeyboardShortcut(UINT nChar, UINT nFlags,
  997.                                      CMenu *pMenu)
  998. {
  999. #ifdef _CPPRTTI 
  1000.   BCMenu *pBCMenu = dynamic_cast<BCMenu *>(pMenu);
  1001. #else
  1002.   BCMenu *pBCMenu = (BCMenu *)pMenu;
  1003. #endif
  1004.   if(pBCMenu && nFlags&MF_POPUP){
  1005.     CString key(_T('&'),2);//SK: modified for Unicode correctness
  1006. key.SetAt(1,(TCHAR)nChar);
  1007. key.MakeLower();
  1008.     CString menutext;
  1009.     int menusize = (int)pBCMenu->GetMenuItemCount();
  1010.     if(menusize!=(pBCMenu->m_MenuList.GetUpperBound()+1))
  1011.       pBCMenu->SynchronizeMenu();
  1012.     for(int i=0;i<menusize;++i){
  1013.       if(pBCMenu->GetMenuText(i,menutext)){
  1014.         menutext.MakeLower();
  1015.         if(menutext.Find(key)>=0)return(MAKELRESULT(i,2));
  1016.       }
  1017.     }
  1018.   }
  1019.   return(0);
  1020. }
  1021. void BCMenu::DitherBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth, 
  1022.                         int nHeight, HBITMAP hbm, int nXSrc, int nYSrc)
  1023. {
  1024.   ASSERT(hdcDest && hbm);
  1025.   ASSERT(nWidth > 0 && nHeight > 0);
  1026.   
  1027.   // Create a generic DC for all BitBlts
  1028.   HDC hDC = CreateCompatibleDC(hdcDest);
  1029.   ASSERT(hDC);
  1030.   
  1031.   if (hDC)
  1032.   {
  1033.     // Create a DC for the monochrome DIB section
  1034.     HDC bwDC = CreateCompatibleDC(hDC);
  1035.     ASSERT(bwDC);
  1036.     
  1037.     if (bwDC)
  1038.     {
  1039.       // Create the monochrome DIB section with a black and white palette
  1040.       struct {
  1041.         BITMAPINFOHEADER bmiHeader; 
  1042.         RGBQUAD      bmiColors[2]; 
  1043.       } RGBBWBITMAPINFO = {
  1044.         
  1045.         {    // a BITMAPINFOHEADER
  1046.           sizeof(BITMAPINFOHEADER),  // biSize 
  1047.             nWidth,         // biWidth; 
  1048.             nHeight,        // biHeight; 
  1049.             1,            // biPlanes; 
  1050.             1,            // biBitCount 
  1051.             BI_RGB,         // biCompression; 
  1052.             0,            // biSizeImage; 
  1053.             0,            // biXPelsPerMeter; 
  1054.             0,            // biYPelsPerMeter; 
  1055.             0,            // biClrUsed; 
  1056.             0            // biClrImportant; 
  1057.         },    
  1058.         {
  1059.           { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
  1060.         } 
  1061.       };
  1062.       VOID *pbitsBW;
  1063.       HBITMAP hbmBW = CreateDIBSection(bwDC,
  1064.         (LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
  1065.       ASSERT(hbmBW);
  1066.       
  1067.       if (hbmBW)
  1068.       {
  1069.         // Attach the monochrome DIB section and the bitmap to the DCs
  1070.         HBITMAP olddib = (HBITMAP)SelectObject(bwDC, hbmBW);
  1071.         SelectObject(hDC, hbm);
  1072.         
  1073.         // BitBlt the bitmap into the monochrome DIB section
  1074.         BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);
  1075.         
  1076.         // Paint the destination rectangle in gray
  1077.         FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest +
  1078. nHeight), GetSysColorBrush((IsNewShell())?COLOR_3DFACE:COLOR_MENU));
  1079.             //SK: looks better on the old shell
  1080.         // BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT
  1081.         // bits in the destination DC
  1082.         // The magic ROP comes from the Charles Petzold's book
  1083.         HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
  1084.         HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb);
  1085.         BitBlt(hdcDest,nXDest+1,nYDest+1,nWidth,nHeight,bwDC,0,0,0xB8074A);
  1086.         
  1087.         // BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW
  1088.         // bits in the destination DC
  1089.         hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
  1090.         DeleteObject(SelectObject(hdcDest, hb));
  1091.         BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,bwDC,0,0,0xB8074A);
  1092.         DeleteObject(SelectObject(hdcDest, oldBrush));
  1093.         VERIFY(DeleteObject(SelectObject(bwDC, olddib)));
  1094.       }
  1095.       
  1096.       VERIFY(DeleteDC(bwDC));
  1097.     }
  1098.     
  1099.     VERIFY(DeleteDC(hDC));
  1100.   }
  1101. }
  1102. int BCMenu::AddBitmapToImageList(CImageList *bmplist,UINT nResourceID)
  1103. {
  1104.   int bReturn;
  1105.   HBITMAP hbmp=LoadSysColorBitmap(nResourceID);
  1106.   if(hbmp){
  1107.     CBitmap bmp;
  1108.     bmp.Attach(hbmp);
  1109.     if(m_bitmapBackgroundFlag) bReturn=bmplist->Add(&bmp,m_bitmapBackground);
  1110.     else bReturn=bmplist->Add(&bmp,GetSysColor(COLOR_3DFACE));
  1111.     bmp.Detach();
  1112.     DeleteObject(hbmp);
  1113.   }
  1114.   else bReturn = -1;
  1115.   return(bReturn);
  1116. }
  1117. void BCMenu::SetBitmapBackground(COLORREF color)
  1118. {
  1119.   m_bitmapBackground=color;
  1120.   m_bitmapBackgroundFlag=TRUE;
  1121. }
  1122. void BCMenu::UnSetBitmapBackground(void)
  1123. {
  1124.   m_bitmapBackgroundFlag=FALSE;
  1125. }
  1126. // Given a toolbar, append all the options from it to this menu
  1127. // Passed a ptr to the toolbar object and the toolbar ID
  1128. // Author : Robert Edward Caldecott
  1129. void BCMenu::AddFromToolBar(CToolBar* pToolBar, int nResourceID)
  1130. {
  1131.   for (int i = 0; i < pToolBar->GetCount(); i++) {
  1132.     UINT nID = pToolBar->GetItemID(i);
  1133.     // See if this toolbar option
  1134.     // appears as a command on this
  1135.     // menu or is a separator
  1136.     if (nID == 0 || GetMenuState(nID, MF_BYCOMMAND) == 0xFFFFFFFF)
  1137.       continue; // Item doesn't exist
  1138.     UINT nStyle;
  1139.     int nImage;
  1140.     // Get the toolbar button info
  1141.     pToolBar->GetButtonInfo(i, nID, nStyle, nImage);
  1142.     // OK, we have the command ID of the toolbar
  1143.     // option, and the tollbar bitmap offset
  1144.     int nLoc;
  1145.     BCMenuData* pData;
  1146.     BCMenu *pSubMenu = FindMenuOption(nID, nLoc);
  1147.     if (pSubMenu && nLoc >= 0)pData = pSubMenu->m_MenuList[nLoc];
  1148.     else {
  1149.       // Create a new BCMenuData structure
  1150.       pData = new BCMenuData;
  1151.       m_MenuList.Add(pData);
  1152.     }
  1153.     // Set some default structure members
  1154.     pData->menuIconNormal = nResourceID;
  1155.     pData->nID = nID;
  1156.     pData->nFlags =  MF_BYCOMMAND | MF_OWNERDRAW;
  1157.     pData->xoffset = nImage;
  1158.     if (pData->bitmap)pData->bitmap->DeleteImageList();
  1159.     else pData->bitmap = new CImageList;
  1160.     pData->bitmap->Create(m_iconX, m_iconY,ILC_COLORDDB|ILC_MASK, 1, 1);
  1161.     AddBitmapToImageList(pData->bitmap, nResourceID);
  1162.     // Modify our menu
  1163.     ModifyMenu(nID,pData->nFlags,nID,(LPCTSTR)pData);
  1164.   }
  1165. }
  1166. BOOL BCMenu::Draw3DCheckmark(CDC *dc, const CRect& rc,
  1167.                              BOOL bSelected, HBITMAP hbmCheck)
  1168. {
  1169.   CRect rcDest = rc;
  1170.   CBrush brush;
  1171.   COLORREF col=GetSysColor((bSelected||!IsNewShell())?COLOR_MENU:COLOR_3DLIGHT);//SK: Looks better on the old shell
  1172.   brush.CreateSolidBrush(col);
  1173.   dc->FillRect(rcDest,&brush);
  1174.   brush.DeleteObject();
  1175.   if (IsNewShell()) //SK: looks better on the old shell
  1176.     dc->DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
  1177.   if (!hbmCheck)DrawCheckMark(dc,rc.left+4,rc.top+4,GetSysColor(COLOR_MENUTEXT));
  1178.   else DrawRadioDot(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
  1179.   return TRUE;
  1180. }
  1181. void BCMenu::DitherBlt2(CDC *drawdc, int nXDest, int nYDest, int nWidth, 
  1182.                         int nHeight, CBitmap &bmp, int nXSrc, int nYSrc)
  1183. {
  1184. // create a monochrome memory DC
  1185. CDC ddc;
  1186. ddc.CreateCompatibleDC(0);
  1187.   CBitmap bwbmp;
  1188. bwbmp.CreateCompatibleBitmap(&ddc, nWidth, nHeight);
  1189. CBitmap * pddcOldBmp = ddc.SelectObject(&bwbmp);
  1190.   CDC dc;
  1191. dc.CreateCompatibleDC(0);
  1192.   CBitmap * pdcOldBmp = dc.SelectObject(&bmp);
  1193. // build a mask
  1194. ddc.PatBlt(0, 0, nWidth, nHeight, WHITENESS);
  1195. dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
  1196. ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCCOPY);
  1197. dc.SetBkColor(GetSysColor(COLOR_BTNHILIGHT));
  1198. ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCPAINT);
  1199. // Copy the image from the toolbar into the memory DC
  1200. // and draw it (grayed) back into the toolbar.
  1201. dc.FillSolidRect(0,0, nWidth, nHeight, GetSysColor((IsNewShell())?COLOR_3DFACE:COLOR_MENU));
  1202.         //SK: Looks better on the old shell
  1203. dc.SetBkColor(RGB(0, 0, 0));
  1204. dc.SetTextColor(RGB(255, 255, 255));
  1205. CBrush brShadow, brHilight;
  1206. brHilight.CreateSolidBrush(GetSysColor(COLOR_BTNHILIGHT));
  1207. brShadow.CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
  1208. CBrush * pOldBrush = dc.SelectObject(&brHilight);
  1209. dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
  1210. drawdc->BitBlt(nXDest+1,nYDest+1,nWidth, nHeight, &dc,0,0,SRCCOPY);
  1211. dc.BitBlt(1,1, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
  1212. dc.SelectObject(&brShadow);
  1213. dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
  1214. drawdc->BitBlt(nXDest,nYDest,nWidth, nHeight, &dc,0,0,SRCCOPY);
  1215. // reset DCs
  1216. ddc.SelectObject(pddcOldBmp);
  1217. ddc.DeleteDC();
  1218. dc.SelectObject(pOldBrush);
  1219. dc.SelectObject(pdcOldBmp);
  1220. dc.DeleteDC();
  1221. bwbmp.DeleteObject();
  1222. }
  1223. void BCMenu::SetDisableOldStyle(void)
  1224. {
  1225.   disable_old_style=TRUE;
  1226. }
  1227. void BCMenu::UnSetDisableOldStyle(void)
  1228. {
  1229.   disable_old_style=FALSE;
  1230. }
  1231. BOOL BCMenu::GetDisableOldStyle(void)
  1232. {
  1233.   return(disable_old_style);
  1234. }
  1235. HBITMAP BCMenu::LoadSysColorBitmap(int nResourceId)
  1236. {
  1237.   HINSTANCE hInst = 
  1238.     AfxFindResourceHandle(MAKEINTRESOURCE(nResourceId),RT_BITMAP);
  1239.   HRSRC hRsrc = 
  1240.     ::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP);
  1241. if (hRsrc == NULL)
  1242. return NULL;
  1243. return AfxLoadSysColorBitmap(hInst, hRsrc, FALSE);
  1244. }
  1245. //*************************************************************************